[llvm] 85342c2 - [ARM] Optimize immediate selection

Sjoerd Meijer via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 29 05:30:00 PDT 2020


Author: Sjoerd Meijer
Date: 2020-07-29T13:29:17+01:00
New Revision: 85342c27a303e68a4091797e5d7938aa7beb4da5

URL: https://github.com/llvm/llvm-project/commit/85342c27a303e68a4091797e5d7938aa7beb4da5
DIFF: https://github.com/llvm/llvm-project/commit/85342c27a303e68a4091797e5d7938aa7beb4da5.diff

LOG: [ARM] Optimize immediate selection

Optimize some specific immediates selection by materializing them with sub/mvn
instructions as opposed to loading them from the constant pool.

Patch by Ben Shi, powerman1st at 163.com.

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

Added: 
    llvm/test/CodeGen/ARM/add-sub-imm.ll

Modified: 
    llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
    llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
    llvm/lib/Target/ARM/ARMInstrInfo.td
    llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h
    llvm/test/CodeGen/ARM/select-imm.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index d340931f31d8..b501dc06ca72 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -5513,6 +5513,8 @@ unsigned llvm::ConstantMaterializationCost(unsigned Val,
       return ForCodesize ? 4 : 1;
     if (ARM_AM::isSOImmTwoPartVal(Val)) // two instrs
       return ForCodesize ? 8 : 2;
+    if (ARM_AM::isSOImmTwoPartValNeg(Val)) // two instrs
+      return ForCodesize ? 8 : 2;
   }
   if (Subtarget->useMovt()) // MOVW + MOVT
     return ForCodesize ? 8 : 2;

diff  --git a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
index ec72c2b5ac19..9be0b6fa33e9 100644
--- a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
@@ -873,16 +873,27 @@ void ARMExpandPseudo::ExpandMOV32BitImm(MachineBasicBlock &MBB,
     // FIXME Windows CE supports older ARM CPUs
     assert(!STI->isTargetWindows() && "Windows on ARM requires ARMv7+");
 
-    // Expand into a movi + orr.
-    LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::MOVi), DstReg);
-    HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::ORRri))
-      .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
-      .addReg(DstReg);
-
     assert (MO.isImm() && "MOVi32imm w/ non-immediate source operand!");
     unsigned ImmVal = (unsigned)MO.getImm();
-    unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal);
-    unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal);
+    unsigned SOImmValV1 = 0, SOImmValV2 = 0;
+
+    if (ARM_AM::isSOImmTwoPartVal(ImmVal)) { // Expand into a movi + orr.
+      LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::MOVi), DstReg);
+      HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::ORRri))
+          .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstReg);
+      SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal);
+      SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal);
+    } else { // Expand into a mvn + sub.
+      LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::MVNi), DstReg);
+      HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::SUBri))
+          .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstReg);
+      SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(-ImmVal);
+      SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(-ImmVal);
+      SOImmValV1 = ~(-SOImmValV1);
+    }
+
     unsigned MIFlags = MI.getFlags();
     LO16 = LO16.addImm(SOImmValV1);
     HI16 = HI16.addImm(SOImmValV2);

