[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