Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 49 additions & 44 deletions llvm/lib/Target/ARM/ARMISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4832,59 +4832,47 @@ SDValue ARMTargetLowering::getVFPCmp(SDValue LHS, SDValue RHS,
}

// This function returns three things: the arithmetic computation itself
// (Value), a comparison (OverflowCmp), and a condition code (ARMcc). The
// (Value), a comparison (Overflow), and a condition code (ARMcc). The
// comparison and the condition code define the case in which the arithmetic
// computation *does not* overflow.
std::pair<SDValue, SDValue>
ARMTargetLowering::getARMXALUOOp(SDValue Op, SelectionDAG &DAG,
SDValue &ARMcc) const {
assert(Op.getValueType() == MVT::i32 && "Unsupported value type");

SDValue Value, OverflowCmp;
SDValue Value, Overflow;
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
SDLoc dl(Op);

// FIXME: We are currently always generating CMPs because we don't support
// generating CMN through the backend. This is not as good as the natural
// CMP case because it causes a register dependency and cannot be folded
// later.
unsigned Opc = 0;

switch (Op.getOpcode()) {
default:
llvm_unreachable("Unknown overflow instruction!");
case ISD::SADDO:
Opc = ARMISD::ADDC;
ARMcc = DAG.getConstant(ARMCC::VC, dl, MVT::i32);
Value = DAG.getNode(ISD::ADD, dl, Op.getValueType(), LHS, RHS);
OverflowCmp = DAG.getNode(ARMISD::CMP, dl, FlagsVT, Value, LHS);
break;
case ISD::UADDO:
ARMcc = DAG.getConstant(ARMCC::HS, dl, MVT::i32);
// We use ADDC here to correspond to its use in LowerUnsignedALUO.
// We do not use it in the USUBO case as Value may not be used.
Value = DAG.getNode(ARMISD::ADDC, dl,
DAG.getVTList(Op.getValueType(), MVT::i32), LHS, RHS)
.getValue(0);
OverflowCmp = DAG.getNode(ARMISD::CMP, dl, FlagsVT, Value, LHS);
Opc = ARMISD::ADDC;
ARMcc = DAG.getConstant(ARMCC::LO, dl, MVT::i32);
break;
case ISD::SSUBO:
Opc = ARMISD::SUBC;
ARMcc = DAG.getConstant(ARMCC::VC, dl, MVT::i32);
Value = DAG.getNode(ISD::SUB, dl, Op.getValueType(), LHS, RHS);
OverflowCmp = DAG.getNode(ARMISD::CMP, dl, FlagsVT, LHS, RHS);
break;
case ISD::USUBO:
Opc = ARMISD::SUBC;
ARMcc = DAG.getConstant(ARMCC::HS, dl, MVT::i32);
Value = DAG.getNode(ISD::SUB, dl, Op.getValueType(), LHS, RHS);
OverflowCmp = DAG.getNode(ARMISD::CMP, dl, FlagsVT, LHS, RHS);
break;
case ISD::UMULO:
// We generate a UMUL_LOHI and then check if the high word is 0.
ARMcc = DAG.getConstant(ARMCC::EQ, dl, MVT::i32);
Value = DAG.getNode(ISD::UMUL_LOHI, dl,
DAG.getVTList(Op.getValueType(), Op.getValueType()),
LHS, RHS);
OverflowCmp = DAG.getNode(ARMISD::CMP, dl, FlagsVT, Value.getValue(1),
DAG.getConstant(0, dl, MVT::i32));
Overflow = DAG.getNode(ARMISD::CMP, dl, FlagsVT, Value.getValue(1),
DAG.getConstant(0, dl, MVT::i32));
Value = Value.getValue(0); // We only want the low 32 bits for the result.
break;
case ISD::SMULO:
Expand All @@ -4894,15 +4882,34 @@ ARMTargetLowering::getARMXALUOOp(SDValue Op, SelectionDAG &DAG,
Value = DAG.getNode(ISD::SMUL_LOHI, dl,
DAG.getVTList(Op.getValueType(), Op.getValueType()),
LHS, RHS);
OverflowCmp = DAG.getNode(ARMISD::CMP, dl, FlagsVT, Value.getValue(1),
DAG.getNode(ISD::SRA, dl, Op.getValueType(),
Value.getValue(0),
DAG.getConstant(31, dl, MVT::i32)));
Overflow = DAG.getNode(ARMISD::CMP, dl, FlagsVT, Value.getValue(1),
DAG.getNode(ISD::SRA, dl, Op.getValueType(),
Value.getValue(0),
DAG.getConstant(31, dl, MVT::i32)));
Value = Value.getValue(0); // We only want the low 32 bits for the result.
break;
} // switch (...)
if (Opc) {
if (Subtarget->isThumb1Only() &&
(Op.getOpcode() == ISD::SADDO || Op.getOpcode() == ISD::SSUBO)) {
// FIXME: Thumb1 has to split between the cmp and the add/sub.
// Remove when the peephole optimizer handles this or we no longer need to
// split.
if (Opc == ARMISD::ADDC) {
Value = DAG.getNode(ISD::ADD, dl, Op.getValueType(), LHS, RHS);
Overflow = DAG.getNode(ARMISD::CMP, dl, FlagsVT, Value, LHS);
} else {
Value = DAG.getNode(ISD::SUB, dl, Op.getValueType(), LHS, RHS);
Overflow = DAG.getNode(ARMISD::CMP, dl, FlagsVT, LHS, RHS);
}
} else {
SDVTList VTs = DAG.getVTList(Op.getValueType(), FlagsVT);
Value = DAG.getNode(Opc, dl, VTs, LHS, RHS);
Overflow = Value.getValue(1);
}
}

return std::make_pair(Value, OverflowCmp);
return std::make_pair(Value, Overflow);
}

SDValue
Expand All @@ -4911,20 +4918,18 @@ ARMTargetLowering::LowerSignedALUO(SDValue Op, SelectionDAG &DAG) const {
if (!isTypeLegal(Op.getValueType()))
return SDValue();

SDValue Value, OverflowCmp;
SDValue ARMcc;
std::tie(Value, OverflowCmp) = getARMXALUOOp(Op, DAG, ARMcc);
SDLoc dl(Op);
SDValue Value, Overflow;
SDValue ARMcc;
std::tie(Value, Overflow) = getARMXALUOOp(Op, DAG, ARMcc);
// We use 0 and 1 as false and true values.
SDValue TVal = DAG.getConstant(1, dl, MVT::i32);
SDValue FVal = DAG.getConstant(0, dl, MVT::i32);
EVT VT = Op.getValueType();

SDValue Overflow =
DAG.getNode(ARMISD::CMOV, dl, VT, TVal, FVal, ARMcc, OverflowCmp);
Overflow =
DAG.getNode(ARMISD::CMOV, dl, MVT::i32, TVal, FVal, ARMcc, Overflow);

SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::i32);
return DAG.getNode(ISD::MERGE_VALUES, dl, VTs, Value, Overflow);
return DAG.getMergeValues({Value, Overflow}, dl);
}

