[llvm] [ARM] Use adds to implement integer cmn in thumb1 and thumb2 (PR #199247)
via llvm-commits
llvm-commits at lists.llvm.org
Fri May 22 11:11:55 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-arm
Author: LumioseSil (LumioseSil)
<details>
<summary>Changes</summary>
This saves us from having to materialize the negative.
---
Patch is 42.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/199247.diff
13 Files Affected:
- (modified) llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp (+51-37)
- (modified) llvm/lib/Target/ARM/ARMISelLowering.cpp (+3-8)
- (modified) llvm/test/CodeGen/ARM/cmn.ll (+2-4)
- (modified) llvm/test/CodeGen/ARM/consthoist-icmpimm.ll (+56-56)
- (added) llvm/test/CodeGen/ARM/thumb-cmp-neg-imm-adds.ll (+48)
- (modified) llvm/test/CodeGen/Thumb/cmp-add-fold.ll (+6-4)
- (modified) llvm/test/CodeGen/Thumb/smul_fix_sat.ll (+63-70)
- (modified) llvm/test/CodeGen/Thumb2/mve-blockplacement.ll (+10-10)
- (modified) llvm/test/CodeGen/Thumb2/mve-memtp-loop.ll (+1-1)
- (modified) llvm/test/CodeGen/Thumb2/mve-saturating-arith.ll (+2-2)
- (modified) llvm/test/CodeGen/Thumb2/mve-vselect-constants.ll (+2-2)
- (modified) llvm/test/CodeGen/Thumb2/pacbti-m-outliner-4.ll (+1-1)
- (modified) llvm/test/CodeGen/Thumb2/thumb2-cmp.ll (+159-25)
``````````diff
diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 61b679d55fb47..2f31efa082d81 100644
--- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -315,6 +315,10 @@ class ARMDAGToDAGISel : public SelectionDAGISel {
void SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI);
+ /// Thumb compare-with-negative-immediate -> tADDSi / t2ADDSri with a dead
+ /// GPR def; compare users take the CPSR result (not the GPR).
+ bool selectCmpNegImmToAdds(SDNode *N);
+
void SelectCMP_SWAP(SDNode *N);
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
@@ -3678,6 +3682,49 @@ static unsigned getVectorShuffleOpcode(EVT VT, unsigned Opc64[3],
}
}
+bool ARMDAGToDAGISel::selectCmpNegImmToAdds(SDNode *N) {
+ assert((N->getOpcode() == ARMISD::CMP ||
+ N->getOpcode() == ARMISD::CMPZ) &&
+ "expected an ARM compare node");
+
+ // ARM-mode functions use CMP/CMN; this transform is Thumb-only.
+ if (!Subtarget->isThumb())
+ return false;
+
+ auto *RHSC = dyn_cast<ConstantSDNode>(N->getOperand(1));
+ if (!RHSC || RHSC->getSExtValue() >= 0)
+ return false;
+
+ int64_t Addend = -RHSC->getSExtValue();
+ // Thumb1 only has 16-bit ADD/S with immediates up to 255.
+ if (Addend >= 256)
+ return false;
+
+ // Thumb2: use 32-bit CMN when the addend does not fit a narrow ADDS.
+ if (Subtarget->hasThumb2() && ARM_AM::getT2SOImmVal(Addend) == -1)
+ return false;
+
+ SDLoc dl(N);
+ SDValue LHS = N->getOperand(0);
+ SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
+
+ // Select directly to a flag-setting ADDS with two results (GPR, CPSR).
+ // Compare users must use result 1; result 0 is an unused in-place add.
+ if (Subtarget->hasThumb2()) {
+ SDValue Ops[] = {LHS, getI32Imm(Addend, dl), getAL(CurDAG, dl), Reg0};
+ CurDAG->SelectNodeTo(N, ARM::t2ADDSri, MVT::i32, MVT::i32, Ops);
+ } else {
+ unsigned Opc = Addend < 8 ? ARM::tADDSi3 : ARM::tADDSi8;
+ SDValue Ops[] = {LHS, getI32Imm(Addend, dl)};
+ CurDAG->SelectNodeTo(N, Opc, MVT::i32, MVT::i32, Ops);
+ }
+
+ // ARMcmp/CMPZ only expose flags on result 0; after SelectNodeTo that slot
+ // is the GPR def. Rewire all compare users to result 1 (CPSR).
+ ReplaceUses(SDValue(N, 0), SDValue(N, 1));
+ return true;
+}
+
void ARMDAGToDAGISel::Select(SDNode *N) {
SDLoc dl(N);
@@ -4196,44 +4243,11 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
CurDAG->SelectNodeTo(N, Opc, MVT::Other, Ops);
return;
}
-
- case ARMISD::CMPZ: {
- // select (CMPZ X, #-C) -> (CMPZ (ADDS X, #C), #0)
- // This allows us to avoid materializing the expensive negative constant.
- // The CMPZ #0 is useless and will be peepholed away but we need to keep
- // it for its flags output.
- SDValue X = N->getOperand(0);
- auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1).getNode());
- if (C && C->getSExtValue() < 0 && Subtarget->isThumb()) {
- int64_t Addend = -C->getSExtValue();
-
- SDNode *Add = nullptr;
- // ADDS can be better than CMN if the immediate fits in a
- // 16-bit ADDS, which means either [0,256) for tADDi8 or [0,8) for tADDi3.
- // Outside that range we can just use a CMN which is 32-bit but has a
- // 12-bit immediate range.
- if (Addend < 1<<8) {
- if (Subtarget->isThumb2()) {
- SDValue Ops[] = { X, CurDAG->getTargetConstant(Addend, dl, MVT::i32),
- getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
- CurDAG->getRegister(0, MVT::i32) };
- Add = CurDAG->getMachineNode(ARM::t2ADDri, dl, MVT::i32, Ops);
- } else {
- unsigned Opc = (Addend < 1<<3) ? ARM::tADDi3 : ARM::tADDi8;
- SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), X,
- CurDAG->getTargetConstant(Addend, dl, MVT::i32),
- getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
- Add = CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
- }
- }
- if (Add) {
- SDValue Ops2[] = {SDValue(Add, 0), CurDAG->getConstant(0, dl, MVT::i32)};
- CurDAG->MorphNodeTo(N, ARMISD::CMPZ, N->getVTList(), Ops2);
- }
- }
- // Other cases are autogenerated.
+ case ARMISD::CMP:
+ case ARMISD::CMPZ:
+ if (selectCmpNegImmToAdds(N))
+ return;
break;
- }
case ARMISD::CMOV: {
SDValue Flags = N->getOperand(3);
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 635a5f4e6ca94..50ce3a0ee8fa8 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -19729,16 +19729,11 @@ bool ARMTargetLowering::isLegalAddressingMode(const DataLayout &DL,
/// icmp immediate, that is the target has icmp instructions which can compare
/// a register against the immediate without having to materialize the
/// immediate into a register.
+
+// Integer comparisons have the same range as ADDS/SUBS, and for thumb1, implemented as adds.
bool ARMTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
// Thumb2 and ARM modes can use cmn for negative immediates.
- if (!Subtarget->isThumb())
- return ARM_AM::getSOImmVal((uint32_t)Imm) != -1 ||
- ARM_AM::getSOImmVal(-(uint32_t)Imm) != -1;
- if (Subtarget->isThumb2())
- return ARM_AM::getT2SOImmVal((uint32_t)Imm) != -1 ||
- ARM_AM::getT2SOImmVal(-(uint32_t)Imm) != -1;
- // Thumb1 doesn't have cmn, and only 8-bit immediates.
- return Imm >= 0 && Imm <= 255;
+ return isLegalAddImmediate(Imm);
}
/// isLegalAddImmediate - Return true if the specified immediate is a legal add
diff --git a/llvm/test/CodeGen/ARM/cmn.ll b/llvm/test/CodeGen/ARM/cmn.ll
index fbcee5196b63d..e506e49731f6b 100644
--- a/llvm/test/CodeGen/ARM/cmn.ll
+++ b/llvm/test/CodeGen/ARM/cmn.ll
@@ -7,7 +7,7 @@ define i32 @compare_i_gt(i32 %a) {
; T2-LABEL: compare_i_gt:
; T2: @ %bb.0: @ %entry
; T2-NEXT: movs r1, #24
-; T2-NEXT: cmn.w r0, #78
+; T2-NEXT: adds r0, #78
; T2-NEXT: it gt
; T2-NEXT: movgt r1, #42
; T2-NEXT: mov r0, r1
@@ -15,9 +15,7 @@ define i32 @compare_i_gt(i32 %a) {
;
; T1-LABEL: compare_i_gt:
; T1: @ %bb.0: @ %entry
-; T1-NEXT: movs r1, #77
-; T1-NEXT: mvns r1, r1
-; T1-NEXT: cmp r0, r1
+; T1-NEXT: adds r0, #78
; T1-NEXT: bgt .LBB0_2
; T1-NEXT: @ %bb.1: @ %entry
; T1-NEXT: movs r0, #24
diff --git a/llvm/test/CodeGen/ARM/consthoist-icmpimm.ll b/llvm/test/CodeGen/ARM/consthoist-icmpimm.ll
index 16b7403bdb932..541b2b679a613 100644
--- a/llvm/test/CodeGen/ARM/consthoist-icmpimm.ll
+++ b/llvm/test/CodeGen/ARM/consthoist-icmpimm.ll
@@ -12,26 +12,26 @@ define i32 @icmp64_sge_0(i64 %x, i64 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV6M-NEXT: ldr r0, [sp]
; CHECKV6M-NEXT: beq .LBB0_4
; CHECKV6M-NEXT: @ %bb.1: @ %then
-; CHECKV6M-NEXT: cmp r3, #0
+; CHECKV6M-NEXT: adds r3, r3, #1
; CHECKV6M-NEXT: mov r3, r0
-; CHECKV6M-NEXT: blt .LBB0_7
+; CHECKV6M-NEXT: ble .LBB0_7
; CHECKV6M-NEXT: @ %bb.2: @ %then
-; CHECKV6M-NEXT: cmp r1, #0
-; CHECKV6M-NEXT: blt .LBB0_8
+; CHECKV6M-NEXT: adds r1, r1, #1
+; CHECKV6M-NEXT: ble .LBB0_8
; CHECKV6M-NEXT: .LBB0_3: @ %then
; CHECKV6M-NEXT: adds r0, r0, r3
; CHECKV6M-NEXT: bx lr
; CHECKV6M-NEXT: .LBB0_4: @ %else
-; CHECKV6M-NEXT: cmp r1, #0
-; CHECKV6M-NEXT: bge .LBB0_6
+; CHECKV6M-NEXT: adds r1, r1, #1
+; CHECKV6M-NEXT: bgt .LBB0_6
; CHECKV6M-NEXT: @ %bb.5: @ %else
; CHECKV6M-NEXT: mov r0, r2
; CHECKV6M-NEXT: .LBB0_6: @ %else
; CHECKV6M-NEXT: bx lr
; CHECKV6M-NEXT: .LBB0_7: @ %then
; CHECKV6M-NEXT: mov r3, r2
-; CHECKV6M-NEXT: cmp r1, #0
-; CHECKV6M-NEXT: bge .LBB0_3
+; CHECKV6M-NEXT: adds r1, r1, #1
+; CHECKV6M-NEXT: bgt .LBB0_3
; CHECKV6M-NEXT: .LBB0_8: @ %then
; CHECKV6M-NEXT: mov r0, r2
; CHECKV6M-NEXT: adds r0, r0, r3
@@ -44,17 +44,17 @@ define i32 @icmp64_sge_0(i64 %x, i64 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV7M-NEXT: ldrd r2, r0, [sp]
; CHECKV7M-NEXT: beq .LBB0_2
; CHECKV7M-NEXT: @ %bb.1: @ %then
-; CHECKV7M-NEXT: cmp.w r3, #-1
+; CHECKV7M-NEXT: adds r3, #1
; CHECKV7M-NEXT: mov r3, r0
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r3, r2
-; CHECKV7M-NEXT: cmp.w r1, #-1
+; CHECKV7M-NEXT: adds r1, #1
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r0, r2
; CHECKV7M-NEXT: add r0, r3
; CHECKV7M-NEXT: bx lr
; CHECKV7M-NEXT: .LBB0_2: @ %else
-; CHECKV7M-NEXT: cmp.w r1, #-1
+; CHECKV7M-NEXT: adds r1, #1
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r0, r2
; CHECKV7M-NEXT: bx lr
@@ -66,17 +66,17 @@ define i32 @icmp64_sge_0(i64 %x, i64 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV7A-NEXT: lsls r2, r2, #31
; CHECKV7A-NEXT: beq .LBB0_2
; CHECKV7A-NEXT: @ %bb.1: @ %then
-; CHECKV7A-NEXT: cmp.w r3, #-1
+; CHECKV7A-NEXT: adds r2, r3, #1
; CHECKV7A-NEXT: mov r2, r0
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r2, r12
-; CHECKV7A-NEXT: cmp.w r1, #-1
+; CHECKV7A-NEXT: adds r1, #1
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r0, r12
; CHECKV7A-NEXT: add r0, r2
; CHECKV7A-NEXT: bx lr
; CHECKV7A-NEXT: .LBB0_2: @ %else
-; CHECKV7A-NEXT: cmp.w r1, #-1
+; CHECKV7A-NEXT: adds r1, #1
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r0, r12
; CHECKV7A-NEXT: bx lr
@@ -103,26 +103,26 @@ define i32 @icmp64_sgt_m1(i64 %x, i64 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV6M-NEXT: ldr r0, [sp]
; CHECKV6M-NEXT: beq .LBB1_4
; CHECKV6M-NEXT: @ %bb.1: @ %then
-; CHECKV6M-NEXT: cmp r3, #0
+; CHECKV6M-NEXT: adds r3, r3, #1
; CHECKV6M-NEXT: mov r3, r0
-; CHECKV6M-NEXT: blt .LBB1_7
+; CHECKV6M-NEXT: ble .LBB1_7
; CHECKV6M-NEXT: @ %bb.2: @ %then
-; CHECKV6M-NEXT: cmp r1, #0
-; CHECKV6M-NEXT: blt .LBB1_8
+; CHECKV6M-NEXT: adds r1, r1, #1
+; CHECKV6M-NEXT: ble .LBB1_8
; CHECKV6M-NEXT: .LBB1_3: @ %then
; CHECKV6M-NEXT: adds r0, r0, r3
; CHECKV6M-NEXT: bx lr
; CHECKV6M-NEXT: .LBB1_4: @ %else
-; CHECKV6M-NEXT: cmp r3, #0
-; CHECKV6M-NEXT: bge .LBB1_6
+; CHECKV6M-NEXT: adds r1, r3, #1
+; CHECKV6M-NEXT: bgt .LBB1_6
; CHECKV6M-NEXT: @ %bb.5: @ %else
; CHECKV6M-NEXT: mov r0, r2
; CHECKV6M-NEXT: .LBB1_6: @ %else
; CHECKV6M-NEXT: bx lr
; CHECKV6M-NEXT: .LBB1_7: @ %then
; CHECKV6M-NEXT: mov r3, r2
-; CHECKV6M-NEXT: cmp r1, #0
-; CHECKV6M-NEXT: bge .LBB1_3
+; CHECKV6M-NEXT: adds r1, r1, #1
+; CHECKV6M-NEXT: bgt .LBB1_3
; CHECKV6M-NEXT: .LBB1_8: @ %then
; CHECKV6M-NEXT: mov r0, r2
; CHECKV6M-NEXT: adds r0, r0, r3
@@ -135,17 +135,17 @@ define i32 @icmp64_sgt_m1(i64 %x, i64 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV7M-NEXT: ldrd r2, r0, [sp]
; CHECKV7M-NEXT: beq .LBB1_2
; CHECKV7M-NEXT: @ %bb.1: @ %then
-; CHECKV7M-NEXT: cmp.w r3, #-1
+; CHECKV7M-NEXT: adds r3, #1
; CHECKV7M-NEXT: mov r3, r0
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r3, r2
-; CHECKV7M-NEXT: cmp.w r1, #-1
+; CHECKV7M-NEXT: adds r1, #1
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r0, r2
; CHECKV7M-NEXT: add r0, r3
; CHECKV7M-NEXT: bx lr
; CHECKV7M-NEXT: .LBB1_2: @ %else
-; CHECKV7M-NEXT: cmp.w r3, #-1
+; CHECKV7M-NEXT: adds r1, r3, #1
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r0, r2
; CHECKV7M-NEXT: bx lr
@@ -157,17 +157,17 @@ define i32 @icmp64_sgt_m1(i64 %x, i64 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV7A-NEXT: lsls r2, r2, #31
; CHECKV7A-NEXT: beq .LBB1_2
; CHECKV7A-NEXT: @ %bb.1: @ %then
-; CHECKV7A-NEXT: cmp.w r3, #-1
+; CHECKV7A-NEXT: adds r2, r3, #1
; CHECKV7A-NEXT: mov r2, r0
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r2, r12
-; CHECKV7A-NEXT: cmp.w r1, #-1
+; CHECKV7A-NEXT: adds r1, #1
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r0, r12
; CHECKV7A-NEXT: add r0, r2
; CHECKV7A-NEXT: bx lr
; CHECKV7A-NEXT: .LBB1_2: @ %else
-; CHECKV7A-NEXT: cmp.w r3, #-1
+; CHECKV7A-NEXT: adds r1, r3, #1
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r0, r12
; CHECKV7A-NEXT: bx lr
@@ -194,18 +194,18 @@ define i32 @icmp32_sge_0(i32 %x, i32 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV6M-NEXT: lsls r4, r4, #31
; CHECKV6M-NEXT: beq .LBB2_4
; CHECKV6M-NEXT: @ %bb.1: @ %then
-; CHECKV6M-NEXT: cmp r1, #0
+; CHECKV6M-NEXT: adds r1, r1, #1
; CHECKV6M-NEXT: mov r1, r2
-; CHECKV6M-NEXT: blt .LBB2_7
+; CHECKV6M-NEXT: ble .LBB2_7
; CHECKV6M-NEXT: @ %bb.2: @ %then
-; CHECKV6M-NEXT: cmp r0, #0
-; CHECKV6M-NEXT: blt .LBB2_8
+; CHECKV6M-NEXT: adds r0, r0, #1
+; CHECKV6M-NEXT: ble .LBB2_8
; CHECKV6M-NEXT: .LBB2_3: @ %then
; CHECKV6M-NEXT: adds r0, r2, r1
; CHECKV6M-NEXT: pop {r4, pc}
; CHECKV6M-NEXT: .LBB2_4: @ %else
-; CHECKV6M-NEXT: cmp r0, #0
-; CHECKV6M-NEXT: bge .LBB2_6
+; CHECKV6M-NEXT: adds r0, r0, #1
+; CHECKV6M-NEXT: bgt .LBB2_6
; CHECKV6M-NEXT: @ %bb.5: @ %else
; CHECKV6M-NEXT: mov r2, r3
; CHECKV6M-NEXT: .LBB2_6: @ %else
@@ -213,8 +213,8 @@ define i32 @icmp32_sge_0(i32 %x, i32 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV6M-NEXT: pop {r4, pc}
; CHECKV6M-NEXT: .LBB2_7: @ %then
; CHECKV6M-NEXT: mov r1, r3
-; CHECKV6M-NEXT: cmp r0, #0
-; CHECKV6M-NEXT: bge .LBB2_3
+; CHECKV6M-NEXT: adds r0, r0, #1
+; CHECKV6M-NEXT: bgt .LBB2_3
; CHECKV6M-NEXT: .LBB2_8: @ %then
; CHECKV6M-NEXT: mov r2, r3
; CHECKV6M-NEXT: adds r0, r2, r1
@@ -227,17 +227,17 @@ define i32 @icmp32_sge_0(i32 %x, i32 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV7M-NEXT: lsls r3, r3, #31
; CHECKV7M-NEXT: beq .LBB2_2
; CHECKV7M-NEXT: @ %bb.1: @ %then
-; CHECKV7M-NEXT: cmp.w r1, #-1
+; CHECKV7M-NEXT: adds r1, #1
; CHECKV7M-NEXT: mov r1, r12
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r1, r2
-; CHECKV7M-NEXT: cmp.w r0, #-1
+; CHECKV7M-NEXT: adds r0, #1
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r12, r2
; CHECKV7M-NEXT: add.w r0, r12, r1
; CHECKV7M-NEXT: bx lr
; CHECKV7M-NEXT: .LBB2_2: @ %else
-; CHECKV7M-NEXT: cmp.w r0, #-1
+; CHECKV7M-NEXT: adds r0, #1
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r12, r2
; CHECKV7M-NEXT: mov r0, r12
@@ -250,17 +250,17 @@ define i32 @icmp32_sge_0(i32 %x, i32 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV7A-NEXT: lsls r3, r3, #31
; CHECKV7A-NEXT: beq .LBB2_2
; CHECKV7A-NEXT: @ %bb.1: @ %then
-; CHECKV7A-NEXT: cmp.w r1, #-1
+; CHECKV7A-NEXT: adds r1, #1
; CHECKV7A-NEXT: mov r1, r12
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r1, r2
-; CHECKV7A-NEXT: cmp.w r0, #-1
+; CHECKV7A-NEXT: adds r0, #1
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r12, r2
; CHECKV7A-NEXT: add.w r0, r12, r1
; CHECKV7A-NEXT: bx lr
; CHECKV7A-NEXT: .LBB2_2: @ %else
-; CHECKV7A-NEXT: cmp.w r0, #-1
+; CHECKV7A-NEXT: adds r0, #1
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r12, r2
; CHECKV7A-NEXT: mov r0, r12
@@ -288,18 +288,18 @@ define i32 @icmp32_sgt_m1(i32 %x, i32 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV6M-NEXT: lsls r4, r4, #31
; CHECKV6M-NEXT: beq .LBB3_4
; CHECKV6M-NEXT: @ %bb.1: @ %then
-; CHECKV6M-NEXT: cmp r1, #0
+; CHECKV6M-NEXT: adds r1, r1, #1
; CHECKV6M-NEXT: mov r1, r2
-; CHECKV6M-NEXT: blt .LBB3_7
+; CHECKV6M-NEXT: ble .LBB3_7
; CHECKV6M-NEXT: @ %bb.2: @ %then
-; CHECKV6M-NEXT: cmp r0, #0
-; CHECKV6M-NEXT: blt .LBB3_8
+; CHECKV6M-NEXT: adds r0, r0, #1
+; CHECKV6M-NEXT: ble .LBB3_8
; CHECKV6M-NEXT: .LBB3_3: @ %then
; CHECKV6M-NEXT: adds r0, r2, r1
; CHECKV6M-NEXT: pop {r4, pc}
; CHECKV6M-NEXT: .LBB3_4: @ %else
-; CHECKV6M-NEXT: cmp r1, #0
-; CHECKV6M-NEXT: bge .LBB3_6
+; CHECKV6M-NEXT: adds r0, r1, #1
+; CHECKV6M-NEXT: bgt .LBB3_6
; CHECKV6M-NEXT: @ %bb.5: @ %else
; CHECKV6M-NEXT: mov r2, r3
; CHECKV6M-NEXT: .LBB3_6: @ %else
@@ -307,8 +307,8 @@ define i32 @icmp32_sgt_m1(i32 %x, i32 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV6M-NEXT: pop {r4, pc}
; CHECKV6M-NEXT: .LBB3_7: @ %then
; CHECKV6M-NEXT: mov r1, r3
-; CHECKV6M-NEXT: cmp r0, #0
-; CHECKV6M-NEXT: bge .LBB3_3
+; CHECKV6M-NEXT: adds r0, r0, #1
+; CHECKV6M-NEXT: bgt .LBB3_3
; CHECKV6M-NEXT: .LBB3_8: @ %then
; CHECKV6M-NEXT: mov r2, r3
; CHECKV6M-NEXT: adds r0, r2, r1
@@ -321,17 +321,17 @@ define i32 @icmp32_sgt_m1(i32 %x, i32 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV7M-NEXT: lsls r3, r3, #31
; CHECKV7M-NEXT: beq .LBB3_2
; CHECKV7M-NEXT: @ %bb.1: @ %then
-; CHECKV7M-NEXT: cmp.w r1, #-1
+; CHECKV7M-NEXT: adds r1, #1
; CHECKV7M-NEXT: mov r1, r12
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r1, r2
-; CHECKV7M-NEXT: cmp.w r0, #-1
+; CHECKV7M-NEXT: adds r0, #1
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r12, r2
; CHECKV7M-NEXT: add.w r0, r12, r1
; CHECKV7M-NEXT: bx lr
; CHECKV7M-NEXT: .LBB3_2: @ %else
-; CHECKV7M-NEXT: cmp.w r1, #-1
+; CHECKV7M-NEXT: adds r0, r1, #1
; CHECKV7M-NEXT: it gt
; CHECKV7M-NEXT: movgt r12, r2
; CHECKV7M-NEXT: mov r0, r12
@@ -344,17 +344,17 @@ define i32 @icmp32_sgt_m1(i32 %x, i32 %y, i32 %a, i32 %b, i1 %c) {
; CHECKV7A-NEXT: lsls r3, r3, #31
; CHECKV7A-NEXT: beq .LBB3_2
; CHECKV7A-NEXT: @ %bb.1: @ %then
-; CHECKV7A-NEXT: cmp.w r1, #-1
+; CHECKV7A-NEXT: adds r1, #1
; CHECKV7A-NEXT: mov r1, r12
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r1, r2
-; CHECKV7A-NEXT: cmp.w r0, #-1
+; CHECKV7A-NEXT: adds r0, #1
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r12, r2
; CHECKV7A-NEXT: add.w r0, r12, r1
; CHECKV7A-NEXT: bx lr
; CHECKV7A-NEXT: .LBB3_2: @ %else
-; CHECKV7A-NEXT: cmp.w r1, #-1
+; CHECKV7A-NEXT: adds r0, r1, #1
; CHECKV7A-NEXT: it gt
; CHECKV7A-NEXT: movgt r12, r2
; CHECKV7A-NEXT: mov r0, r12
diff --git a/llvm/test/CodeGen/ARM/thumb-cmp-neg-imm-adds.ll b/llvm/test/CodeGen/ARM/thumb-cmp-neg-imm-adds.ll
new file mode 100644
index 0000000000000..e981bda5c8ca9
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/thumb-cmp-neg-imm-adds.ll
@@ -0,0 +1,48 @@
+; RUN: llc -mtriple=thumbv6m %s -o - | FileCheck %s --check-prefix=T1
+; RUN: llc -mtriple=thumbv7 %s -o - | FileCheck %s --check-prefix=T2
+
+; Compare against a small negative constant should use 16-bit ADDS, not CMN.
+define i1 @cmp_eq_small_neg(i32 %a) {
+; T1-LABEL: cmp_eq_small_neg:
+; T1: adds{{[ \t]}}
+; T1-NOT: {{[ \t]}}cmn{{[ \t]}}
+; T1-NOT: {{[ \t]}}cmp{{[ \t]}}r
+; T1-NOT: {{[ \t]}}cmp{{[ \t]}}#
+;
+; T2-LABEL: cmp_eq_small_neg:
+; T2: adds{{[ \t]}}
+; T2-NOT: {{[ \t]}}cmn
+; T2-NOT: {{[ \t]}}cmp{{[ \t]}}r
+; T2-NOT: {{[ \t]}}cmp{{[ \t]}}#
+entry:
+ %cmp = icmp eq i32 %a, -5
+ ret i1 %cmp
+}
+
+define i1 @cmp_sgt_small_neg(i32 %a) {
+; T1-LABEL: cmp_sgt_small_neg:
+; T1: adds{{[ \t]}}r0, #42
+; T1-NOT: {{[ \t]}}cmn{{[ \t]}}
+;
+; T2-LABEL: cmp_sgt_small_neg:
+; T2: adds{{[ \t]}}r0, #42
+; T2-NOT: {{[ \t]}}cmn.w
+entry:
+ %cmp = icmp sgt i32 %a, -42
+ ret i1 %cmp
+}
+
+; Large negative immediates still need a full compare, not 32-bit CMN on Thumb1.
+define i1 @cmp_large_neg(i32 %a) {
+; T1-LABEL: cmp_large_neg:
+; T1: cmp{{[ \t]}}r0,
+; T1-NOT: {{[ \t]}}cmn{{[ \t]}}
+; T1-NOT: {{[ \t]}}adds{{[ \t]}}
+;
+; T2-LABEL: cmp_large_neg:
+; T2: cmn.w{{[ \t]}}r0,
+; T2-NOT: {{[ \t]}}adds{{[ \t]}}
+entry:
+ %cmp = icmp sgt i32 %a, -50529027
+ ret i1 %cmp
+}
diff --git a/llvm/test/CodeGen/Thumb/cmp-add-fold.ll b/llvm/test/CodeGen/Thumb/cmp-add-fold.ll
index 4dc0bc70440dd..3baa4e7097d13 100644
--- a/llvm/test/CodeGen/Thumb/cmp-add-fold.ll
+++ b/llvm/test/CodeGen/Thumb/cmp-add-fold.ll
@@ -16,10 +16,11 @@ define i32 @addri1(i32 %a, i32 %b) {
;
; T2-LABEL: addri1:
; T2: @ %bb.0: @ %entry
+; T2-NEXT: movs r1, #5
; T2-NEXT: adds r0, #3
-; T2-NEXT: mov.w r0, #5
; T2-NEXT: it eq
-; T2-NEXT: moveq r0, #4
+; T2-NEXT: moveq r1, #4
+; T2-NEXT: mov r0, r1
; T2-NEXT: bx lr
entry:
%c = add i32 %a, 3
@@ -47,10 +48,11 @@ define i32 @addri2(i32 %a, i32 %b) {
;
; T2-LABEL: addri2:
; T2: @ %bb.0: @ %entry
+; T2-NEXT: movs r1, #5
; T2-NEXT: adds r0, #254
-; T2-NEXT: mov.w r0, #5
; T2-NEXT: it eq
-; T2-NEXT: moveq r0, #4
+; T2-NEXT: moveq r1, #4
+; T2-NEXT: mov r0, r1
; T2-NEXT: bx lr
entry:
%c = add i32 %a, 254
diff --git a/llvm/test/CodeGen/Thumb/smul_fix_sat.ll b/llvm/test...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/199247
More information about the llvm-commits
mailing list