Skip to content

Commit

Permalink
[RISCV] Introduce codegen patterns for RV64M-only instructions
Browse files Browse the repository at this point in the history
As discussed on llvm-dev
<http://lists.llvm.org/pipermail/llvm-dev/2018-December/128497.html>, we have
to be careful when trying to select the *w RV64M instructions. i32 is not a
legal type for RV64 in the RISC-V backend, so operations have been promoted by
the time they reach instruction selection. Information about whether the
operation was originally a 32-bit operations has been lost, and it's easy to
write incorrect patterns.

Similarly to the variable 32-bit shifts, a DAG combine on ANY_EXTEND will
produce a SIGN_EXTEND if this is likely to result in sdiv/udiv/urem being
selected (and so save instructions to sext/zext the input operands).

Differential Revision: https://reviews.llvm.org/D53230

llvm-svn: 350993
  • Loading branch information
asb committed Jan 12, 2019
1 parent d05eae7 commit 61aa940
Show file tree
Hide file tree
Showing 6 changed files with 1,781 additions and 9 deletions.
26 changes: 21 additions & 5 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Expand Up @@ -525,6 +525,20 @@ static bool isVariableShift(SDValue Val) {
}
}

// Returns true if the given node is an sdiv, udiv, or urem with non-constant
// operands.
static bool isVariableSDivUDivURem(SDValue Val) {
switch (Val.getOpcode()) {
default:
return false;
case ISD::SDIV:
case ISD::UDIV:
case ISD::UREM:
return Val.getOperand(0).getOpcode() != ISD::Constant &&
Val.getOperand(1).getOpcode() != ISD::Constant;
}
}

SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
DAGCombinerInfo &DCI) const {
SelectionDAG &DAG = DCI.DAG;
Expand Down Expand Up @@ -552,12 +566,14 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
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.
// 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.
SDValue Src = N->getOperand(0);
if (N->getValueType(0) != MVT::i64 || Src.getValueType() != MVT::i32 ||
!isVariableShift(Src))
if (N->getValueType(0) != MVT::i64 || Src.getValueType() != MVT::i32)
break;
if (!isVariableShift(Src) &&
!(Subtarget.hasStdExtM() && isVariableSDivUDivURem(Src)))
break;
SDLoc DL(N);
return DCI.CombineTo(N, DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, Src));
Expand Down
31 changes: 31 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfoM.td
Expand Up @@ -49,3 +49,34 @@ def : PatGprGpr<udiv, DIVU>;
def : PatGprGpr<srem, REM>;
def : PatGprGpr<urem, REMU>;
} // Predicates = [HasStdExtM]

let Predicates = [HasStdExtM, IsRV64] in {
def : Pat<(sext_inreg (mul GPR:$rs1, GPR:$rs2), i32),
(MULW GPR:$rs1, GPR:$rs2)>;
def : Pat<(sext_inreg (sdiv (sexti32 GPR:$rs1),
(sexti32 GPR:$rs2)), i32),
(DIVW GPR:$rs1, GPR:$rs2)>;
def : Pat<(zexti32 (sdiv (sexti32 GPR:$rs1),
(sexti32 GPR:$rs2))),
(SRLI (SLLI (DIVW GPR:$rs1, GPR:$rs2), 32), 32)>;
def : Pat<(sext_inreg (udiv (zexti32 GPR:$rs1), (zexti32 GPR:$rs2)), i32),
(DIVUW GPR:$rs1, GPR:$rs2)>;
// It's cheaper to perform a divuw and zero-extend the result than to
// zero-extend both inputs to a udiv.
def : Pat<(udiv (and GPR:$rs1, 0xffffffff), (and GPR:$rs2, 0xffffffff)),
(SRLI (SLLI (DIVUW GPR:$rs1, GPR:$rs2), 32), 32)>;
// Although the sexti32 operands may not have originated from an i32 srem,
// this pattern is safe as it is impossible for two sign extended inputs to
// produce a result where res[63:32]=0 and res[31]=1.
def : Pat<(srem (sexti32 GPR:$rs1), (sexti32 GPR:$rs2)),
(REMW GPR:$rs1, GPR:$rs2)>;
def : Pat<(sext_inreg (srem (sexti32 GPR:$rs1),
(sexti32 GPR:$rs2)), i32),
(REMW GPR:$rs1, GPR:$rs2)>;
def : Pat<(sext_inreg (urem (zexti32 GPR:$rs1), (zexti32 GPR:$rs2)), i32),
(REMUW GPR:$rs1, GPR:$rs2)>;
// It's cheaper to perform a remuw and zero-extend the result than to
// zero-extend both inputs to a urem.
def : Pat<(urem (and GPR:$rs1, 0xffffffff), (and GPR:$rs2, 0xffffffff)),
(SRLI (SLLI (REMUW GPR:$rs1, GPR:$rs2), 32), 32)>;
} // Predicates = [HasStdExtM, IsRV64]

0 comments on commit 61aa940

Please sign in to comment.