summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/ARM
diff options
context:
space:
mode:
authorRoger Ferrer Ibanez <roger.ferreribanez@arm.com>2018-02-16 09:23:59 +0000
committerRoger Ferrer Ibanez <roger.ferreribanez@arm.com>2018-02-16 09:23:59 +0000
commitd41059a9f6d04d3314636f6da524ba74b3442f3b (patch)
tree8703db1755eb01d1909401ce4efe91baef9dc7bd /llvm/lib/Target/ARM
parent42a16192626c01b1cada04c51893f153f95c8698 (diff)
downloadbcm5719-llvm-d41059a9f6d04d3314636f6da524ba74b3442f3b.tar.gz
bcm5719-llvm-d41059a9f6d04d3314636f6da524ba74b3442f3b.zip
[ARM] Materialise some boolean values to avoid a branch
This patch combines some cases of ARMISD::CMOV for integers that arise in comparisons of the form a != b ? x : 0 a == b ? 0 : x and that currently (e.g. in Thumb1) are emitted as branches. Differential Revision: https://reviews.llvm.org/D34515 llvm-svn: 325323
Diffstat (limited to 'llvm/lib/Target/ARM')
-rw-r--r--llvm/lib/Target/ARM/ARMISelLowering.cpp99
1 files changed, 89 insertions, 10 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index c52b619a050..ed72b1d05d2 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -4044,11 +4044,10 @@ static SDValue ConvertBooleanCarryToCarryFlag(SDValue BoolCarry,
SDLoc DL(BoolCarry);
EVT CarryVT = BoolCarry.getValueType();
- APInt NegOne = APInt::getAllOnesValue(CarryVT.getScalarSizeInBits());
// This converts the boolean value carry into the carry flag by doing
- // ARMISD::ADDC Carry, ~0
- return DAG.getNode(ARMISD::ADDC, DL, DAG.getVTList(CarryVT, MVT::i32),
- BoolCarry, DAG.getConstant(NegOne, DL, CarryVT));
+ // ARMISD::SUBC Carry, 1
+ return DAG.getNode(ARMISD::SUBC, DL, DAG.getVTList(CarryVT, MVT::i32),
+ BoolCarry, DAG.getConstant(1, DL, CarryVT));
}
static SDValue ConvertCarryFlagToBooleanCarry(SDValue Flags, EVT VT,
@@ -7663,12 +7662,9 @@ static SDValue LowerADDSUBCARRY(SDValue Op, SelectionDAG &DAG) {
SDVTList VTs = DAG.getVTList(VT, MVT::i32);
SDValue Carry = Op.getOperand(2);
- EVT CarryVT = Carry.getValueType();
SDLoc DL(Op);
- APInt NegOne = APInt::getAllOnesValue(CarryVT.getScalarSizeInBits());
-
SDValue Result;
if (Op.getOpcode() == ISD::ADDCARRY) {
// This converts the boolean value carry into the carry flag.
@@ -10254,13 +10250,13 @@ static SDValue PerformAddcSubcCombine(SDNode *N,
const ARMSubtarget *Subtarget) {
SelectionDAG &DAG(DCI.DAG);
- if (N->getOpcode() == ARMISD::ADDC) {
- // (ADDC (ADDE 0, 0, C), -1) -> C
+ if (N->getOpcode() == ARMISD::SUBC) {
+ // (SUBC (ADDE 0, 0, C), 1) -> C
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
if (LHS->getOpcode() == ARMISD::ADDE &&
isNullConstant(LHS->getOperand(0)) &&
- isNullConstant(LHS->getOperand(1)) && isAllOnesConstant(RHS)) {
+ isNullConstant(LHS->getOperand(1)) && isOneConstant(RHS)) {
return DCI.CombineTo(N, SDValue(N, 0), LHS->getOperand(2));
}
}
@@ -12493,6 +12489,89 @@ ARMTargetLowering::PerformCMOVCombine(SDNode *N, SelectionDAG &DAG) const {
}
}
+ if (!VT.isInteger())
+ return SDValue();
+
+ // Materialize a boolean comparison for integers so we can avoid branching.
+ if (isNullConstant(FalseVal)) {
+ if (CC == ARMCC::EQ && isOneConstant(TrueVal)) {
+ if (!Subtarget->isThumb1Only() && Subtarget->hasV5TOps()) {
+ // If x == y then x - y == 0 and ARM's CLZ will return 32, shifting it
+ // right 5 bits will make that 32 be 1, otherwise it will be 0.
+ // CMOV 0, 1, ==, (CMPZ x, y) -> SRL (CTLZ (SUB x, y)), 5
+ SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS);
+ Res = DAG.getNode(ISD::SRL, dl, VT, DAG.getNode(ISD::CTLZ, dl, VT, Sub),
+ DAG.getConstant(5, dl, MVT::i32));
+ } else {
+ // CMOV 0, 1, ==, (CMPZ x, y) ->
+ // (ADDCARRY (SUB x, y), t:0, t:1)
+ // where t = (SUBCARRY 0, (SUB x, y), 0)
+ //
+ // The SUBCARRY computes 0 - (x - y) and this will give a borrow when
+ // x != y. In other words, a carry C == 1 when x == y, C == 0
+ // otherwise.
+ // The final ADDCARRY computes
+ // x - y + (0 - (x - y)) + C == C
+ 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::SUBCARRY returns a borrow but we want the carry here
+ // actually.
+ SDValue Carry =
+ DAG.getNode(ISD::SUB, dl, MVT::i32,
+ DAG.getConstant(1, dl, MVT::i32), Neg.getValue(1));
+ Res = DAG.getNode(ISD::ADDCARRY, dl, VTs, Sub, Neg, Carry);
+ }
+ } else if (CC == ARMCC::NE && LHS != RHS &&
+ (!Subtarget->isThumb1Only() || isPowerOf2Constant(TrueVal))) {
+ // This seems pointless but will allow us to combine it further below.
+ // CMOV 0, z, !=, (CMPZ x, y) -> CMOV (SUB x, y), z, !=, (CMPZ x, y)
+ SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS);
+ Res = DAG.getNode(ARMISD::CMOV, dl, VT, Sub, TrueVal, ARMcc,
+ N->getOperand(3), Cmp);
+ }
+ } else if (isNullConstant(TrueVal)) {
+ if (CC == ARMCC::EQ && LHS != RHS &&
+ (!Subtarget->isThumb1Only() || isPowerOf2Constant(FalseVal))) {
+ // This seems pointless but will allow us to combine it further below
+ // Note that we change == for != as this is the dual for the case above.
+ // CMOV z, 0, ==, (CMPZ x, y) -> CMOV (SUB x, y), z, !=, (CMPZ x, y)
+ SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS);
+ Res = DAG.getNode(ARMISD::CMOV, dl, VT, Sub, FalseVal,
+ DAG.getConstant(ARMCC::NE, dl, MVT::i32),
+ N->getOperand(3), Cmp);
+ }
+ }
+
+ // On Thumb1, the DAG above may be further combined if z is a power of 2
+ // (z == 2 ^ K).
+ // CMOV (SUB x, y), z, !=, (CMPZ x, y) ->
+ // merge t3, t4
+ // where t1 = (SUBCARRY (SUB x, y), z, 0)
+ // t2 = (SUBCARRY (SUB x, y), t1:0, t1:1)
+ // t3 = if K != 0 then (SHL t2:0, K) else t2:0
+ // t4 = (SUB 1, t2:1) [ we want a carry, not a borrow ]
+ const APInt *TrueConst;
+ if (Subtarget->isThumb1Only() && CC == ARMCC::NE &&
+ (FalseVal.getOpcode() == ISD::SUB) && (FalseVal.getOperand(0) == LHS) &&
+ (FalseVal.getOperand(1) == RHS) &&
+ (TrueConst = isPowerOf2Constant(TrueVal))) {
+ SDVTList VTs = DAG.getVTList(VT, MVT::i32);
+ unsigned ShiftAmount = TrueConst->logBase2();
+ if (ShiftAmount)
+ TrueVal = DAG.getConstant(1, dl, VT);
+ SDValue Subc = DAG.getNode(ISD::USUBO, dl, VTs, FalseVal, TrueVal);
+ Res = DAG.getNode(ISD::SUBCARRY, dl, VTs, FalseVal, Subc, Subc.getValue(1));
+ // Make it a carry, not a borrow.
+ SDValue Carry = DAG.getNode(
+ ISD::SUB, dl, VT, DAG.getConstant(1, dl, MVT::i32), Res.getValue(1));
+ Res = DAG.getNode(ISD::MERGE_VALUES, dl, VTs, Res, Carry);
+
+ if (ShiftAmount)
+ Res = DAG.getNode(ISD::SHL, dl, VT, Res,
+ DAG.getConstant(ShiftAmount, dl, MVT::i32));
+ }
+
if (Res.getNode()) {
KnownBits Known;
DAG.computeKnownBits(SDValue(N,0), Known);
OpenPOWER on IntegriCloud