| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py |
| ; RUN: llc --mtriple=loongarch32 < %s | FileCheck %s |
| |
| ;; Test generation of the bstrins.w instruction. |
| ;; There are 8 patterns that can be matched to bstrins.w. See performORCombine |
| ;; for details. |
| |
| ;; Pattern 1 |
| ;; R = or (and X, mask0), (and (shl Y, lsb), mask1) |
| ;; => |
| ;; R = BSTRINS X, Y, msb, lsb |
| define i32 @pat1(i32 %a, i32 %b) nounwind { |
| ; CHECK-LABEL: pat1: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and1 = and i32 %a, -1048321 ; 0xfff000ff |
| %shl = shl i32 %b, 8 |
| %and2 = and i32 %shl, 1048320 ; 0x000fff00 |
| %or = or i32 %and1, %and2 |
| ret i32 %or |
| } |
| |
| define i32 @pat1_swap(i32 %a, i32 %b) nounwind { |
| ; CHECK-LABEL: pat1_swap: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and1 = and i32 %a, -1048321 ; 0xfff000ff |
| %shl = shl i32 %b, 8 |
| %and2 = and i32 %shl, 1048320 ; 0x000fff00 |
| %or = or i32 %and2, %and1 |
| ret i32 %or |
| } |
| |
| ;; Pattern 2 |
| ;; R = or (and X, mask0), (shl (and Y, mask1), lsb) |
| ;; => |
| ;; R = BSTRINS X, Y, msb, lsb |
| define i32 @pat2(i32 %a, i32 %b) nounwind { |
| ; CHECK-LABEL: pat2: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and1 = and i32 %a, -1048321 ; 0xfff000ff |
| %and2 = and i32 %b, 4095 ; 0x00000fff |
| %shl = shl i32 %and2, 8 |
| %or = or i32 %and1, %shl |
| ret i32 %or |
| } |
| |
| define i32 @pat2_swap(i32 %a, i32 %b) nounwind { |
| ; CHECK-LABEL: pat2_swap: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and1 = and i32 %a, -1048321 ; 0xfff000ff |
| %and2 = and i32 %b, 4095 ; 0x00000fff |
| %shl = shl i32 %and2, 8 |
| %or = or i32 %shl, %and1 |
| ret i32 %or |
| } |
| |
| ;; Pattern 3 |
| ;; R = or (and X, mask0), (and Y, mask1) |
| ;; => |
| ;; R = BSTRINS X, (srl (and Y, mask1), lsb), msb, lsb |
| define i32 @pat3(i32 %a, i32 %b) nounwind { |
| ; CHECK-LABEL: pat3: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: andi $a1, $a1, 288 |
| ; CHECK-NEXT: srli.w $a1, $a1, 4 |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 11, 4 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and1 = and i32 %a, -4081 ; 0xfffff00f |
| %and2 = and i32 %b, 288 ; 0x00000120 |
| %or = or i32 %and1, %and2 |
| ret i32 %or |
| } |
| |
| define i32 @pat3_swap(i32 %a, i32 %b) nounwind { |
| ; CHECK-LABEL: pat3_swap: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: andi $a1, $a1, 288 |
| ; CHECK-NEXT: srli.w $a1, $a1, 4 |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 11, 4 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and1 = and i32 %a, -4081 ; 0xfffff00f |
| %and2 = and i32 %b, 288 ; 0x00000120 |
| %or = or i32 %and2, %and1 |
| ret i32 %or |
| } |
| |
| define i32 @pat3_positive_mask0(i32 %a, i32 %b) nounwind { |
| ; CHECK-LABEL: pat3_positive_mask0: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: srli.w $a1, $a1, 28 |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 31, 28 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and1 = and i32 %a, 268435455 ; 0x0fffffff |
| %and2 = and i32 %b, 4026531840 ; 0xf0000000 |
| %or = or i32 %and1, %and2 |
| ret i32 %or |
| } |
| |
| ;; Pattern 4 |
| ;; R = or (and X, mask), (shl Y, shamt) |
| ;; => |
| ;; R = BSTRINS X, Y, 31, shamt |
| define i32 @pat4(i32 %a, i32 %b) nounwind { |
| ; CHECK-LABEL: pat4: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 31, 28 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and = and i32 %a, 268435455 ; 0x0fffffff |
| %shl = shl i32 %b, 28 |
| %or = or i32 %and, %shl |
| ret i32 %or |
| } |
| |
| define i32 @pat4_swap(i32 %a, i32 %b) nounwind { |
| ; CHECK-LABEL: pat4_swap: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 31, 28 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and = and i32 %a, 268435455 ; 0x0fffffff |
| %shl = shl i32 %b, 28 |
| %or = or i32 %shl, %and |
| ret i32 %or |
| } |
| |
| ;; Pattern 5 |
| ;; R = or (and X, mask), const |
| ;; => |
| ;; R = BSTRINS X, (const >> lsb), msb, lsb |
| define i32 @pat5(i32 %a) nounwind { |
| ; CHECK-LABEL: pat5: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: lu12i.w $a1, 1 |
| ; CHECK-NEXT: ori $a1, $a1, 564 |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 23, 8 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and = and i32 %a, 4278190335 ; 0xff0000ff |
| %or = or i32 %and, 1192960 ; 0x00123400 |
| ret i32 %or |
| } |
| |
| ;; Pattern 6: a = b | ((c & mask) << shamt) |
| ;; In this testcase b is 0x10000002, but in fact we do not require b being a |
| ;; constant. As long as all positions in b to be overwritten by the incoming |
| ;; bits are known to be zero, the pattern could be matched. |
| define i32 @pat6(i32 %c) nounwind { |
| ; CHECK-LABEL: pat6: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: lu12i.w $a1, 65536 |
| ; CHECK-NEXT: ori $a1, $a1, 2 |
| ; CHECK-NEXT: bstrins.w $a1, $a0, 27, 4 |
| ; CHECK-NEXT: move $a0, $a1 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and = and i32 %c, 16777215 ; 0x00ffffff |
| %shl = shl i32 %and, 4 |
| %or = or i32 %shl, 268435458 ; 0x10000002 |
| ret i32 %or |
| } |
| |
| ;; Pattern 7: a = b | ((c << shamt) & shifted_mask) |
| ;; Similar to pattern 6. |
| define i32 @pat7(i32 %c) nounwind { |
| ; CHECK-LABEL: pat7: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: lu12i.w $a1, 65536 |
| ; CHECK-NEXT: ori $a1, $a1, 2 |
| ; CHECK-NEXT: bstrins.w $a1, $a0, 27, 4 |
| ; CHECK-NEXT: move $a0, $a1 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %shl = shl i32 %c, 4 |
| %and = and i32 %shl, 268435440 ; 0x0ffffff0 |
| %or = or i32 %and, 268435458 ; 0x10000002 |
| ret i32 %or |
| } |
| |
| ;; Pattern 8: a = b | (c & shifted_mask) |
| ;; Similar to pattern 7 but without shift to c. |
| define i32 @pat8(i32 %c) nounwind { |
| ; CHECK-LABEL: pat8: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: srli.w $a1, $a0, 4 |
| ; CHECK-NEXT: lu12i.w $a0, 65536 |
| ; CHECK-NEXT: ori $a0, $a0, 2 |
| ; CHECK-NEXT: bstrins.w $a0, $a1, 27, 4 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and = and i32 %c, 268435440 ; 0x0ffffff0 |
| %or = or i32 %and, 268435458 ; 0x10000002 |
| ret i32 %or |
| } |
| |
| ;; Test that bstrins.w is not generated because constant OR operand |
| ;; doesn't fit into bits cleared by constant AND operand. |
| define i32 @no_bstrins_w(i32 %a) nounwind { |
| ; CHECK-LABEL: no_bstrins_w: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: lu12i.w $a1, 291 |
| ; CHECK-NEXT: ori $a1, $a1, 1104 |
| ; CHECK-NEXT: or $a0, $a0, $a1 |
| ; CHECK-NEXT: lu12i.w $a1, -3805 |
| ; CHECK-NEXT: ori $a1, $a1, 1279 |
| ; CHECK-NEXT: and $a0, $a0, $a1 |
| ; CHECK-NEXT: jirl $zero, $ra, 0 |
| %and = and i32 %a, 4278190335 ; 0xff0000ff |
| %or = or i32 %and, 1193040 ; 0x00123450 |
| ret i32 %or |
| } |