static SDValue ConvertBooleanCarryToCarryFlag(SDValue BoolCarry,
Expand Down Expand Up @@ -5055,12 +5060,12 @@ SDValue ARMTargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
if (!isTypeLegal(Cond->getValueType(0)))
return SDValue();

SDValue Value, OverflowCmp;
SDValue Value, Overflow;
SDValue ARMcc;
std::tie(Value, OverflowCmp) = getARMXALUOOp(Cond, DAG, ARMcc);
std::tie(Value, Overflow) = getARMXALUOOp(Cond, DAG, ARMcc);
EVT VT = Op.getValueType();

return getCMOV(dl, VT, SelectTrue, SelectFalse, ARMcc, OverflowCmp, DAG);
return getCMOV(dl, VT, SelectTrue, SelectFalse, ARMcc, Overflow, DAG);
}

// Convert:
Expand Down Expand Up @@ -5657,9 +5662,9 @@ SDValue ARMTargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const {
return SDValue();

// The actual operation with overflow check.
SDValue Value, OverflowCmp;
SDValue Value, Overflow;
SDValue ARMcc;
std::tie(Value, OverflowCmp) = getARMXALUOOp(Cond, DAG, ARMcc);
std::tie(Value, Overflow) = getARMXALUOOp(Cond, DAG, ARMcc);

// Reverse the condition code.
ARMCC::CondCodes CondCode =
Expand All @@ -5668,7 +5673,7 @@ SDValue ARMTargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const {
ARMcc = DAG.getConstant(CondCode, SDLoc(ARMcc), MVT::i32);

return DAG.getNode(ARMISD::BRCOND, dl, MVT::Other, Chain, Dest, ARMcc,
OverflowCmp);
Overflow);
}

