summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
authorDavid Green <david.green@arm.com>2019-09-03 10:53:07 +0000
committerDavid Green <david.green@arm.com>2019-09-03 10:53:07 +0000
commit57cc65ff47276d5584ce74d54539656943daef79 (patch)
treeffc8e0d30944baa1ec7858b8c31ec05f69cb5ea9 /llvm/lib/Target
parenta1ae7e373479187c00cfcfc6a8eabaf9e4370bcc (diff)
downloadbcm5719-llvm-57cc65ff47276d5584ce74d54539656943daef79.tar.gz
bcm5719-llvm-57cc65ff47276d5584ce74d54539656943daef79.zip
[ARM] Generate 8.1-m CSINC, CSNEG and CSINV instructions.
Arm 8.1-M adds a number of related CSEL instructions, including CSINC, CSNEG and CSINV. These choose between two values given the content in CPSR and a condition, performing an increment, negation or inverse of the false value. This adds some selection for them, either from constant values or patterns. It does not include CSEL directly, which is currently not always making code better. It is still useful, but we will have to check more carefully where it should and shouldn't be used. Code by Ranjeet Singh and Simon Tatham, with some modifications from me. Differential revision: https://reviews.llvm.org/D66483 llvm-svn: 370739
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r--llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp6
-rw-r--r--llvm/lib/Target/ARM/ARMISelLowering.cpp46
-rw-r--r--llvm/lib/Target/ARM/ARMISelLowering.h5
-rw-r--r--llvm/lib/Target/ARM/ARMInstrFormats.td7
-rw-r--r--llvm/lib/Target/ARM/ARMInstrInfo.td10
-rw-r--r--llvm/lib/Target/ARM/ARMInstrThumb2.td19
6 files changed, 92 insertions, 1 deletions
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 680729dd29b..54ddb946a2d 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -3040,18 +3040,22 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
break;
case ARM::VSELEQD:
case ARM::VSELEQS:
+ case ARM::VSELEQH:
CC = ARMCC::EQ;
break;
case ARM::VSELGTD:
case ARM::VSELGTS:
+ case ARM::VSELGTH:
CC = ARMCC::GT;
break;
case ARM::VSELGED:
case ARM::VSELGES:
+ case ARM::VSELGEH:
CC = ARMCC::GE;
break;
- case ARM::VSELVSS:
case ARM::VSELVSD:
+ case ARM::VSELVSS:
+ case ARM::VSELVSH:
CC = ARMCC::VS;
break;
}
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 8a4de79a218..0239d6af8ad 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -1634,6 +1634,9 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
case ARMISD::WLS: return "ARMISD::WLS";
case ARMISD::LE: return "ARMISD::LE";
case ARMISD::LOOP_DEC: return "ARMISD::LOOP_DEC";
+ case ARMISD::CSINV: return "ARMISD::CSINV";
+ case ARMISD::CSNEG: return "ARMISD::CSNEG";
+ case ARMISD::CSINC: return "ARMISD::CSINC";
}
return nullptr;
}
@@ -4815,6 +4818,49 @@ SDValue ARMTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
SDValue TrueVal = Op.getOperand(2);
SDValue FalseVal = Op.getOperand(3);
+ ConstantSDNode *CFVal = dyn_cast<ConstantSDNode>(FalseVal);
+ ConstantSDNode *CTVal = dyn_cast<ConstantSDNode>(TrueVal);
+
+ if (Subtarget->hasV8_1MMainlineOps() && CFVal && CTVal &&
+ LHS.getValueType() == MVT::i32 && RHS.getValueType() == MVT::i32) {
+ unsigned TVal = CTVal->getZExtValue();
+ unsigned FVal = CFVal->getZExtValue();
+ unsigned Opcode = 0;
+
+ if (TVal == ~FVal) {
+ Opcode = ARMISD::CSINV;
+ } else if (TVal == ~FVal + 1) {
+ Opcode = ARMISD::CSNEG;
+ } else if (TVal + 1 == FVal) {
+ Opcode = ARMISD::CSINC;
+ } else if (TVal == FVal + 1) {
+ Opcode = ARMISD::CSINC;
+ std::swap(TrueVal, FalseVal);
+ std::swap(TVal, FVal);
+ CC = ISD::getSetCCInverse(CC, true);
+ }
+
+ if (Opcode) {
+ // Attempt to use ZR checking TVal is 0, possibly inverting the condition
+ // to get there. CSINC not is invertable like the other two (~(~a) == a,
+ // -(-a) == a, but (a+1)+1 != a).
+ if (FVal == 0 && Opcode != ARMISD::CSINC) {
+ std::swap(TrueVal, FalseVal);
+ std::swap(TVal, FVal);
+ CC = ISD::getSetCCInverse(CC, true);
+ }
+ if (TVal == 0)
+ TrueVal = DAG.getRegister(ARM::ZR, MVT::i32);
+
+ // Drops F's value because we can get it by inverting/negating TVal.
+ FalseVal = TrueVal;
+
+ SDValue ARMcc;
+ SDValue Cmp = getARMCmp(LHS, RHS, CC, ARMcc, DAG, dl);
+ EVT VT = TrueVal.getValueType();
+ return DAG.getNode(Opcode, dl, VT, TrueVal, FalseVal, ARMcc, Cmp);
+ }
+ }
if (isUnsupportedFloatingType(LHS.getValueType())) {
DAG.getTargetLoweringInfo().softenSetCCOperands(
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h
index d84a235b8b2..d7586bca2ba 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -240,6 +240,11 @@ class VectorType;
// instructions.
MEMCPY,
+ // V8.1MMainline condition select
+ CSINV, // Conditional select invert.
+ CSNEG, // Conditional select negate.
+ CSINC, // Conditional select increment.
+
// Vector load N-element structure to all lanes:
VLD1DUP = ISD::FIRST_TARGET_MEMORY_OPCODE,
VLD2DUP,
diff --git a/llvm/lib/Target/ARM/ARMInstrFormats.td b/llvm/lib/Target/ARM/ARMInstrFormats.td
index 8885b731749..043b54a7deb 100644
--- a/llvm/lib/Target/ARM/ARMInstrFormats.td
+++ b/llvm/lib/Target/ARM/ARMInstrFormats.td
@@ -188,6 +188,13 @@ def s_cc_out : OptionalDefOperand<OtherVT, (ops CCR), (ops (i32 CPSR))> {
let DecoderMethod = "DecodeCCOutOperand";
}
+// Transform to generate the inverse of a condition code during ISel
+def inv_cond_XFORM : SDNodeXForm<imm, [{
+ ARMCC::CondCodes CC = static_cast<ARMCC::CondCodes>(N->getZExtValue());
+ return CurDAG->getTargetConstant(ARMCC::getOppositeCondition(CC), SDLoc(N),
+ MVT::i32);
+}]>;
+
// VPT predicate
def VPTPredNOperand : AsmOperandClass {
diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td
index ac1be46447f..5396ffb7af5 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -116,6 +116,16 @@ def ARMSmlaldx : SDNode<"ARMISD::SMLALDX", SDT_LongMac>;
def ARMSmlsld : SDNode<"ARMISD::SMLSLD", SDT_LongMac>;
def ARMSmlsldx : SDNode<"ARMISD::SMLSLDX", SDT_LongMac>;
+def SDT_ARMCSel : SDTypeProfile<1, 3,
+ [SDTCisSameAs<0, 1>,
+ SDTCisSameAs<0, 2>,
+ SDTCisInt<3>,
+ SDTCisVT<3, i32>]>;
+
+def ARMcsinv : SDNode<"ARMISD::CSINV", SDT_ARMCSel, [SDNPOptInGlue]>;
+def ARMcsneg : SDNode<"ARMISD::CSNEG", SDT_ARMCSel, [SDNPOptInGlue]>;
+def ARMcsinc : SDNode<"ARMISD::CSINC", SDT_ARMCSel, [SDNPOptInGlue]>;
+
def SDT_MulHSR : SDTypeProfile<1, 3, [SDTCisVT<0,i32>,
SDTCisSameAs<0, 1>,
SDTCisSameAs<0, 2>,
diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td
index 7e74a0a3845..f8cea50408c 100644
--- a/llvm/lib/Target/ARM/ARMInstrThumb2.td
+++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td
@@ -5257,6 +5257,25 @@ def t2CSINC : CS<"csinc", 0b1001>;
def t2CSINV : CS<"csinv", 0b1010>;
def t2CSNEG : CS<"csneg", 0b1011>;
+let Predicates = [HasV8_1MMainline] in {
+ def : T2Pat<(ARMcsinc GPRwithZR:$tval, GPRwithZR:$fval, imm0_31:$imm),
+ (t2CSINC GPRwithZR:$tval, GPRwithZR:$fval, imm0_31:$imm)>;
+ def : T2Pat<(ARMcsinv GPRwithZR:$tval, GPRwithZR:$fval, imm0_31:$imm),
+ (t2CSINV GPRwithZR:$tval, GPRwithZR:$fval, imm0_31:$imm)>;
+ def : T2Pat<(ARMcsneg GPRwithZR:$tval, GPRwithZR:$fval, imm0_31:$imm),
+ (t2CSNEG GPRwithZR:$tval, GPRwithZR:$fval, imm0_31:$imm)>;
+
+ multiclass ModifiedV8_1CSEL<Instruction Insn, dag modvalue> {
+ def : T2Pat<(ARMcmov modvalue, GPRwithZR:$tval, cmovpred:$imm),
+ (Insn GPRwithZR:$tval, GPRwithZR:$fval, imm0_31:$imm)>;
+ def : T2Pat<(ARMcmov GPRwithZR:$tval, modvalue, cmovpred:$imm),
+ (Insn GPRwithZR:$tval, GPRwithZR:$fval,
+ (i32 (inv_cond_XFORM imm:$imm)))>;
+ }
+ defm : ModifiedV8_1CSEL<t2CSINC, (add rGPR:$fval, 1)>;
+ defm : ModifiedV8_1CSEL<t2CSINV, (xor rGPR:$fval, -1)>;
+ defm : ModifiedV8_1CSEL<t2CSNEG, (sub 0, rGPR:$fval)>;
+}
// CS aliases.
let Predicates = [HasV8_1MMainline] in {
OpenPOWER on IntegriCloud