[LoongArch] Optimize bitwise and with immediates
authorBen Shi <powerman1st@163.com>
Mon, 3 Apr 2023 01:54:43 +0000 (09:54 +0800)
committerBen Shi <powerman1st@163.com>
Mon, 3 Apr 2023 04:10:07 +0000 (12:10 +0800)
Optimize bitfield extractions retaining bit positions
from 'lu12i + addi + and' to 'bstrpick + slli'.

Reviewed By: xen0n, SixWeining

Differential Revision: https://reviews.llvm.org/D147368

llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
llvm/test/CodeGen/LoongArch/alloca.ll
llvm/test/CodeGen/LoongArch/ir-instruction/and.ll
llvm/test/CodeGen/LoongArch/shrinkwrap.ll
llvm/test/CodeGen/LoongArch/stack-realignment-with-variable-sized-objects.ll

index 4cf943e..7f62a12 100644 (file)
@@ -1372,16 +1372,39 @@ static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
     if (CN->getZExtValue() <= 0xfff)
       return SDValue();
 
-    // Return if the mask doesn't start at position 0.
-    if (SMIdx)
+    // Return if the MSB exceeds.
+    if (SMIdx + SMLen > ValTy.getSizeInBits())
       return SDValue();
 
-    lsb = 0;
+    if (SMIdx > 0) {
+      // Omit if the constant has more than 2 uses. This a conservative
+      // decision. Whether it is a win depends on the HW microarchitecture.
+      // However it should always be better for 1 and 2 uses.
+      if (CN->use_size() > 2)
+        return SDValue();
+      // Return if the constant can be composed by a single LU12I.W.
+      if ((CN->getZExtValue() & 0xfff) == 0)
+        return SDValue();
+      // Return if the constand can be composed by a single ADDI with
+      // the zero register.
+      if (CN->getSExtValue() >= -2048 && CN->getSExtValue() < 0)
+        return SDValue();
+    }
+
+    lsb = SMIdx;
     NewOperand = FirstOperand;
   }
+
   msb = lsb + SMLen - 1;
-  return DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
-                     DAG.getConstant(msb, DL, GRLenVT),
+  SDValue NR0 = DAG.getNode(LoongArchISD::BSTRPICK, DL, ValTy, NewOperand,
+                            DAG.getConstant(msb, DL, GRLenVT),
+                            DAG.getConstant(lsb, DL, GRLenVT));
+  if (FirstOperandOpc == ISD::SRA || FirstOperandOpc == ISD::SRL || lsb == 0)
+    return NR0;
+  // Try to optimize to
+  //   bstrpick $Rd, $Rs, msb, lsb
+  //   slli     $Rd, $Rd, lsb
+  return DAG.getNode(ISD::SHL, DL, ValTy, NR0,
                      DAG.getConstant(lsb, DL, GRLenVT));
 }
 
