[llvm] [ARM] Custom Lowering for SADDO_CARRY an SSUBO_CARRY (PR #154419)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 20 13:59:15 PDT 2025


https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/154419

>From 27a8a2be5b255089c06a1adfeaaf1d9808bf12ec Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Tue, 19 Aug 2025 16:04:49 -0400
Subject: [PATCH] [ARM] Custom Lowering for SADDO_CARRY an SSUBO_CARRY

To do this, I did refactoring to mirror what goes on with AArch64, including having the carryFlagToValue do the inversion.

Revert "[ARM] Custom Lowering for SADDO_CARRY an SSUBO_CARRY"
---
 llvm/lib/Target/ARM/ARMISelLowering.cpp | 124 ++++++++++++------------
 llvm/test/CodeGen/ARM/sadd_sat.ll       | 107 ++++++++++----------
 llvm/test/CodeGen/ARM/sadd_sat_plus.ll  |  75 ++++++--------
 llvm/test/CodeGen/ARM/ssub_sat.ll       |  62 ++++++------
 llvm/test/CodeGen/ARM/ssub_sat_plus.ll  |  68 ++++++-------
 5 files changed, 198 insertions(+), 238 deletions(-)

diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 830156359e9e8..003887189bb47 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -988,6 +988,8 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM_,
 
   setOperationAction(ISD::UADDO_CARRY, MVT::i32, Custom);
   setOperationAction(ISD::USUBO_CARRY, MVT::i32, Custom);
+  setOperationAction(ISD::SADDO_CARRY, MVT::i32, Custom);
+  setOperationAction(ISD::SSUBO_CARRY, MVT::i32, Custom);
   if (Subtarget->hasDSP()) {
     setOperationAction(ISD::SADDSAT, MVT::i8, Custom);
     setOperationAction(ISD::SSUBSAT, MVT::i8, Custom);
@@ -4923,23 +4925,31 @@ ARMTargetLowering::LowerSignedALUO(SDValue Op, SelectionDAG &DAG) const {
   return DAG.getNode(ISD::MERGE_VALUES, dl, VTs, Value, Overflow);
 }
 
-static SDValue ConvertBooleanCarryToCarryFlag(SDValue BoolCarry,
-                                              SelectionDAG &DAG) {
-  SDLoc DL(BoolCarry);
-  EVT CarryVT = BoolCarry.getValueType();
+static SDValue valueToCarryFlag(SDValue Value, SelectionDAG &DAG, bool Invert) {
+  SDLoc DL(Value);
+  EVT VT = Value.getValueType();
+
+  if (Invert)
+    Value = DAG.getNode(ISD::SUB, DL, MVT::i32,
+                        DAG.getConstant(1, DL, MVT::i32), Value);
 
-  // This converts the boolean value carry into the carry flag by doing
-  // ARMISD::SUBC Carry, 1
-  SDValue Carry = DAG.getNode(ARMISD::SUBC, DL,
-                              DAG.getVTList(CarryVT, MVT::i32),
-                              BoolCarry, DAG.getConstant(1, DL, CarryVT));
-  return Carry.getValue(1);
+  SDValue Cmp = DAG.getNode(ARMISD::SUBC, DL, DAG.getVTList(VT, MVT::i32),
+                            Value, DAG.getConstant(1, DL, VT));
+  return Cmp.getValue(1);
 }
 
-static SDValue ConvertCarryFlagToBooleanCarry(SDValue Flags, EVT VT,
-                                              SelectionDAG &DAG) {
+static SDValue carryFlagToValue(SDValue Flags, EVT VT, SelectionDAG &DAG,
+                                bool Invert) {
   SDLoc DL(Flags);
 
+  if (Invert) {
+    // Convert flags to boolean with ADDE 0,0,Carry then compute 1 - bool.
+    SDValue BoolCarry = DAG.getNode(
+        ARMISD::ADDE, DL, DAG.getVTList(VT, MVT::i32),
+        DAG.getConstant(0, DL, VT), DAG.getConstant(0, DL, VT), Flags);
+    return DAG.getNode(ISD::SUB, DL, VT, DAG.getConstant(1, DL, VT), BoolCarry);
+  }
+
   // Now convert the carry flag into a boolean carry. We do this
   // using ARMISD:ADDE 0, 0, Carry
   return DAG.getNode(ARMISD::ADDE, DL, DAG.getVTList(VT, MVT::i32),
@@ -4947,6 +4957,15 @@ static SDValue ConvertCarryFlagToBooleanCarry(SDValue Flags, EVT VT,
                      DAG.getConstant(0, DL, MVT::i32), Flags);
 }
 
+// Value is 1 if 'V' bit is 1, else 0
+static SDValue overflowFlagToValue(SDValue Flags, EVT VT, SelectionDAG &DAG) {
+  SDLoc DL(Flags);
+  SDValue Zero = DAG.getConstant(0, DL, VT);
+  SDValue One = DAG.getConstant(1, DL, VT);
+  SDValue ARMcc = DAG.getConstant(ARMCC::VS, DL, MVT::i32);
+  return DAG.getNode(ARMISD::CMOV, DL, VT, Zero, One, ARMcc, Flags);
+}
+
 SDValue ARMTargetLowering::LowerUnsignedALUO(SDValue Op,
                                              SelectionDAG &DAG) const {
   // Let legalize expand this if it isn't a legal type yet.
@@ -4967,16 +4986,12 @@ SDValue ARMTargetLowering::LowerUnsignedALUO(SDValue Op,
   case ISD::UADDO:
     Value = DAG.getNode(ARMISD::ADDC, dl, VTs, LHS, RHS);
     // Convert the carry flag into a boolean value.
-    Overflow = ConvertCarryFlagToBooleanCarry(Value.getValue(1), VT, DAG);
+    Overflow = carryFlagToValue(Value.getValue(1), VT, DAG, false);
     break;
   case ISD::USUBO: {
     Value = DAG.getNode(ARMISD::SUBC, dl, VTs, LHS, RHS);
     // Convert the carry flag into a boolean value.
-    Overflow = ConvertCarryFlagToBooleanCarry(Value.getValue(1), VT, DAG);
-    // ARMISD::SUBC returns 0 when we have to borrow, so make it an overflow
-    // value. So compute 1 - C.
-    Overflow = DAG.getNode(ISD::SUB, dl, MVT::i32,
-                           DAG.getConstant(1, dl, MVT::i32), Overflow);
+    Overflow = carryFlagToValue(Value.getValue(1), VT, DAG, true);
     break;
   }
   }
@@ -6859,21 +6874,19 @@ static SDValue LowerVSETCC(SDValue Op, SelectionDAG &DAG,
 static SDValue LowerSETCCCARRY(SDValue Op, SelectionDAG &DAG) {
   SDValue LHS = Op.getOperand(0);
   SDValue RHS = Op.getOperand(1);
+
+  assert(LHS.getSimpleValueType().isInteger() && "SETCCCARRY is integer only.");
+
   SDValue Carry = Op.getOperand(2);
   SDValue Cond = Op.getOperand(3);
   SDLoc DL(Op);
 
-  assert(LHS.getSimpleValueType().isInteger() && "SETCCCARRY is integer only.");
-
   // ARMISD::SUBE expects a carry not a borrow like ISD::USUBO_CARRY so we
   // have to invert the carry first.
-  Carry = DAG.getNode(ISD::SUB, DL, MVT::i32,
-                      DAG.getConstant(1, DL, MVT::i32), Carry);
-  // This converts the boolean value carry into the carry flag.
-  Carry = ConvertBooleanCarryToCarryFlag(Carry, DAG);
+  SDValue InvCarry = valueToCarryFlag(Carry, DAG, true);
 
   SDVTList VTs = DAG.getVTList(LHS.getValueType(), MVT::i32);
-  SDValue Cmp = DAG.getNode(ARMISD::SUBE, DL, VTs, LHS, RHS, Carry);
+  SDValue Cmp = DAG.getNode(ARMISD::SUBE, DL, VTs, LHS, RHS, InvCarry);
 
   SDValue FVal = DAG.getConstant(0, DL, MVT::i32);
   SDValue TVal = DAG.getConstant(1, DL, MVT::i32);
@@ -9766,48 +9779,26 @@ static SDValue LowerUDIV(SDValue Op, SelectionDAG &DAG,
   return N0;
 }
 
-static SDValue LowerUADDSUBO_CARRY(SDValue Op, SelectionDAG &DAG) {
-  SDNode *N = Op.getNode();
-  EVT VT = N->getValueType(0);
-  SDVTList VTs = DAG.getVTList(VT, MVT::i32);
+static SDValue LowerADDSUBO_CARRY(SDValue Op, SelectionDAG &DAG,
+                                  unsigned Opcode, bool IsSigned) {
+  EVT VT0 = Op.getValue(0).getValueType();
+  EVT VT1 = Op.getValue(1).getValueType();
 
-  SDValue Carry = Op.getOperand(2);
+  bool InvertCarry = Opcode == ARMISD::SUBE;
+  SDValue OpLHS = Op.getOperand(0);
+  SDValue OpRHS = Op.getOperand(1);
+  SDValue OpCarryIn = valueToCarryFlag(Op.getOperand(2), DAG, InvertCarry);
 
   SDLoc DL(Op);
 
-  SDValue Result;
-  if (Op.getOpcode() == ISD::UADDO_CARRY) {
-    // This converts the boolean value carry into the carry flag.
-    Carry = ConvertBooleanCarryToCarryFlag(Carry, DAG);
-
-    // Do the addition proper using the carry flag we wanted.
-    Result = DAG.getNode(ARMISD::ADDE, DL, VTs, Op.getOperand(0),
-                         Op.getOperand(1), Carry);
-
-    // Now convert the carry flag into a boolean value.
-    Carry = ConvertCarryFlagToBooleanCarry(Result.getValue(1), VT, DAG);
-  } else {
-    // ARMISD::SUBE expects a carry not a borrow like ISD::USUBO_CARRY so we
-    // have to invert the carry first.
-    Carry = DAG.getNode(ISD::SUB, DL, MVT::i32,
-                        DAG.getConstant(1, DL, MVT::i32), Carry);
-    // This converts the boolean value carry into the carry flag.
-    Carry = ConvertBooleanCarryToCarryFlag(Carry, DAG);
-
-    // Do the subtraction proper using the carry flag we wanted.
-    Result = DAG.getNode(ARMISD::SUBE, DL, VTs, Op.getOperand(0),
-                         Op.getOperand(1), Carry);
+  SDValue Sum = DAG.getNode(Opcode, DL, DAG.getVTList(VT0, MVT::i32), OpLHS,
+                            OpRHS, OpCarryIn);
 
-    // Now convert the carry flag into a boolean value.
-    Carry = ConvertCarryFlagToBooleanCarry(Result.getValue(1), VT, DAG);
-    // But the carry returned by ARMISD::SUBE is not a borrow as expected
-    // by ISD::USUBO_CARRY, so compute 1 - C.
-    Carry = DAG.getNode(ISD::SUB, DL, MVT::i32,
-                        DAG.getConstant(1, DL, MVT::i32), Carry);
-  }
+  SDValue OutFlag =
+      IsSigned ? overflowFlagToValue(Sum.getValue(1), VT1, DAG)
+               : carryFlagToValue(Sum.getValue(1), VT1, DAG, InvertCarry);
 
-  // Return both values.
-  return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Result, Carry);
+  return DAG.getMergeValues({Sum, OutFlag}, DL);
 }
 
 SDValue ARMTargetLowering::LowerFSINCOS(SDValue Op, SelectionDAG &DAG) const {
@@ -10651,8 +10642,13 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
       return LowerDIV_Windows(Op, DAG, /* Signed */ false);
     return LowerUDIV(Op, DAG, Subtarget);
   case ISD::UADDO_CARRY:
+    return LowerADDSUBO_CARRY(Op, DAG, ARMISD::ADDE, false /*unsigned*/);
   case ISD::USUBO_CARRY:
-    return LowerUADDSUBO_CARRY(Op, DAG);
+    return LowerADDSUBO_CARRY(Op, DAG, ARMISD::SUBE, false /*unsigned*/);
+  case ISD::SADDO_CARRY:
+    return LowerADDSUBO_CARRY(Op, DAG, ARMISD::ADDE, true /*signed*/);
+  case ISD::SSUBO_CARRY:
+    return LowerADDSUBO_CARRY(Op, DAG, ARMISD::SUBE, true /*signed*/);
   case ISD::SADDO:
   case ISD::SSUBO:
     return LowerSignedALUO(Op, DAG);
@@ -13198,9 +13194,9 @@ static SDValue PerformAddeSubeCombine(SDNode *N,
                                       TargetLowering::DAGCombinerInfo &DCI,
                                       const ARMSubtarget *Subtarget) {
   if (Subtarget->isThumb1Only()) {
-    SelectionDAG &DAG = DCI.DAG;
     SDValue RHS = N->getOperand(1);
     if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
+      SelectionDAG &DAG = DCI.DAG;
       int64_t imm = C->getSExtValue();
       if (imm < 0) {
         SDLoc DL(N);
@@ -18504,7 +18500,7 @@ ARMTargetLowering::PerformCMOVCombine(SDNode *N, SelectionDAG &DAG) const {
         SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS);
         SDVTList VTs = DAG.getVTList(VT, MVT::i32);
         SDValue Neg = DAG.getNode(ISD::USUBO, dl, VTs, FalseVal, Sub);
-        // ISD::USUBO_CARRY returns a borrow but we want the carry here
+        // ISD::USUBO returns a borrow but we want the carry here
         // actually.
         SDValue Carry =
             DAG.getNode(ISD::SUB, dl, MVT::i32,
diff --git a/llvm/test/CodeGen/ARM/sadd_sat.ll b/llvm/test/CodeGen/ARM/sadd_sat.ll
index b8f7a2daaeaba..f0366fe459abb 100644
--- a/llvm/test/CodeGen/ARM/sadd_sat.ll
+++ b/llvm/test/CodeGen/ARM/sadd_sat.ll
@@ -64,86 +64,81 @@ define i32 @func(i32 %x, i32 %y) nounwind {
 define i64 @func2(i64 %x, i64 %y) nounwind {
 ; CHECK-T16-LABEL: func2:
 ; CHECK-T16:       @ %bb.0:
-; CHECK-T16-NEXT:    .save {r4, lr}
-; CHECK-T16-NEXT:    push {r4, lr}
-; CHECK-T16-NEXT:    mov r4, r1
-; CHECK-T16-NEXT:    eors r1, r3
-; CHECK-T16-NEXT:    adds r2, r0, r2
-; CHECK-T16-NEXT:    adcs r3, r4
-; CHECK-T16-NEXT:    eors r4, r3
-; CHECK-T16-NEXT:    bics r4, r1
-; CHECK-T16-NEXT:    asrs r0, r3, #31
-; CHECK-T16-NEXT:    movs r1, #1
-; CHECK-T16-NEXT:    lsls r1, r1, #31
-; CHECK-T16-NEXT:    eors r1, r0
-; CHECK-T16-NEXT:    cmp r4, #0
-; CHECK-T16-NEXT:    bpl .LBB1_3
+; CHECK-T16-NEXT:    .save {r4, r5, r7, lr}
+; CHECK-T16-NEXT:    push {r4, r5, r7, lr}
+; CHECK-T16-NEXT:    mov r5, r0
+; CHECK-T16-NEXT:    adds r0, r0, r2
+; CHECK-T16-NEXT:    mov r0, r1
+; CHECK-T16-NEXT:    adcs r0, r3
+; CHECK-T16-NEXT:    asrs r0, r0, #31
+; CHECK-T16-NEXT:    movs r4, #1
+; CHECK-T16-NEXT:    lsls r4, r4, #31
+; CHECK-T16-NEXT:    eors r4, r0
+; CHECK-T16-NEXT:    adds r2, r5, r2
+; CHECK-T16-NEXT:    adcs r1, r3
+; CHECK-T16-NEXT:    bvc .LBB1_3
 ; CHECK-T16-NEXT:  @ %bb.1:
-; CHECK-T16-NEXT:    bpl .LBB1_4
+; CHECK-T16-NEXT:    bvc .LBB1_4
 ; CHECK-T16-NEXT:  .LBB1_2:
-; CHECK-T16-NEXT:    pop {r4, pc}
+; CHECK-T16-NEXT:    mov r1, r4
+; CHECK-T16-NEXT:    pop {r4, r5, r7, pc}
 ; CHECK-T16-NEXT:  .LBB1_3:
 ; CHECK-T16-NEXT:    mov r0, r2
-; CHECK-T16-NEXT:    bmi .LBB1_2
+; CHECK-T16-NEXT:    bvs .LBB1_2
 ; CHECK-T16-NEXT:  .LBB1_4:
-; CHECK-T16-NEXT:    mov r1, r3
-; CHECK-T16-NEXT:    pop {r4, pc}
+; CHECK-T16-NEXT:    mov r4, r1
+; CHECK-T16-NEXT:    mov r1, r4
+; CHECK-T16-NEXT:    pop {r4, r5, r7, pc}
 ;
 ; CHECK-T2-LABEL: func2:
 ; CHECK-T2:       @ %bb.0:
 ; CHECK-T2-NEXT:    adds r0, r0, r2
-; CHECK-T2-NEXT:    eor.w r12, r1, r3
-; CHECK-T2-NEXT:    adc.w r2, r1, r3
-; CHECK-T2-NEXT:    eors r1, r2
-; CHECK-T2-NEXT:    bics.w r1, r1, r12
-; CHECK-T2-NEXT:    it mi
-; CHECK-T2-NEXT:    asrmi r0, r2, #31
-; CHECK-T2-NEXT:    mov.w r1, #-2147483648
-; CHECK-T2-NEXT:    it mi
-; CHECK-T2-NEXT:    eormi.w r2, r1, r2, asr #31
-; CHECK-T2-NEXT:    mov r1, r2
+; CHECK-T2-NEXT:    mov.w r2, #-2147483648
+; CHECK-T2-NEXT:    adcs r1, r3
+; CHECK-T2-NEXT:    it vs
+; CHECK-T2-NEXT:    asrvs r0, r1, #31
+; CHECK-T2-NEXT:    it vs
+; CHECK-T2-NEXT:    eorvs.w r1, r2, r1, asr #31
 ; CHECK-T2-NEXT:    bx lr
 ;
 ; CHECK-ARM-LABEL: func2:
 ; CHECK-ARM:       @ %bb.0:
 ; CHECK-ARM-NEXT:    adds r0, r0, r2
-; CHECK-ARM-NEXT:    eor r12, r1, r3
-; CHECK-ARM-NEXT:    adc r2, r1, r3
-; CHECK-ARM-NEXT:    eor r1, r1, r2
-; CHECK-ARM-NEXT:    bics r1, r1, r12
-; CHECK-ARM-NEXT:    asrmi r0, r2, #31
-; CHECK-ARM-NEXT:    mov r1, #-2147483648
-; CHECK-ARM-NEXT:    eormi r2, r1, r2, asr #31
-; CHECK-ARM-NEXT:    mov r1, r2
+; CHECK-ARM-NEXT:    mov r2, #-2147483648
+; CHECK-ARM-NEXT:    adcs r1, r1, r3
+; CHECK-ARM-NEXT:    asrvs r0, r1, #31
+; CHECK-ARM-NEXT:    eorvs r1, r2, r1, asr #31
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-T15TE-LABEL: func2:
 ; CHECK-T15TE:       @ %bb.0:
-; CHECK-T15TE-NEXT:    .save {r4, lr}
-; CHECK-T15TE-NEXT:    push {r4, lr}
-; CHECK-T15TE-NEXT:    movs r4, r1
-; CHECK-T15TE-NEXT:    eors r1, r3
-; CHECK-T15TE-NEXT:    adds r2, r0, r2
-; CHECK-T15TE-NEXT:    adcs r3, r4
-; CHECK-T15TE-NEXT:    eors r4, r3
-; CHECK-T15TE-NEXT:    bics r4, r1
-; CHECK-T15TE-NEXT:    asrs r0, r3, #31
-; CHECK-T15TE-NEXT:    movs r1, #1
-; CHECK-T15TE-NEXT:    lsls r1, r1, #31
-; CHECK-T15TE-NEXT:    eors r1, r0
-; CHECK-T15TE-NEXT:    cmp r4, #0
-; CHECK-T15TE-NEXT:    bpl .LBB1_3
+; CHECK-T15TE-NEXT:    .save {r4, r5, r7, lr}
+; CHECK-T15TE-NEXT:    push {r4, r5, r7, lr}
+; CHECK-T15TE-NEXT:    movs r5, r0
+; CHECK-T15TE-NEXT:    adds r0, r0, r2
+; CHECK-T15TE-NEXT:    mov r12, r1
+; CHECK-T15TE-NEXT:    mov r0, r12
+; CHECK-T15TE-NEXT:    adcs r0, r3
+; CHECK-T15TE-NEXT:    asrs r0, r0, #31
+; CHECK-T15TE-NEXT:    movs r4, #1
+; CHECK-T15TE-NEXT:    lsls r4, r4, #31
+; CHECK-T15TE-NEXT:    eors r4, r0
+; CHECK-T15TE-NEXT:    adds r2, r5, r2
+; CHECK-T15TE-NEXT:    adcs r1, r3
+; CHECK-T15TE-NEXT:    bvc .LBB1_3
 ; CHECK-T15TE-NEXT:  @ %bb.1:
-; CHECK-T15TE-NEXT:    bpl .LBB1_4
+; CHECK-T15TE-NEXT:    bvc .LBB1_4
 ; CHECK-T15TE-NEXT:  .LBB1_2:
-; CHECK-T15TE-NEXT:    pop {r4, pc}
+; CHECK-T15TE-NEXT:    movs r1, r4
+; CHECK-T15TE-NEXT:    pop {r4, r5, r7, pc}
 ; CHECK-T15TE-NEXT:  .LBB1_3:
 ; CHECK-T15TE-NEXT:    mov r12, r2
 ; CHECK-T15TE-NEXT:    mov r0, r12
-; CHECK-T15TE-NEXT:    bmi .LBB1_2
+; CHECK-T15TE-NEXT:    bvs .LBB1_2
 ; CHECK-T15TE-NEXT:  .LBB1_4:
-; CHECK-T15TE-NEXT:    movs r1, r3
-; CHECK-T15TE-NEXT:    pop {r4, pc}
+; CHECK-T15TE-NEXT:    movs r4, r1
+; CHECK-T15TE-NEXT:    movs r1, r4
+; CHECK-T15TE-NEXT:    pop {r4, r5, r7, pc}
   %tmp = call i64 @llvm.sadd.sat.i64(i64 %x, i64 %y)
   ret i64 %tmp
 }
diff --git a/llvm/test/CodeGen/ARM/sadd_sat_plus.ll b/llvm/test/CodeGen/ARM/sadd_sat_plus.ll
index 0ddb64fc3f2d1..d54c97cca9eb0 100644
--- a/llvm/test/CodeGen/ARM/sadd_sat_plus.ll
+++ b/llvm/test/CodeGen/ARM/sadd_sat_plus.ll
@@ -53,65 +53,54 @@ define i32 @func32(i32 %x, i32 %y, i32 %z) nounwind {
 define i64 @func64(i64 %x, i64 %y, i64 %z) nounwind {
 ; CHECK-T1-LABEL: func64:
 ; CHECK-T1:       @ %bb.0:
-; CHECK-T1-NEXT:    .save {r4, lr}
-; CHECK-T1-NEXT:    push {r4, lr}
-; CHECK-T1-NEXT:    ldr r3, [sp, #12]
-; CHECK-T1-NEXT:    mov r2, r1
-; CHECK-T1-NEXT:    eors r2, r3
-; CHECK-T1-NEXT:    ldr r4, [sp, #8]
-; CHECK-T1-NEXT:    adds r4, r0, r4
-; CHECK-T1-NEXT:    adcs r3, r1
-; CHECK-T1-NEXT:    eors r1, r3
-; CHECK-T1-NEXT:    bics r1, r2
-; CHECK-T1-NEXT:    asrs r0, r3, #31
+; CHECK-T1-NEXT:    .save {r4, r5, r7, lr}
+; CHECK-T1-NEXT:    push {r4, r5, r7, lr}
+; CHECK-T1-NEXT:    mov r3, r0
+; CHECK-T1-NEXT:    ldr r4, [sp, #20]
+; CHECK-T1-NEXT:    ldr r5, [sp, #16]
+; CHECK-T1-NEXT:    adds r0, r0, r5
+; CHECK-T1-NEXT:    mov r0, r1
+; CHECK-T1-NEXT:    adcs r0, r4
+; CHECK-T1-NEXT:    asrs r0, r0, #31
 ; CHECK-T1-NEXT:    movs r2, #1
 ; CHECK-T1-NEXT:    lsls r2, r2, #31
 ; CHECK-T1-NEXT:    eors r2, r0
-; CHECK-T1-NEXT:    cmp r1, #0
-; CHECK-T1-NEXT:    bpl .LBB1_3
+; CHECK-T1-NEXT:    adds r3, r3, r5
+; CHECK-T1-NEXT:    adcs r1, r4
+; CHECK-T1-NEXT:    bvc .LBB1_3
 ; CHECK-T1-NEXT:  @ %bb.1:
-; CHECK-T1-NEXT:    bpl .LBB1_4
+; CHECK-T1-NEXT:    bvc .LBB1_4
 ; CHECK-T1-NEXT:  .LBB1_2:
 ; CHECK-T1-NEXT:    mov r1, r2
-; CHECK-T1-NEXT:    pop {r4, pc}
+; CHECK-T1-NEXT:    pop {r4, r5, r7, pc}
 ; CHECK-T1-NEXT:  .LBB1_3:
-; CHECK-T1-NEXT:    mov r0, r4
-; CHECK-T1-NEXT:    bmi .LBB1_2
+; CHECK-T1-NEXT:    mov r0, r3
+; CHECK-T1-NEXT:    bvs .LBB1_2
 ; CHECK-T1-NEXT:  .LBB1_4:
-; CHECK-T1-NEXT:    mov r2, r3
+; CHECK-T1-NEXT:    mov r2, r1
 ; CHECK-T1-NEXT:    mov r1, r2
-; CHECK-T1-NEXT:    pop {r4, pc}
+; CHECK-T1-NEXT:    pop {r4, r5, r7, pc}
 ;
 ; CHECK-T2-LABEL: func64:
 ; CHECK-T2:       @ %bb.0:
-; CHECK-T2-NEXT:    ldr r2, [sp]
-; CHECK-T2-NEXT:    ldr.w r12, [sp, #4]
-; CHECK-T2-NEXT:    adds r0, r0, r2
-; CHECK-T2-NEXT:    adc.w r2, r1, r12
-; CHECK-T2-NEXT:    eor.w r3, r1, r12
-; CHECK-T2-NEXT:    eors r1, r2
-; CHECK-T2-NEXT:    bics r1, r3
-; CHECK-T2-NEXT:    it mi
-; CHECK-T2-NEXT:    asrmi r0, r2, #31
-; CHECK-T2-NEXT:    mov.w r1, #-2147483648
-; CHECK-T2-NEXT:    it mi
-; CHECK-T2-NEXT:    eormi.w r2, r1, r2, asr #31
-; CHECK-T2-NEXT:    mov r1, r2
+; CHECK-T2-NEXT:    ldrd r3, r2, [sp]
+; CHECK-T2-NEXT:    adds r0, r0, r3
+; CHECK-T2-NEXT:    adcs r1, r2
+; CHECK-T2-NEXT:    it vs
+; CHECK-T2-NEXT:    asrvs r0, r1, #31
+; CHECK-T2-NEXT:    mov.w r2, #-2147483648
+; CHECK-T2-NEXT:    it vs
+; CHECK-T2-NEXT:    eorvs.w r1, r2, r1, asr #31
 ; CHECK-T2-NEXT:    bx lr
 ;
 ; CHECK-ARM-LABEL: func64:
 ; CHECK-ARM:       @ %bb.0:
-; CHECK-ARM-NEXT:    ldr r12, [sp]
-; CHECK-ARM-NEXT:    ldr r2, [sp, #4]
-; CHECK-ARM-NEXT:    adds r0, r0, r12
-; CHECK-ARM-NEXT:    eor r3, r1, r2
-; CHECK-ARM-NEXT:    adc r2, r1, r2
-; CHECK-ARM-NEXT:    eor r1, r1, r2
-; CHECK-ARM-NEXT:    bics r1, r1, r3
-; CHECK-ARM-NEXT:    asrmi r0, r2, #31
-; CHECK-ARM-NEXT:    mov r1, #-2147483648
-; CHECK-ARM-NEXT:    eormi r2, r1, r2, asr #31
-; CHECK-ARM-NEXT:    mov r1, r2
+; CHECK-ARM-NEXT:    ldm sp, {r2, r3}
+; CHECK-ARM-NEXT:    adds r0, r0, r2
+; CHECK-ARM-NEXT:    mov r2, #-2147483648
+; CHECK-ARM-NEXT:    adcs r1, r1, r3
+; CHECK-ARM-NEXT:    asrvs r0, r1, #31
+; CHECK-ARM-NEXT:    eorvs r1, r2, r1, asr #31
 ; CHECK-ARM-NEXT:    bx lr
   %a = mul i64 %y, %z
   %tmp = call i64 @llvm.sadd.sat.i64(i64 %x, i64 %z)
diff --git a/llvm/test/CodeGen/ARM/ssub_sat.ll b/llvm/test/CodeGen/ARM/ssub_sat.ll
index 0978bfd1f0140..8cce3a76a50db 100644
--- a/llvm/test/CodeGen/ARM/ssub_sat.ll
+++ b/llvm/test/CodeGen/ARM/ssub_sat.ll
@@ -64,56 +64,48 @@ define i64 @func2(i64 %x, i64 %y) nounwind {
 ; CHECK-T1:       @ %bb.0:
 ; CHECK-T1-NEXT:    .save {r4, r5, r7, lr}
 ; CHECK-T1-NEXT:    push {r4, r5, r7, lr}
-; CHECK-T1-NEXT:    mov r4, r1
-; CHECK-T1-NEXT:    eors r1, r3
-; CHECK-T1-NEXT:    subs r5, r0, r2
-; CHECK-T1-NEXT:    mov r2, r4
-; CHECK-T1-NEXT:    sbcs r2, r3
-; CHECK-T1-NEXT:    eors r4, r2
-; CHECK-T1-NEXT:    ands r4, r1
-; CHECK-T1-NEXT:    asrs r0, r2, #31
-; CHECK-T1-NEXT:    movs r1, #1
-; CHECK-T1-NEXT:    lsls r1, r1, #31
-; CHECK-T1-NEXT:    eors r1, r0
-; CHECK-T1-NEXT:    cmp r4, #0
-; CHECK-T1-NEXT:    bpl .LBB1_3
+; CHECK-T1-NEXT:    mov r5, r0
+; CHECK-T1-NEXT:    subs r0, r0, r2
+; CHECK-T1-NEXT:    mov r0, r1
+; CHECK-T1-NEXT:    sbcs r0, r3
+; CHECK-T1-NEXT:    asrs r0, r0, #31
+; CHECK-T1-NEXT:    movs r4, #1
+; CHECK-T1-NEXT:    lsls r4, r4, #31
+; CHECK-T1-NEXT:    eors r4, r0
+; CHECK-T1-NEXT:    subs r2, r5, r2
+; CHECK-T1-NEXT:    sbcs r1, r3
+; CHECK-T1-NEXT:    bvc .LBB1_3
 ; CHECK-T1-NEXT:  @ %bb.1:
-; CHECK-T1-NEXT:    bpl .LBB1_4
+; CHECK-T1-NEXT:    bvc .LBB1_4
 ; CHECK-T1-NEXT:  .LBB1_2:
+; CHECK-T1-NEXT:    mov r1, r4
 ; CHECK-T1-NEXT:    pop {r4, r5, r7, pc}
 ; CHECK-T1-NEXT:  .LBB1_3:
-; CHECK-T1-NEXT:    mov r0, r5
-; CHECK-T1-NEXT:    bmi .LBB1_2
+; CHECK-T1-NEXT:    mov r0, r2
+; CHECK-T1-NEXT:    bvs .LBB1_2
 ; CHECK-T1-NEXT:  .LBB1_4:
-; CHECK-T1-NEXT:    mov r1, r2
+; CHECK-T1-NEXT:    mov r4, r1
+; CHECK-T1-NEXT:    mov r1, r4
 ; CHECK-T1-NEXT:    pop {r4, r5, r7, pc}
 ;
 ; CHECK-T2-LABEL: func2:
 ; CHECK-T2:       @ %bb.0:
 ; CHECK-T2-NEXT:    subs r0, r0, r2
-; CHECK-T2-NEXT:    eor.w r12, r1, r3
-; CHECK-T2-NEXT:    sbc.w r2, r1, r3
-; CHECK-T2-NEXT:    eors r1, r2
-; CHECK-T2-NEXT:    ands.w r1, r1, r12
-; CHECK-T2-NEXT:    it mi
-; CHECK-T2-NEXT:    asrmi r0, r2, #31
-; CHECK-T2-NEXT:    mov.w r1, #-2147483648
-; CHECK-T2-NEXT:    it mi
-; CHECK-T2-NEXT:    eormi.w r2, r1, r2, asr #31
-; CHECK-T2-NEXT:    mov r1, r2
+; CHECK-T2-NEXT:    mov.w r2, #-2147483648
+; CHECK-T2-NEXT:    sbcs r1, r3
+; CHECK-T2-NEXT:    it vs
+; CHECK-T2-NEXT:    asrvs r0, r1, #31
+; CHECK-T2-NEXT:    it vs
+; CHECK-T2-NEXT:    eorvs.w r1, r2, r1, asr #31
 ; CHECK-T2-NEXT:    bx lr
 ;
 ; CHECK-ARM-LABEL: func2:
 ; CHECK-ARM:       @ %bb.0:
 ; CHECK-ARM-NEXT:    subs r0, r0, r2
-; CHECK-ARM-NEXT:    eor r12, r1, r3
-; CHECK-ARM-NEXT:    sbc r2, r1, r3
-; CHECK-ARM-NEXT:    eor r1, r1, r2
-; CHECK-ARM-NEXT:    ands r1, r12, r1
-; CHECK-ARM-NEXT:    asrmi r0, r2, #31
-; CHECK-ARM-NEXT:    mov r1, #-2147483648
-; CHECK-ARM-NEXT:    eormi r2, r1, r2, asr #31
-; CHECK-ARM-NEXT:    mov r1, r2
+; CHECK-ARM-NEXT:    mov r2, #-2147483648
+; CHECK-ARM-NEXT:    sbcs r1, r1, r3
+; CHECK-ARM-NEXT:    asrvs r0, r1, #31
+; CHECK-ARM-NEXT:    eorvs r1, r2, r1, asr #31
 ; CHECK-ARM-NEXT:    bx lr
   %tmp = call i64 @llvm.ssub.sat.i64(i64 %x, i64 %y)
   ret i64 %tmp
diff --git a/llvm/test/CodeGen/ARM/ssub_sat_plus.ll b/llvm/test/CodeGen/ARM/ssub_sat_plus.ll
index adf6cafc6ccb8..9690918d1f702 100644
--- a/llvm/test/CodeGen/ARM/ssub_sat_plus.ll
+++ b/llvm/test/CodeGen/ARM/ssub_sat_plus.ll
@@ -56,64 +56,52 @@ define i64 @func64(i64 %x, i64 %y, i64 %z) nounwind {
 ; CHECK-T1:       @ %bb.0:
 ; CHECK-T1-NEXT:    .save {r4, r5, r7, lr}
 ; CHECK-T1-NEXT:    push {r4, r5, r7, lr}
-; CHECK-T1-NEXT:    ldr r2, [sp, #20]
-; CHECK-T1-NEXT:    mov r5, r1
-; CHECK-T1-NEXT:    eors r5, r2
-; CHECK-T1-NEXT:    ldr r3, [sp, #16]
-; CHECK-T1-NEXT:    subs r4, r0, r3
-; CHECK-T1-NEXT:    mov r3, r1
-; CHECK-T1-NEXT:    sbcs r3, r2
-; CHECK-T1-NEXT:    eors r1, r3
-; CHECK-T1-NEXT:    ands r1, r5
-; CHECK-T1-NEXT:    asrs r0, r3, #31
+; CHECK-T1-NEXT:    mov r3, r0
+; CHECK-T1-NEXT:    ldr r4, [sp, #20]
+; CHECK-T1-NEXT:    ldr r5, [sp, #16]
+; CHECK-T1-NEXT:    subs r0, r0, r5
+; CHECK-T1-NEXT:    mov r0, r1
+; CHECK-T1-NEXT:    sbcs r0, r4
+; CHECK-T1-NEXT:    asrs r0, r0, #31
 ; CHECK-T1-NEXT:    movs r2, #1
 ; CHECK-T1-NEXT:    lsls r2, r2, #31
 ; CHECK-T1-NEXT:    eors r2, r0
-; CHECK-T1-NEXT:    cmp r1, #0
-; CHECK-T1-NEXT:    bpl .LBB1_3
+; CHECK-T1-NEXT:    subs r3, r3, r5
+; CHECK-T1-NEXT:    sbcs r1, r4
+; CHECK-T1-NEXT:    bvc .LBB1_3
 ; CHECK-T1-NEXT:  @ %bb.1:
-; CHECK-T1-NEXT:    bpl .LBB1_4
+; CHECK-T1-NEXT:    bvc .LBB1_4
 ; CHECK-T1-NEXT:  .LBB1_2:
 ; CHECK-T1-NEXT:    mov r1, r2
 ; CHECK-T1-NEXT:    pop {r4, r5, r7, pc}
 ; CHECK-T1-NEXT:  .LBB1_3:
-; CHECK-T1-NEXT:    mov r0, r4
-; CHECK-T1-NEXT:    bmi .LBB1_2
+; CHECK-T1-NEXT:    mov r0, r3
+; CHECK-T1-NEXT:    bvs .LBB1_2
 ; CHECK-T1-NEXT:  .LBB1_4:
-; CHECK-T1-NEXT:    mov r2, r3
+; CHECK-T1-NEXT:    mov r2, r1
 ; CHECK-T1-NEXT:    mov r1, r2
 ; CHECK-T1-NEXT:    pop {r4, r5, r7, pc}
 ;
 ; CHECK-T2-LABEL: func64:
 ; CHECK-T2:       @ %bb.0:
-; CHECK-T2-NEXT:    ldr r2, [sp]
-; CHECK-T2-NEXT:    ldr.w r12, [sp, #4]
-; CHECK-T2-NEXT:    subs r0, r0, r2
-; CHECK-T2-NEXT:    sbc.w r2, r1, r12
-; CHECK-T2-NEXT:    eor.w r3, r1, r12
-; CHECK-T2-NEXT:    eors r1, r2
-; CHECK-T2-NEXT:    ands r1, r3
-; CHECK-T2-NEXT:    it mi
-; CHECK-T2-NEXT:    asrmi r0, r2, #31
-; CHECK-T2-NEXT:    mov.w r1, #-2147483648
-; CHECK-T2-NEXT:    it mi
-; CHECK-T2-NEXT:    eormi.w r2, r1, r2, asr #31
-; CHECK-T2-NEXT:    mov r1, r2
+; CHECK-T2-NEXT:    ldrd r3, r2, [sp]
+; CHECK-T2-NEXT:    subs r0, r0, r3
+; CHECK-T2-NEXT:    sbcs r1, r2
+; CHECK-T2-NEXT:    it vs
+; CHECK-T2-NEXT:    asrvs r0, r1, #31
+; CHECK-T2-NEXT:    mov.w r2, #-2147483648
+; CHECK-T2-NEXT:    it vs
+; CHECK-T2-NEXT:    eorvs.w r1, r2, r1, asr #31
 ; CHECK-T2-NEXT:    bx lr
 ;
 ; CHECK-ARM-LABEL: func64:
 ; CHECK-ARM:       @ %bb.0:
-; CHECK-ARM-NEXT:    ldr r12, [sp]
-; CHECK-ARM-NEXT:    ldr r2, [sp, #4]
-; CHECK-ARM-NEXT:    subs r0, r0, r12
-; CHECK-ARM-NEXT:    eor r3, r1, r2
-; CHECK-ARM-NEXT:    sbc r2, r1, r2
-; CHECK-ARM-NEXT:    eor r1, r1, r2
-; CHECK-ARM-NEXT:    ands r1, r3, r1
-; CHECK-ARM-NEXT:    asrmi r0, r2, #31
-; CHECK-ARM-NEXT:    mov r1, #-2147483648
-; CHECK-ARM-NEXT:    eormi r2, r1, r2, asr #31
-; CHECK-ARM-NEXT:    mov r1, r2
+; CHECK-ARM-NEXT:    ldm sp, {r2, r3}
+; CHECK-ARM-NEXT:    subs r0, r0, r2
+; CHECK-ARM-NEXT:    mov r2, #-2147483648
+; CHECK-ARM-NEXT:    sbcs r1, r1, r3
+; CHECK-ARM-NEXT:    asrvs r0, r1, #31
+; CHECK-ARM-NEXT:    eorvs r1, r2, r1, asr #31
 ; CHECK-ARM-NEXT:    bx lr
   %a = mul i64 %y, %z
   %tmp = call i64 @llvm.ssub.sat.i64(i64 %x, i64 %z)



More information about the llvm-commits mailing list