[llvm] [ARM] Selection should prefer immediates on the right hand side instead of shifted regs (PR #205126)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 22 09:05:29 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-arm
Author: AZero13 (AZero13)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/205126.diff
2 Files Affected:
- (modified) llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp (+83)
- (modified) llvm/test/CodeGen/ARM/cmse-harden-entry-arguments.ll (+4-4)
``````````diff
diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 61b679d55fb47..d31574f21b8b8 100644
--- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -188,6 +188,10 @@ class ARMDAGToDAGISel : public SelectionDAGISel {
private:
void transferMemOperands(SDNode *Src, SDNode *Dst);
+ // Preference helper: for SUB with encodable immediate LHS, select RSBri
+ // and materialize any RHS shift first when needed. Returns true if handled.
+ bool tryPreferRSBForSUB(SDNode *N);
+
/// Indexed (pre/post inc/dec) load matching code for ARM.
bool tryARMIndexedLoad(SDNode *N);
bool tryT1IndexedLoad(SDNode *N);
@@ -3588,6 +3592,81 @@ getContiguousRangeOfSetBits(const APInt &A) {
return std::make_pair(FirstOne, LastOne);
}
+bool ARMDAGToDAGISel::tryPreferRSBForSUB(SDNode *N) {
+ if (Subtarget->isThumb1Only())
+ return false;
+
+ SDValue LHS = N->getOperand(0);
+ SDValue RHS = N->getOperand(1);
+ const auto *CI = dyn_cast<ConstantSDNode>(LHS);
+ if (!CI)
+ return false;
+
+ unsigned Imm = (unsigned)CI->getZExtValue();
+ bool Encodable = Subtarget->isThumb() ? is_t2_so_imm(Imm) : is_so_imm(Imm);
+ if (!Encodable)
+ return false;
+
+ SDLoc dl(N);
+ SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
+ SDValue ImmOp = CurDAG->getTargetConstant(Imm, dl, MVT::i32);
+
+ // Materialize shift if RHS is shifted
+ ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(RHS.getOpcode());
+ SDValue Rn = RHS;
+ if (ShOpcVal != ARM_AM::no_shift) {
+ const ConstantSDNode *ShC = dyn_cast<ConstantSDNode>(RHS.getOperand(1));
+ if (!ShC)
+ return false; // can't safely materialize variable shift here
+ unsigned ShAmt = ShC->getZExtValue();
+ if (Subtarget->isThumb()) {
+ unsigned ShOpc = 0;
+ switch (ShOpcVal) {
+ default:
+ ShOpc = 0;
+ break;
+ case ARM_AM::lsl:
+ ShOpc = ARM::t2LSLri;
+ break;
+ case ARM_AM::lsr:
+ ShOpc = ARM::t2LSRri;
+ break;
+ case ARM_AM::asr:
+ ShOpc = ARM::t2ASRri;
+ break;
+ case ARM_AM::ror:
+ ShOpc = ARM::t2RORri;
+ break;
+ }
+ if (!ShOpc)
+ return false;
+ SDValue ShAmtOp = CurDAG->getTargetConstant(ShAmt, dl, MVT::i32);
+ SDValue OpsShift[] = {RHS.getOperand(0), ShAmtOp, getAL(CurDAG, dl), Reg0,
+ Reg0};
+ MachineSDNode *ShN =
+ CurDAG->getMachineNode(ShOpc, dl, MVT::i32, OpsShift);
+ Rn = SDValue(ShN, 0);
+ } else {
+ unsigned SOpc = ARM_AM::getSORegOpc(ShOpcVal, ShAmt);
+ SDValue ShImmOp = CurDAG->getTargetConstant(SOpc, dl, MVT::i32);
+ SDValue OpsShift[] = {RHS.getOperand(0), ShImmOp, getAL(CurDAG, dl), Reg0,
+ Reg0};
+ MachineSDNode *ShN =
+ CurDAG->getMachineNode(ARM::MOVsi, dl, MVT::i32, OpsShift);
+ Rn = SDValue(ShN, 0);
+ }
+ }
+
+ if (Subtarget->isThumb()) {
+ SDValue Ops[] = {Rn, ImmOp, getAL(CurDAG, dl), Reg0, Reg0};
+ CurDAG->SelectNodeTo(N, ARM::t2RSBri, MVT::i32, Ops);
+ } else {
+ SDValue Ops[] = {Rn, ImmOp, getAL(CurDAG, dl), Reg0, Reg0};
+ CurDAG->SelectNodeTo(N, ARM::RSBri, MVT::i32, Ops);
+ }
+ return true;
+}
+
void ARMDAGToDAGISel::SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI) {
assert(N->getOpcode() == ARMISD::CMPZ);
SwitchEQNEToPLMI = false;
@@ -3739,6 +3818,10 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
if (tryInlineAsm(N))
return;
break;
+ case ISD::SUB:
+ if (tryPreferRSBForSUB(N))
+ return;
+ break;
case ISD::Constant: {
unsigned Val = N->getAsZExtVal();
// If we can't materialize the constant we need to use a literal pool
diff --git a/llvm/test/CodeGen/ARM/cmse-harden-entry-arguments.ll b/llvm/test/CodeGen/ARM/cmse-harden-entry-arguments.ll
index c66ab00566ddf..35a46ffde206e 100644
--- a/llvm/test/CodeGen/ARM/cmse-harden-entry-arguments.ll
+++ b/llvm/test/CodeGen/ARM/cmse-harden-entry-arguments.ll
@@ -297,8 +297,8 @@ define i32 @access_i65(ptr byval(i65) %0) "cmse_nonsecure_entry" {
; V8M-LE-NEXT: ldrb.w r0, [sp, #8]
; V8M-LE-NEXT: and r0, r0, #1
; V8M-LE-NEXT: rsbs r0, r0, #0
-; V8M-BE-NEXT: movs r1, #0
-; V8M-BE-NEXT: sub.w r0, r1, r0, lsr #24
+; V8M-BE-NEXT: lsrs r0, r0, #24
+; V8M-BE-NEXT: rsbs r0, r0, #0
; V8M-COMMON-NEXT: add sp, #16
; V8M-COMMON-NEXT: mov r1, lr
; V8M-COMMON-NEXT: mov r2, lr
@@ -316,8 +316,8 @@ define i32 @access_i65(ptr byval(i65) %0) "cmse_nonsecure_entry" {
; V81M-LE-NEXT: ldrb.w r0, [sp, #8]
; V81M-LE-NEXT: and r0, r0, #1
; V81M-LE-NEXT: rsbs r0, r0, #0
-; V81M-BE-NEXT: movs r1, #0
-; V81M-BE-NEXT: sub.w r0, r1, r0, lsr #24
+; V81M-BE-NEXT: lsrs r0, r0, #24
+; V81M-BE-NEXT: rsbs r0, r0, #0
; V81M-COMMON-NEXT: sub sp, #4
; V81M-COMMON-NEXT: add sp, #16
; V81M-COMMON-NEXT: vscclrm {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, vpr}
``````````
</details>
https://github.com/llvm/llvm-project/pull/205126
More information about the llvm-commits
mailing list