index ca6508e..2247309 100644 (file)
@@ -34,11 +34,10 @@ define void @simple_alloca(i32 %n) nounwind {
 ; LA64-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
 ; LA64-NEXT:    st.d $fp, $sp, 0 # 8-byte Folded Spill
 ; LA64-NEXT:    addi.d $fp, $sp, 16
-; LA64-NEXT:    addi.w $a1, $zero, -16
-; LA64-NEXT:    lu32i.d $a1, 1
 ; LA64-NEXT:    bstrpick.d $a0, $a0, 31, 0
 ; LA64-NEXT:    addi.d $a0, $a0, 15
-; LA64-NEXT:    and $a0, $a0, $a1
+; LA64-NEXT:    bstrpick.d $a0, $a0, 32, 4
+; LA64-NEXT:    slli.d $a0, $a0, 4
 ; LA64-NEXT:    sub.d $a0, $sp, $a0
 ; LA64-NEXT:    move $sp, $a0
 ; LA64-NEXT:    bl %plt(notdead)
@@ -85,12 +84,11 @@ define void @scoped_alloca(i32 %n) nounwind {
 ; LA64-NEXT:    st.d $fp, $sp, 16 # 8-byte Folded Spill
 ; LA64-NEXT:    st.d $s0, $sp, 8 # 8-byte Folded Spill
 ; LA64-NEXT:    addi.d $fp, $sp, 32
-; LA64-NEXT:    addi.w $a1, $zero, -16
-; LA64-NEXT:    lu32i.d $a1, 1
+; LA64-NEXT:    move $s0, $sp
 ; LA64-NEXT:    bstrpick.d $a0, $a0, 31, 0
 ; LA64-NEXT:    addi.d $a0, $a0, 15
-; LA64-NEXT:    and $a0, $a0, $a1
-; LA64-NEXT:    move $s0, $sp
+; LA64-NEXT:    bstrpick.d $a0, $a0, 32, 4
+; LA64-NEXT:    slli.d $a0, $a0, 4
 ; LA64-NEXT:    sub.d $a0, $sp, $a0
 ; LA64-NEXT:    move $sp, $a0
 ; LA64-NEXT:    bl %plt(notdead)
@@ -154,11 +152,10 @@ define void @alloca_callframe(i32 %n) nounwind {
 ; LA64-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
 ; LA64-NEXT:    st.d $fp, $sp, 0 # 8-byte Folded Spill
 ; LA64-NEXT:    addi.d $fp, $sp, 16
-; LA64-NEXT:    addi.w $a1, $zero, -16
-; LA64-NEXT:    lu32i.d $a1, 1
 ; LA64-NEXT:    bstrpick.d $a0, $a0, 31, 0
 ; LA64-NEXT:    addi.d $a0, $a0, 15
-; LA64-NEXT:    and $a0, $a0, $a1
+; LA64-NEXT:    bstrpick.d $a0, $a0, 32, 4
+; LA64-NEXT:    slli.d $a0, $a0, 4
 ; LA64-NEXT:    sub.d $a0, $sp, $a0
 ; LA64-NEXT:    move $sp, $a0
 ; LA64-NEXT:    addi.d $sp, $sp, -32
index ea6051f..a038ddc 100644 (file)
@@ -269,16 +269,14 @@ entry:
 define signext i32 @and_i32_0xfff0(i32 %a) {
 ; LA32-LABEL: and_i32_0xfff0:
 ; LA32:       # %bb.0:
-; LA32-NEXT:    lu12i.w $a1, 15
-; LA32-NEXT:    ori $a1, $a1, 4080
-; LA32-NEXT:    and $a0, $a0, $a1
+; LA32-NEXT:    bstrpick.w $a0, $a0, 15, 4
+; LA32-NEXT:    slli.w $a0, $a0, 4
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: and_i32_0xfff0:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 15
-; LA64-NEXT:    ori $a1, $a1, 4080
-; LA64-NEXT:    and $a0, $a0, $a1
+; LA64-NEXT:    bstrpick.d $a0, $a0, 15, 4
+; LA64-NEXT:    slli.d $a0, $a0, 4
 ; LA64-NEXT:    ret
   %b = and i32 %a, 65520
   ret i32 %b
@@ -287,19 +285,19 @@ define signext i32 @and_i32_0xfff0(i32 %a) {
 define signext i32 @and_i32_0xfff0_twice(i32 %a, i32 %b) {
 ; LA32-LABEL: and_i32_0xfff0_twice:
 ; LA32:       # %bb.0:
-; LA32-NEXT:    lu12i.w $a2, 15
-; LA32-NEXT:    ori $a2, $a2, 4080
-; LA32-NEXT:    and $a1, $a1, $a2
-; LA32-NEXT:    and $a0, $a0, $a2
+; LA32-NEXT:    bstrpick.w $a1, $a1, 15, 4
+; LA32-NEXT:    slli.w $a1, $a1, 4
+; LA32-NEXT:    bstrpick.w $a0, $a0, 15, 4
+; LA32-NEXT:    slli.w $a0, $a0, 4
 ; LA32-NEXT:    sub.w $a0, $a0, $a1
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: and_i32_0xfff0_twice:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a2, 15
-; LA64-NEXT:    ori $a2, $a2, 4080
-; LA64-NEXT:    and $a1, $a1, $a2
-; LA64-NEXT:    and $a0, $a0, $a2
+; LA64-NEXT:    bstrpick.d $a1, $a1, 15, 4
+; LA64-NEXT:    slli.d $a1, $a1, 4
+; LA64-NEXT:    bstrpick.d $a0, $a0, 15, 4
+; LA64-NEXT:    slli.d $a0, $a0, 4
 ; LA64-NEXT:    sub.d $a0, $a0, $a1
 ; LA64-NEXT:    ret
   %c = and i32 %a, 65520
@@ -311,17 +309,15 @@ define signext i32 @and_i32_0xfff0_twice(i32 %a, i32 %b) {
 define i64 @and_i64_0xfff0(i64 %a) {
 ; LA32-LABEL: and_i64_0xfff0:
 ; LA32:       # %bb.0:
-; LA32-NEXT:    lu12i.w $a1, 15
-; LA32-NEXT:    ori $a1, $a1, 4080
-; LA32-NEXT:    and $a0, $a0, $a1
+; LA32-NEXT:    bstrpick.w $a0, $a0, 15, 4
+; LA32-NEXT:    slli.w $a0, $a0, 4
 ; LA32-NEXT:    move $a1, $zero
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: and_i64_0xfff0:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 15
-; LA64-NEXT:    ori $a1, $a1, 4080
-; LA64-NEXT:    and $a0, $a0, $a1
+; LA64-NEXT:    bstrpick.d $a0, $a0, 15, 4
+; LA64-NEXT:    slli.d $a0, $a0, 4
 ; LA64-NEXT:    ret
   %b = and i64 %a, 65520
   ret i64 %b
@@ -330,21 +326,21 @@ define i64 @and_i64_0xfff0(i64 %a) {
 define i64 @and_i64_0xfff0_twice(i64 %a, i64 %b) {
 ; LA32-LABEL: and_i64_0xfff0_twice:
 ; LA32:       # %bb.0:
-; LA32-NEXT:    lu12i.w $a1, 15
-; LA32-NEXT:    ori $a1, $a1, 4080
-; LA32-NEXT:    and $a2, $a2, $a1
-; LA32-NEXT:    and $a1, $a0, $a1
-; LA32-NEXT:    sub.w $a0, $a1, $a2
-; LA32-NEXT:    sltu $a1, $a1, $a2
+; LA32-NEXT:    bstrpick.w $a1, $a2, 15, 4
+; LA32-NEXT:    slli.w $a1, $a1, 4
+; LA32-NEXT:    bstrpick.w $a0, $a0, 15, 4
+; LA32-NEXT:    slli.w $a2, $a0, 4
+; LA32-NEXT:    sub.w $a0, $a2, $a1
+; LA32-NEXT:    sltu $a1, $a2, $a1
 ; LA32-NEXT:    sub.w $a1, $zero, $a1
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: and_i64_0xfff0_twice:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a2, 15
-; LA64-NEXT:    ori $a2, $a2, 4080
-; LA64-NEXT:    and $a1, $a1, $a2
-; LA64-NEXT:    and $a0, $a0, $a2
+; LA64-NEXT:    bstrpick.d $a1, $a1, 15, 4
+; LA64-NEXT:    slli.d $a1, $a1, 4
+; LA64-NEXT:    bstrpick.d $a0, $a0, 15, 4
+; LA64-NEXT:    slli.d $a0, $a0, 4
 ; LA64-NEXT:    sub.d $a0, $a0, $a1
 ; LA64-NEXT:    ret
   %c = and i64 %a, 65520
index 0838064..35f7c8c 100644 (file)
@@ -60,11 +60,10 @@ define void @conditional_alloca(i32 %n) nounwind {
 ; NOSHRINKW-NEXT:    b .LBB1_1
 ; NOSHRINKW-NEXT:  .LBB1_1: # %if.then
 ; NOSHRINKW-NEXT:    ld.d $a0, $fp, -24 # 8-byte Folded Reload
-; NOSHRINKW-NEXT:    addi.w $a1, $zero, -16
-; NOSHRINKW-NEXT:    lu32i.d $a1, 1
 ; NOSHRINKW-NEXT:    bstrpick.d $a0, $a0, 31, 0
 ; NOSHRINKW-NEXT:    addi.d $a0, $a0, 15
-; NOSHRINKW-NEXT:    and $a1, $a0, $a1
+; NOSHRINKW-NEXT:    bstrpick.d $a0, $a0, 32, 4
+; NOSHRINKW-NEXT:    slli.d $a1, $a0, 4
 ; NOSHRINKW-NEXT:    move $a0, $sp
 ; NOSHRINKW-NEXT:    sub.d $a0, $a0, $a1
 ; NOSHRINKW-NEXT:    move $sp, $a0
@@ -87,10 +86,9 @@ define void @conditional_alloca(i32 %n) nounwind {
 ; SHRINKW-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
 ; SHRINKW-NEXT:    st.d $fp, $sp, 0 # 8-byte Folded Spill
 ; SHRINKW-NEXT:    addi.d $fp, $sp, 16
-; SHRINKW-NEXT:    addi.w $a1, $zero, -16
-; SHRINKW-NEXT:    lu32i.d $a1, 1
 ; SHRINKW-NEXT:    addi.d $a0, $a0, 15
-; SHRINKW-NEXT:    and $a0, $a0, $a1
+; SHRINKW-NEXT:    bstrpick.d $a0, $a0, 32, 4
+; SHRINKW-NEXT:    slli.d $a0, $a0, 4
 ; SHRINKW-NEXT:    sub.d $a0, $sp, $a0
 ; SHRINKW-NEXT:    move $sp, $a0
 ; SHRINKW-NEXT:    bl %plt(notdead)
index 667a7af..e149f37 100644 (file)
@@ -51,11 +51,10 @@ define void @caller(i32 %n) {
 ; LA64-NEXT:    srli.d $a1, $sp, 6
 ; LA64-NEXT:    slli.d $sp, $a1, 6
 ; LA64-NEXT:    move $s8, $sp
-; LA64-NEXT:    addi.w $a1, $zero, -16
-; LA64-NEXT:    lu32i.d $a1, 1
 ; LA64-NEXT:    bstrpick.d $a0, $a0, 31, 0
 ; LA64-NEXT:    addi.d $a0, $a0, 15
-; LA64-NEXT:    and $a0, $a0, $a1
+; LA64-NEXT:    bstrpick.d $a0, $a0, 32, 4
+; LA64-NEXT:    slli.d $a0, $a0, 4
 ; LA64-NEXT:    sub.d $a0, $sp, $a0
 ; LA64-NEXT:    move $sp, $a0
 ; LA64-NEXT:    addi.d $a1, $s8, 0