1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc --mtriple=loongarch32 -mattr=+d < %s | FileCheck %s 3 4;; Test generation of the bstrins.w instruction. 5;; There are 8 patterns that can be matched to bstrins.w. See performORCombine 6;; for details. 7 8;; Pattern 1 9;; R = or (and X, mask0), (and (shl Y, lsb), mask1) 10;; => 11;; R = BSTRINS X, Y, msb, lsb 12define i32 @pat1(i32 %a, i32 %b) nounwind { 13; CHECK-LABEL: pat1: 14; CHECK: # %bb.0: 15; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8 16; CHECK-NEXT: ret 17 %and1 = and i32 %a, -1048321 ; 0xfff000ff 18 %shl = shl i32 %b, 8 19 %and2 = and i32 %shl, 1048320 ; 0x000fff00 20 %or = or i32 %and1, %and2 21 ret i32 %or 22} 23 24define i32 @pat1_swap(i32 %a, i32 %b) nounwind { 25; CHECK-LABEL: pat1_swap: 26; CHECK: # %bb.0: 27; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8 28; CHECK-NEXT: ret 29 %and1 = and i32 %a, -1048321 ; 0xfff000ff 30 %shl = shl i32 %b, 8 31 %and2 = and i32 %shl, 1048320 ; 0x000fff00 32 %or = or i32 %and2, %and1 33 ret i32 %or 34} 35 36;; Pattern 2 37;; R = or (and X, mask0), (shl (and Y, mask1), lsb) 38;; => 39;; R = BSTRINS X, Y, msb, lsb 40define i32 @pat2(i32 %a, i32 %b) nounwind { 41; CHECK-LABEL: pat2: 42; CHECK: # %bb.0: 43; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8 44; CHECK-NEXT: ret 45 %and1 = and i32 %a, -1048321 ; 0xfff000ff 46 %and2 = and i32 %b, 4095 ; 0x00000fff 47 %shl = shl i32 %and2, 8 48 %or = or i32 %and1, %shl 49 ret i32 %or 50} 51 52define i32 @pat2_swap(i32 %a, i32 %b) nounwind { 53; CHECK-LABEL: pat2_swap: 54; CHECK: # %bb.0: 55; CHECK-NEXT: bstrins.w $a0, $a1, 19, 8 56; CHECK-NEXT: ret 57 %and1 = and i32 %a, -1048321 ; 0xfff000ff 58 %and2 = and i32 %b, 4095 ; 0x00000fff 59 %shl = shl i32 %and2, 8 60 %or = or i32 %shl, %and1 61 ret i32 %or 62} 63 64;; Pattern 3 65;; R = or (and X, mask0), (and Y, mask1) 66;; => 67;; R = BSTRINS X, (srl (and Y, mask1), lsb), msb, lsb 68define i32 @pat3(i32 %a, i32 %b) nounwind { 69; CHECK-LABEL: pat3: 70; CHECK: # %bb.0: 71; CHECK-NEXT: andi $a1, $a1, 288 72; CHECK-NEXT: srli.w $a1, $a1, 4 73; CHECK-NEXT: bstrins.w $a0, $a1, 11, 4 74; CHECK-NEXT: ret 75 %and1 = and i32 %a, -4081 ; 0xfffff00f 76 %and2 = and i32 %b, 288 ; 0x00000120 77 %or = or i32 %and1, %and2 78 ret i32 %or 79} 80 81define i32 @pat3_swap(i32 %a, i32 %b) nounwind { 82; CHECK-LABEL: pat3_swap: 83; CHECK: # %bb.0: 84; CHECK-NEXT: andi $a1, $a1, 288 85; CHECK-NEXT: srli.w $a1, $a1, 4 86; CHECK-NEXT: bstrins.w $a0, $a1, 11, 4 87; CHECK-NEXT: ret 88 %and1 = and i32 %a, -4081 ; 0xfffff00f 89 %and2 = and i32 %b, 288 ; 0x00000120 90 %or = or i32 %and2, %and1 91 ret i32 %or 92} 93 94define i32 @pat3_positive_mask0(i32 %a, i32 %b) nounwind { 95; CHECK-LABEL: pat3_positive_mask0: 96; CHECK: # %bb.0: 97; CHECK-NEXT: srli.w $a1, $a1, 28 98; CHECK-NEXT: bstrins.w $a0, $a1, 31, 28 99; CHECK-NEXT: ret 100 %and1 = and i32 %a, 268435455 ; 0x0fffffff 101 %and2 = and i32 %b, 4026531840 ; 0xf0000000 102 %or = or i32 %and1, %and2 103 ret i32 %or 104} 105 106;; Pattern 4 107;; R = or (and X, mask), (shl Y, shamt) 108;; => 109;; R = BSTRINS X, Y, 31, shamt 110define i32 @pat4(i32 %a, i32 %b) nounwind { 111; CHECK-LABEL: pat4: 112; CHECK: # %bb.0: 113; CHECK-NEXT: bstrins.w $a0, $a1, 31, 28 114; CHECK-NEXT: ret 115 %and = and i32 %a, 268435455 ; 0x0fffffff 116 %shl = shl i32 %b, 28 117 %or = or i32 %and, %shl 118 ret i32 %or 119} 120 121define i32 @pat4_swap(i32 %a, i32 %b) nounwind { 122; CHECK-LABEL: pat4_swap: 123; CHECK: # %bb.0: 124; CHECK-NEXT: bstrins.w $a0, $a1, 31, 28 125; CHECK-NEXT: ret 126 %and = and i32 %a, 268435455 ; 0x0fffffff 127 %shl = shl i32 %b, 28 128 %or = or i32 %shl, %and 129 ret i32 %or 130} 131 132;; Pattern 5 133;; R = or (and X, mask), const 134;; => 135;; R = BSTRINS X, (const >> lsb), msb, lsb 136define i32 @pat5(i32 %a) nounwind { 137; CHECK-LABEL: pat5: 138; CHECK: # %bb.0: 139; CHECK-NEXT: lu12i.w $a1, 1 140; CHECK-NEXT: ori $a1, $a1, 564 141; CHECK-NEXT: bstrins.w $a0, $a1, 23, 8 142; CHECK-NEXT: ret 143 %and = and i32 %a, 4278190335 ; 0xff0000ff 144 %or = or i32 %and, 1192960 ; 0x00123400 145 ret i32 %or 146} 147 148;; The high bits of `const` are zero. 149define i32 @pat5_high_zeros(i32 %a) nounwind { 150; CHECK-LABEL: pat5_high_zeros: 151; CHECK: # %bb.0: 152; CHECK-NEXT: lu12i.w $a1, 1 153; CHECK-NEXT: ori $a1, $a1, 564 154; CHECK-NEXT: bstrins.w $a0, $a1, 31, 16 155; CHECK-NEXT: ret 156 %and = and i32 %a, 65535 ; 0x0000ffff 157 %or = or i32 %and, 305397760 ; 0x12340000 158 ret i32 %or 159} 160 161;; Pattern 6: a = b | ((c & mask) << shamt) 162;; In this testcase b is 0x10000002, but in fact we do not require b being a 163;; constant. As long as all positions in b to be overwritten by the incoming 164;; bits are known to be zero, the pattern could be matched. 165define i32 @pat6(i32 %c) nounwind { 166; CHECK-LABEL: pat6: 167; CHECK: # %bb.0: 168; CHECK-NEXT: lu12i.w $a1, 65536 169; CHECK-NEXT: ori $a1, $a1, 2 170; CHECK-NEXT: bstrins.w $a1, $a0, 27, 4 171; CHECK-NEXT: move $a0, $a1 172; CHECK-NEXT: ret 173 %and = and i32 %c, 16777215 ; 0x00ffffff 174 %shl = shl i32 %and, 4 175 %or = or i32 %shl, 268435458 ; 0x10000002 176 ret i32 %or 177} 178 179;; Pattern 7: a = b | ((c << shamt) & shifted_mask) 180;; Similar to pattern 6. 181define i32 @pat7(i32 %c) nounwind { 182; CHECK-LABEL: pat7: 183; CHECK: # %bb.0: 184; CHECK-NEXT: lu12i.w $a1, 65536 185; CHECK-NEXT: ori $a1, $a1, 2 186; CHECK-NEXT: bstrins.w $a1, $a0, 27, 4 187; CHECK-NEXT: move $a0, $a1 188; CHECK-NEXT: ret 189 %shl = shl i32 %c, 4 190 %and = and i32 %shl, 268435440 ; 0x0ffffff0 191 %or = or i32 %and, 268435458 ; 0x10000002 192 ret i32 %or 193} 194 195;; Pattern 8: a = b | (c & shifted_mask) 196;; Similar to pattern 7 but without shift to c. 197define i32 @pat8(i32 %c) nounwind { 198; CHECK-LABEL: pat8: 199; CHECK: # %bb.0: 200; CHECK-NEXT: srli.w $a1, $a0, 4 201; CHECK-NEXT: lu12i.w $a0, 65536 202; CHECK-NEXT: ori $a0, $a0, 2 203; CHECK-NEXT: bstrins.w $a0, $a1, 27, 4 204; CHECK-NEXT: ret 205 %and = and i32 %c, 268435440 ; 0x0ffffff0 206 %or = or i32 %and, 268435458 ; 0x10000002 207 ret i32 %or 208} 209 210;; Test that bstrins.w is not generated because constant OR operand 211;; doesn't fit into bits cleared by constant AND operand. 212define i32 @no_bstrins_w(i32 %a) nounwind { 213; CHECK-LABEL: no_bstrins_w: 214; CHECK: # %bb.0: 215; CHECK-NEXT: lu12i.w $a1, 291 216; CHECK-NEXT: ori $a1, $a1, 1104 217; CHECK-NEXT: or $a0, $a0, $a1 218; CHECK-NEXT: lu12i.w $a1, -3805 219; CHECK-NEXT: ori $a1, $a1, 1279 220; CHECK-NEXT: and $a0, $a0, $a1 221; CHECK-NEXT: ret 222 %and = and i32 %a, 4278190335 ; 0xff0000ff 223 %or = or i32 %and, 1193040 ; 0x00123450 224 ret i32 %or 225} 226