[RISCV] Add patterns for RV64I SLLW/SRLW/SRAW instructions
This restores support for selecting the SLLW/SRLW/SRAW instructions, which was
removed in rL348067 as the previous patterns made some unsafe assumptions.
Also see the related llvm-dev discussion
<http://lists.llvm.org/pipermail/llvm-dev/2018-December/128497.html>
Ultimately I didn't introduce a custom SelectionDAG node, but instead added a
DAG combine that inserts an AssertZext i5 on the shift amount for an i32
variable-length shift and also added an ANY_EXTEND DAG-combine which will
instead produce a SIGN_EXTEND for an i32 variable-length shift, increasing the
opportunity to safely select SLLW/SRLW/SRAW.
There are obviously different ways of addressing this (a number discussed in
the llvm-dev thread), so I'd welcome further feedback and comments.
Note that there are now some cases in
test/CodeGen/RISCV/rv64i-exhaustive-w-insts.ll where sraw/srlw/sllw is
selected even though sra/srl/sll could be used without any extra instructions.
Given both are semantically equivalent, there doesn't seem a good reason to
prefer one vs the other. Given that would require more logic to still select
sra/srl/sll in those cases, I've left it preferring the *w variants.
Differential Revision: https://reviews.llvm.org/D56264
llvm-svn: 350992
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index e78085e..ca6fbb1 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -80,6 +80,13 @@
for (auto VT : {MVT::i1, MVT::i8, MVT::i16})
setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand);
+ if (Subtarget.is64Bit()) {
+ setTargetDAGCombine(ISD::SHL);
+ setTargetDAGCombine(ISD::SRL);
+ setTargetDAGCombine(ISD::SRA);
+ setTargetDAGCombine(ISD::ANY_EXTEND);
+ }
+
if (!Subtarget.hasStdExtM()) {
setOperationAction(ISD::MUL, XLenVT, Expand);
setOperationAction(ISD::MULHS, XLenVT, Expand);
@@ -506,11 +513,55 @@
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()) {
+ default:
+ return false;
+ case ISD::SHL:
+ case ISD::SRA:
+ case ISD::SRL:
+ return Val.getOperand(1).getOpcode() != ISD::Constant;
+ }
+}
+
SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
+ SelectionDAG &DAG = DCI.DAG;
+
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 to i64, then instead
+ // sign-extend in order to increase the chance of being able to select the
+ // sllw/srlw/sraw instruction.
+ SDValue Src = N->getOperand(0);
+ if (N->getValueType(0) != MVT::i64 || Src.getValueType() != MVT::i32 ||
+ !isVariableShift(Src))
+ break;
+ SDLoc DL(N);
+ return DCI.CombineTo(N, DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, Src));
+ }
case RISCVISD::SplitF64: {
// If the input to SplitF64 is just BuildPairF64 then the operation is
// redundant. Instead, use BuildPairF64's operands directly.