[ARM] Custom Lowering for SADDO_CARRY and SSUBO_CARRY (#154419)
To do this, I did refactoring to mirror what goes on with AArch64, including having the carryFlagToValue do the inversion. While the patterns are not the best, with pattern matching, I hope to at make it as good as AArch64 on Thumb2 where we have CSEL.
This commit is contained in:
1 parent
ffea943c17
commit
e9113618cb
5 files changed
+199
-239
No files matched your search
@@ -960,6 +960,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);
|
||||
@@ -4721,28 +4723,45 @@ ARMTargetLowering::getARMXALUOOp(SDValue Op, SelectionDAG &DAG,
|
||||
return std::make_pair(Value, OverflowCmp);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// 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);
|
||||
if (Invert)
|
||||
Value = DAG.getNode(ISD::SUB, DL, MVT::i32,
|
||||
DAG.getConstant(1, DL, MVT::i32), Value);
|
||||
|
||||
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
|
||||
// using ARMISD::ADDE 0, 0, Carry
|
||||
return DAG.getNode(ARMISD::ADDE, DL, DAG.getVTList(VT, MVT::i32),
|
||||
DAG.getConstant(0, DL, MVT::i32),
|
||||
DAG.getConstant(0, DL, MVT::i32), Flags);
|
||||
DAG.getConstant(0, DL, VT), DAG.getConstant(0, DL, VT),
|
||||
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::LowerALUO(SDValue Op, SelectionDAG &DAG) const {
|
||||
@@ -4762,16 +4781,12 @@ SDValue ARMTargetLowering::LowerALUO(SDValue Op, SelectionDAG &DAG) const {
|
||||
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;
|
||||
default: {
|
||||
// Handle other operations with getARMXALUOOp
|
||||
@@ -6705,21 +6720,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);
|
||||
@@ -9612,48 +9625,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);
|
||||
SDValue Result = DAG.getNode(Opcode, DL, DAG.getVTList(VT0, MVT::i32), OpLHS,
|
||||
OpRHS, OpCarryIn);
|
||||
|
||||
// Do the addition proper using the carry flag we wanted.
|
||||
Result = DAG.getNode(ARMISD::ADDE, DL, VTs, Op.getOperand(0),
|
||||
Op.getOperand(1), Carry);
|
||||
SDValue OutFlag =
|
||||
IsSigned ? overflowFlagToValue(Result.getValue(1), VT1, DAG)
|
||||
: carryFlagToValue(Result.getValue(1), VT1, DAG, InvertCarry);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Return both values.
|
||||
return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Result, Carry);
|
||||
return DAG.getMergeValues({Result, OutFlag}, DL);
|
||||
}
|
||||
|
||||
SDValue ARMTargetLowering::LowerWindowsDIVLibCall(SDValue Op, SelectionDAG &DAG,
|
||||
@@ -10519,8 +10510,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::UADDO:
|
||||
case ISD::USUBO:
|
||||
case ISD::UMULO:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user