summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
diff options
context:
space:
mode:
authorAlex Bradbury <asb@lowrisc.org>2019-01-25 05:04:00 +0000
committerAlex Bradbury <asb@lowrisc.org>2019-01-25 05:04:00 +0000
commit299d690a502b5a1d56e5e73b2bd7c137b82c20a6 (patch)
tree359222f8403941be1ad126a665199b94c82ab0f2 /llvm/lib/Target/RISCV/RISCVISelLowering.cpp
parent3b9a82ff2c798aff3eb48ab1220447bfd2d013e0 (diff)
downloadbcm5719-llvm-299d690a502b5a1d56e5e73b2bd7c137b82c20a6.tar.gz
bcm5719-llvm-299d690a502b5a1d56e5e73b2bd7c137b82c20a6.zip
[RISCV] Custom-legalise 32-bit variable shifts on RV64
The previous DAG combiner-based approach had an issue with infinite loops between the target-dependent and target-independent combiner logic (see PR40333). Although this was worked around in rL351806, the combiner-based approach is still potentially brittle and can fail to select the 32-bit shift variant when profitable to do so, as demonstrated in the pr40333.ll test case. This patch instead introduces target-specific SelectionDAG nodes for SHLW/SRLW/SRAW and custom-lowers variable i32 shifts to them. pr40333.ll is a good example of how this approach can improve codegen. This adds DAG combine that does SimplifyDemandedBits on the operands (only lower 32-bits of first operand and lower 5 bits of second operand are read). This seems better than implementing SimplifyDemandedBitsForTargetNode as there is no guarantee that would be called (and it's not for e.g. the anyext return test cases). Also implements ComputeNumSignBitsForTargetNode. There are codegen changes in atomic-rmw.ll and atomic-cmpxchg.ll but the new instruction sequences are semantically equivalent. Differential Revision: https://reviews.llvm.org/D57085 llvm-svn: 352169
Diffstat (limited to 'llvm/lib/Target/RISCV/RISCVISelLowering.cpp')
-rw-r--r--llvm/lib/Target/RISCV/RISCVISelLowering.cpp118
1 files changed, 86 insertions, 32 deletions
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 16591c4208c..4bbdd860bd1 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -80,10 +80,10 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand);
if (Subtarget.is64Bit()) {
- setTargetDAGCombine(ISD::SHL);
- setTargetDAGCombine(ISD::SRL);
- setTargetDAGCombine(ISD::SRA);
setTargetDAGCombine(ISD::ANY_EXTEND);
+ setOperationAction(ISD::SHL, MVT::i32, Custom);
+ setOperationAction(ISD::SRA, MVT::i32, Custom);
+ setOperationAction(ISD::SRL, MVT::i32, Custom);
}
if (!Subtarget.hasStdExtM()) {
@@ -512,15 +512,52 @@ SDValue RISCVTargetLowering::lowerRETURNADDR(SDValue Op,
return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, XLenVT);
}
-// Return true if the given node is a shift with a non-constant shift amount.
-static bool isVariableShift(SDValue Val) {
- switch (Val.getOpcode()) {
+// Returns the opcode of the target-specific SDNode that implements the 32-bit
+// form of the given Opcode.
+static RISCVISD::NodeType getRISCVWOpcode(unsigned Opcode) {
+ switch (Opcode) {
default:
- return false;
+ llvm_unreachable("Unexpected opcode");
case ISD::SHL:
+ return RISCVISD::SLLW;
case ISD::SRA:
+ return RISCVISD::SRAW;
case ISD::SRL:
- return Val.getOperand(1).getOpcode() != ISD::Constant;
+ return RISCVISD::SRLW;
+ }
+}
+
+// Converts the given 32-bit operation to a target-specific SelectionDAG node.
+// Because i32 isn't a legal type for RV64, these operations would otherwise
+// be promoted to i64, making it difficult to select the SLLW/DIVUW/.../*W
+// later one because the fact the operation was originally of type i32 is
+// lost.
+static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG) {
+ SDLoc DL(N);
+ RISCVISD::NodeType WOpcode = getRISCVWOpcode(N->getOpcode());
+ SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0));
+ SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
+ SDValue NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
+ // ReplaceNodeResults requires we maintain the same type for the return value.
+ return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
+}
+
+void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
+ SmallVectorImpl<SDValue> &Results,
+ SelectionDAG &DAG) const {
+ SDLoc DL(N);
+ switch (N->getOpcode()) {
+ default:
+ llvm_unreachable("Don't know how to custom type legalize this operation!");
+ case ISD::SHL:
+ case ISD::SRA:
+ case ISD::SRL:
+ assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
+ "Unexpected custom legalisation");
+ if (N->getOperand(1).getOpcode() == ISD::Constant)
+ return;
+ Results.push_back(customLegalizeToWOp(N, DAG));
+ break;
}
}
@@ -545,34 +582,14 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
switch (N->getOpcode()) {
default:
break;
- case ISD::SHL:
- case ISD::SRL:
- case ISD::SRA: {
- assert(Subtarget.getXLen() == 64 && "Combine should be 64-bit only");
- if (!DCI.isBeforeLegalize())
- break;
- SDValue RHS = N->getOperand(1);
- if (N->getValueType(0) != MVT::i32 || RHS->getOpcode() == ISD::Constant ||
- (RHS->getOpcode() == ISD::AssertZext &&
- cast<VTSDNode>(RHS->getOperand(1))->getVT().getSizeInBits() <= 5))
- break;
- SDValue LHS = N->getOperand(0);
- SDLoc DL(N);
- SDValue NewRHS =
- DAG.getNode(ISD::AssertZext, DL, RHS.getValueType(), RHS,
- DAG.getValueType(EVT::getIntegerVT(*DAG.getContext(), 5)));
- return DCI.CombineTo(
- N, DAG.getNode(N->getOpcode(), DL, LHS.getValueType(), LHS, NewRHS));
- }
case ISD::ANY_EXTEND: {
- // If any-extending an i32 variable-length shift or sdiv/udiv/urem to i64,
- // then instead sign-extend in order to increase the chance of being able
- // to select the sllw/srlw/sraw/divw/divuw/remuw instructions.
+ // If any-extending an i32 sdiv/udiv/urem to i64, then instead sign-extend
+ // in order to increase the chance of being able to select the
+ // divw/divuw/remuw instructions.
SDValue Src = N->getOperand(0);
if (N->getValueType(0) != MVT::i64 || Src.getValueType() != MVT::i32)
break;
- if (!isVariableShift(Src) &&
- !(Subtarget.hasStdExtM() && isVariableSDivUDivURem(Src)))
+ if (!(Subtarget.hasStdExtM() && isVariableSDivUDivURem(Src)))
break;
SDLoc DL(N);
// Don't add the new node to the DAGCombiner worklist, in order to avoid
@@ -589,11 +606,42 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
break;
return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1));
}
+ case RISCVISD::SLLW:
+ case RISCVISD::SRAW:
+ case RISCVISD::SRLW: {
+ // Only the lower 32 bits of LHS and lower 5 bits of RHS are read.
+ SDValue LHS = N->getOperand(0);
+ SDValue RHS = N->getOperand(1);
+ APInt LHSMask = APInt::getLowBitsSet(LHS.getValueSizeInBits(), 32);
+ APInt RHSMask = APInt::getLowBitsSet(RHS.getValueSizeInBits(), 5);
+ if ((SimplifyDemandedBits(N->getOperand(0), LHSMask, DCI)) ||
+ (SimplifyDemandedBits(N->getOperand(1), RHSMask, DCI)))
+ return SDValue();
+ break;
+ }
}
return SDValue();
}
+unsigned RISCVTargetLowering::ComputeNumSignBitsForTargetNode(
+ SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG,
+ unsigned Depth) const {
+ switch (Op.getOpcode()) {
+ default:
+ break;
+ case RISCVISD::SLLW:
+ case RISCVISD::SRAW:
+ case RISCVISD::SRLW:
+ // TODO: As the result is sign-extended, this is conservatively correct. A
+ // more precise answer could be calculated for SRAW depending on known
+ // bits in the shift amount.
+ return 33;
+ }
+
+ return 1;
+}
+
static MachineBasicBlock *emitSplitF64Pseudo(MachineInstr &MI,
MachineBasicBlock *BB) {
assert(MI.getOpcode() == RISCV::SplitF64Pseudo && "Unexpected instruction");
@@ -1682,6 +1730,12 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
return "RISCVISD::SplitF64";
case RISCVISD::TAIL:
return "RISCVISD::TAIL";
+ case RISCVISD::SLLW:
+ return "RISCVISD::SLLW";
+ case RISCVISD::SRAW:
+ return "RISCVISD::SRAW";
+ case RISCVISD::SRLW:
+ return "RISCVISD::SRLW";
}
return nullptr;
}
OpenPOWER on IntegriCloud