; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s ;; Test generation of the bstrins.d instruction. ;; There are 8 patterns that can be matched to bstrins.d. See performORCombine ;; for details. ;; Pattern 1 ;; R = or (and X, mask0), (and (shl Y, lsb), mask1) ;; => ;; R = BSTRINS X, Y, msb, lsb define i64 @pat1(i64 %a, i64 %b) nounwind { ; CHECK-LABEL: pat1: ; CHECK: # %bb.0: ; CHECK-NEXT: bstrins.d $a0, $a1, 39, 16 ; CHECK-NEXT: jirl $zero, $ra, 0 %and1 = and i64 %a, -1099511562241 ; 0xffffff000000ffff %shl = shl i64 %b, 16 %and2 = and i64 %shl, 1099511562240 ; 0x000000ffffff0000 %or = or i64 %and1, %and2 ret i64 %or } define i64 @pat1_swap(i64 %a, i64 %b) nounwind { ; CHECK-LABEL: pat1_swap: ; CHECK: # %bb.0: ; CHECK-NEXT: bstrins.d $a0, $a1, 39, 16 ; CHECK-NEXT: jirl $zero, $ra, 0 %and1 = and i64 %a, -1099511562241 ; 0xffffff000000ffff %shl = shl i64 %b, 16 %and2 = and i64 %shl, 1099511562240 ; 0x000000ffffff0000 %or = or i64 %and2, %and1 ret i64 %or } ;; Pattern 2 ;; R = or (and X, mask0), (shl (and Y, mask1), lsb) ;; => ;; R = BSTRINS X, Y, msb, lsb define i64 @pat2(i64 %a, i64 %b) nounwind { ; CHECK-LABEL: pat2: ; CHECK: # %bb.0: ; CHECK-NEXT: bstrins.d $a0, $a1, 39, 16 ; CHECK-NEXT: jirl $zero, $ra, 0 %and1 = and i64 %a, -1099511562241 ; 0xffffff000000ffff %and2 = and i64 %b, 16777215 ; 0x0000000000ffffff %shl = shl i64 %and2, 16 %or = or i64 %and1, %shl ret i64 %or } define i64 @pat2_swap(i64 %a, i64 %b) nounwind { ; CHECK-LABEL: pat2_swap: ; CHECK: # %bb.0: ; CHECK-NEXT: bstrins.d $a0, $a1, 39, 16 ; CHECK-NEXT: jirl $zero, $ra, 0 %and1 = and i64 %a, -1099511562241 ; 0xffffff000000ffff %and2 = and i64 %b, 16777215 ; 0x0000000000ffffff %shl = shl i64 %and2, 16 %or = or i64 %shl, %and1 ret i64 %or } ;; Pattern 3 ;; R = or (and X, mask0), (and Y, mask1) ;; => ;; R = BSTRINS X, (srl (and Y, mask1), lsb), msb, lsb define i64 @pat3(i64 %a, i64 %b) nounwind { ; CHECK-LABEL: pat3: ; CHECK: # %bb.0: ; CHECK-NEXT: andi $a1, $a1, 288 ; CHECK-NEXT: srli.d $a1, $a1, 4 ; CHECK-NEXT: bstrins.d $a0, $a1, 11, 4 ; CHECK-NEXT: jirl $zero, $ra, 0 %and1 = and i64 %a, -4081 ; 0xfffffffffffff00f %and2 = and i64 %b, 288 ; 0x0000000000000120 %or = or i64 %and1, %and2 ret i64 %or } define i64 @pat3_swap(i64 %a, i64 %b) nounwind { ; CHECK-LABEL: pat3_swap: ; CHECK: # %bb.0: ; CHECK-NEXT: andi $a1, $a1, 288 ; CHECK-NEXT: srli.d $a1, $a1, 4 ; CHECK-NEXT: bstrins.d $a0, $a1, 11, 4 ; CHECK-NEXT: jirl $zero, $ra, 0 %and1 = and i64 %a, -4081 ; 0xfffffffffffff00f %and2 = and i64 %b, 288 ; 0x0000000000000120 %or = or i64 %and2, %and1 ret i64 %or } ;; Pattern 4 ;; R = or (and X, mask), (shl Y, shamt) ;; => ;; R = BSTRINS X, Y, 63, shamt define i64 @pat4(i64 %a, i64 %b) nounwind { ; CHECK-LABEL: pat4: ; CHECK: # %bb.0: ; CHECK-NEXT: bstrins.d $a0, $a1, 63, 8 ; CHECK-NEXT: jirl $zero, $ra, 0 %and = and i64 %a, 255 %shl = shl i64 %b, 8 %or = or i64 %and, %shl ret i64 %or } define i64 @pat4_swap(i64 %a, i64 %b) nounwind { ; CHECK-LABEL: pat4_swap: ; CHECK: # %bb.0: ; CHECK-NEXT: bstrins.d $a0, $a1, 63, 8 ; CHECK-NEXT: jirl $zero, $ra, 0 %and = and i64 %a, 255 %shl = shl i64 %b, 8 %or = or i64 %shl, %and ret i64 %or } ;; Pattern 5 ;; R = or (and X, mask0), const ;; => ;; R = BSTRINS X, (const >> lsb), msb, lsb define i64 @pat5(i64 %a) nounwind { ; CHECK-LABEL: pat5: ; CHECK: # %bb.0: ; CHECK-NEXT: lu12i.w $a1, 74565 ; CHECK-NEXT: ori $a1, $a1, 1656 ; CHECK-NEXT: bstrins.d $a0, $a1, 47, 16 ; CHECK-NEXT: jirl $zero, $ra, 0 %and = and i64 %a, 18446462598732906495 ; 0xffff00000000ffff %or = or i64 %and, 20015998304256 ; 0x0000123456780000 ret i64 %or } ;; Pattern 6: a = b | ((c & mask) << shamt) ;; In this testcase b is 0x123456000000789a, 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 i64 @pat6(i64 %c) nounwind { ; CHECK-LABEL: pat6: ; CHECK: # %bb.0: ; CHECK-NEXT: lu12i.w $a1, 7 ; CHECK-NEXT: ori $a1, $a1, 2202 ; CHECK-NEXT: lu32i.d $a1, 284160 ; CHECK-NEXT: lu52i.d $a1, $a1, 291 ; CHECK-NEXT: bstrins.d $a1, $a0, 39, 16 ; CHECK-NEXT: move $a0, $a1 ; CHECK-NEXT: jirl $zero, $ra, 0 %and = and i64 %c, 16777215 ; 0x0000000000ffffff %shl = shl i64 %and, 16 %or = or i64 %shl, 1311767949471676570 ; 0x123456000000789a ret i64 %or } ;; Pattern 7: a = b | ((c << shamt) & shifted_mask) ;; Similar to pattern 6. define i64 @pat7(i64 %c) nounwind { ; CHECK-LABEL: pat7: ; CHECK: # %bb.0: ; CHECK-NEXT: lu12i.w $a1, 7 ; CHECK-NEXT: ori $a1, $a1, 2202 ; CHECK-NEXT: lu32i.d $a1, 284160 ; CHECK-NEXT: lu52i.d $a1, $a1, 291 ; CHECK-NEXT: bstrins.d $a1, $a0, 39, 16 ; CHECK-NEXT: move $a0, $a1 ; CHECK-NEXT: jirl $zero, $ra, 0 %shl = shl i64 %c, 16 %and = and i64 %shl, 1099511562240 ; 0x000000ffffff0000 %or = or i64 %and, 1311767949471676570 ; 0x123456000000789a ret i64 %or } ;; Pattern 8: a = b | (c & shifted_mask) ;; Similar to pattern 7 but without shift to c. define i64 @pat8(i64 %c) nounwind { ; CHECK-LABEL: pat8: ; CHECK: # %bb.0: ; CHECK-NEXT: srli.d $a1, $a0, 16 ; CHECK-NEXT: lu12i.w $a0, 7 ; CHECK-NEXT: ori $a0, $a0, 2202 ; CHECK-NEXT: lu32i.d $a0, 284160 ; CHECK-NEXT: lu52i.d $a0, $a0, 291 ; CHECK-NEXT: bstrins.d $a0, $a1, 39, 16 ; CHECK-NEXT: jirl $zero, $ra, 0 %and = and i64 %c, 1099511562240 ; 0x000000ffffff0000 %or = or i64 %and, 1311767949471676570 ; 0x123456000000789a ret i64 %or } ;; Test that bstrins.d is not generated because constant OR operand ;; doesn't fit into bits cleared by constant AND operand. define i64 @no_bstrins_d(i64 %a) nounwind { ; CHECK-LABEL: no_bstrins_d: ; CHECK: # %bb.0: ; CHECK-NEXT: lu12i.w $a1, 354185 ; CHECK-NEXT: lu32i.d $a1, 4660 ; CHECK-NEXT: or $a0, $a0, $a1 ; CHECK-NEXT: lu12i.w $a1, 354191 ; CHECK-NEXT: ori $a1, $a1, 4095 ; CHECK-NEXT: lu32i.d $a1, -60876 ; CHECK-NEXT: and $a0, $a0, $a1 ; CHECK-NEXT: jirl $zero, $ra, 0 %and = and i64 %a, 18446462598732906495 ; 0xffff00000000ffff %or = or i64 %and, 20015998341120 ; 0x0000123456789000 ret i64 %or }