return SDValue();
Expand Down Expand Up @@ -5707,9 +5712,9 @@ SDValue ARMTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
return SDValue();

// The actual operation with overflow check.
SDValue Value, OverflowCmp;
SDValue Value, Overflow;
SDValue ARMcc;
std::tie(Value, OverflowCmp) = getARMXALUOOp(LHS.getValue(0), DAG, ARMcc);
std::tie(Value, Overflow) = getARMXALUOOp(LHS.getValue(0), DAG, ARMcc);

if ((CC == ISD::SETNE) != isOneConstant(RHS)) {
// Reverse the condition code.
Expand All @@ -5720,7 +5725,7 @@ SDValue ARMTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
}

return DAG.getNode(ARMISD::BRCOND, dl, MVT::Other, Chain, Dest, ARMcc,
OverflowCmp);
Overflow);
}

if (LHS.getValueType() == MVT::i32) {
Expand Down
12 changes: 4 additions & 8 deletions llvm/test/CodeGen/ARM/arm-shrink-wrapping-linux.ll
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,12 @@ define fastcc ptr @wrongUseOfPostDominate(ptr readonly %s, i32 %off, ptr readnon
; ENABLE-NEXT: .LBB0_4: @ %while.body
; ENABLE-NEXT: @ =>This Inner Loop Header: Depth=1
; ENABLE-NEXT: ldrb r3, [r0]
; ENABLE-NEXT: subs r1, r1, #1
; ENABLE-NEXT: ldrb r3, [r12, r3]
; ENABLE-NEXT: add r0, r0, r3
; ENABLE-NEXT: sub r3, r1, #1
; ENABLE-NEXT: cmp r3, r1
; ENABLE-NEXT: bhs .LBB0_6
; ENABLE-NEXT: blo .LBB0_6
; ENABLE-NEXT: @ %bb.5: @ %while.body
; ENABLE-NEXT: @ in Loop: Header=BB0_4 Depth=1
; ENABLE-NEXT: mov r1, r3
; ENABLE-NEXT: cmp r0, r2
; ENABLE-NEXT: blo .LBB0_4
; ENABLE-NEXT: .LBB0_6: @ %if.end29
Expand Down Expand Up @@ -124,14 +122,12 @@ define fastcc ptr @wrongUseOfPostDominate(ptr readonly %s, i32 %off, ptr readnon
; DISABLE-NEXT: .LBB0_4: @ %while.body
; DISABLE-NEXT: @ =>This Inner Loop Header: Depth=1
; DISABLE-NEXT: ldrb r3, [r0]
; DISABLE-NEXT: subs r1, r1, #1
; DISABLE-NEXT: ldrb r3, [r12, r3]
; DISABLE-NEXT: add r0, r0, r3
; DISABLE-NEXT: sub r3, r1, #1
; DISABLE-NEXT: cmp r3, r1
; DISABLE-NEXT: bhs .LBB0_6
; DISABLE-NEXT: blo .LBB0_6
; DISABLE-NEXT: @ %bb.5: @ %while.body
; DISABLE-NEXT: @ in Loop: Header=BB0_4 Depth=1
; DISABLE-NEXT: mov r1, r3
; DISABLE-NEXT: cmp r0, r2
; DISABLE-NEXT: blo .LBB0_4
; DISABLE-NEXT: .LBB0_6: @ %if.end29
Expand Down
Loading