diff  --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td
index db2ab7a97aa6..d0c1e14989d3 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -824,7 +824,9 @@ def mod_imm_neg : Operand<i32>, PatLeaf<(imm), [{
 def arm_i32imm : IntImmLeaf<i32, [{
   if (Subtarget->useMovt())
     return true;
-  return ARM_AM::isSOImmTwoPartVal(Imm.getZExtValue());
+  if (ARM_AM::isSOImmTwoPartVal(Imm.getZExtValue()))
+    return true;
+  return ARM_AM::isSOImmTwoPartValNeg(Imm.getZExtValue());
 }]>;
 
 /// imm0_1 predicate - Immediate in the range [0,1].

diff  --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h
index 24a9fabf0979..dca252a177f2 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h
@@ -205,6 +205,20 @@ namespace ARM_AM {
     return V;
   }
 
+  /// isSOImmTwoPartValNeg - Return true if the specified value can be obtained
+  /// by two SOImmVal, that -V = First + Second.
+  /// "R+V" can be optimized to (sub (sub R, First), Second).
+  /// "R=V" can be optimized to (sub (mvn R, ~(-First)), Second).
+  inline bool isSOImmTwoPartValNeg(unsigned V) {
+    unsigned First;
+    if (!isSOImmTwoPartVal(-V))
+      return false;
+    // Return false if ~(-First) is not a SoImmval.
+    First = getSOImmTwoPartFirst(-V);
+    First = ~(-First);
+    return !(rotr32(~255U, getSOImmValRotate(First)) & First);
+  }
+
   /// getThumbImmValShift - Try to handle Imm with a 8-bit immediate followed
   /// by a left shift. Returns the shift amount to use.
   inline unsigned getThumbImmValShift(unsigned Imm) {

diff  --git a/llvm/test/CodeGen/ARM/add-sub-imm.ll b/llvm/test/CodeGen/ARM/add-sub-imm.ll
new file mode 100644
index 000000000000..71a860537ba1
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/add-sub-imm.ll
@@ -0,0 +1,70 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=arm-eabi %s -o - | FileCheck %s --check-prefix=CHECK
+
+;; Check how immediates are handled in add/sub.
+
+define i32 @sub0(i32 %0) {
+; CHECK-LABEL: sub0:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    sub r0, r0, #23
+; CHECK-NEXT:    mov pc, lr
+  %2 = sub i32 %0, 23
+  ret i32 %2
+}
+
+define i32 @sub1(i32 %0) {
+; CHECK-LABEL: sub1:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    ldr r1, .LCPI1_0
+; CHECK-NEXT:    add r0, r0, r1
+; CHECK-NEXT:    mov pc, lr
+; CHECK-NEXT:    .p2align 2
+; CHECK-NEXT:  @ %bb.1:
+; CHECK-NEXT:  .LCPI1_0:
+; CHECK-NEXT:    .long 4294836225 @ 0xfffe0001
+  %2 = sub i32 %0, 131071
+  ret i32 %2
+}
+
+define i32 @sub2(i32 %0) {
+; CHECK-LABEL: sub2:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    sub r0, r0, #35
+; CHECK-NEXT:    sub r0, r0, #8960
+; CHECK-NEXT:    mov pc, lr
+  %2 = sub i32 %0, 8995
+  ret i32 %2
+}
+
+define i32 @add0(i32 %0) {
+; CHECK-LABEL: add0:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    add r0, r0, #23
+; CHECK-NEXT:    mov pc, lr
+  %2 = add i32 %0, 23
+  ret i32 %2
+}
+
+define i32 @add1(i32 %0) {
+; CHECK-LABEL: add1:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    ldr r1, .LCPI4_0
+; CHECK-NEXT:    add r0, r0, r1
+; CHECK-NEXT:    mov pc, lr
+; CHECK-NEXT:    .p2align 2
+; CHECK-NEXT:  @ %bb.1:
+; CHECK-NEXT:  .LCPI4_0:
+; CHECK-NEXT:    .long 131071 @ 0x1ffff
+  %2 = add i32 %0, 131071
+  ret i32 %2
+}
+
+define i32 @add2(i32 %0) {
+; CHECK-LABEL: add2:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    add r0, r0, #8960
+; CHECK-NEXT:    add r0, r0, #2293760
+; CHECK-NEXT:    mov pc, lr
+  %2 = add i32 %0, 2302720
+  ret i32 %2
+}

diff  --git a/llvm/test/CodeGen/ARM/select-imm.ll b/llvm/test/CodeGen/ARM/select-imm.ll
index 628bae6e1dc9..5cdfe3326e92 100644
--- a/llvm/test/CodeGen/ARM/select-imm.ll
+++ b/llvm/test/CodeGen/ARM/select-imm.ll
@@ -85,7 +85,8 @@ entry:
 define i32 @t4(i32 %a, i32 %b, i32 %x) nounwind {
 entry:
 ; ARM-LABEL: t4:
-; ARM: ldr
+; ARM: mvn [[R0:r[0-9]+]], #170
+; ARM: sub [[R0:r[0-9]+]], [[R0:r[0-9]+]], #11141120
 ; ARM: mov{{lt|ge}}
 
 ; ARMT2-LABEL: t4:


        


More information about the llvm-commits mailing list