[llvm-branch-commits] [llvm] 239cfbc - [RISCV] Custom type legalize i8/i16 UDIV/UREM/SDIV on RV64 so we can use divuw/remuw/divw.
Craig Topper via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Jan 25 11:01:19 PST 2021
Author: Craig Topper
Date: 2021-01-25T10:47:22-08:00
New Revision: 239cfbccb0509da1a08d9e746706013b732e646b
URL: https://github.com/llvm/llvm-project/commit/239cfbccb0509da1a08d9e746706013b732e646b
DIFF: https://github.com/llvm/llvm-project/commit/239cfbccb0509da1a08d9e746706013b732e646b.diff
LOG: [RISCV] Custom type legalize i8/i16 UDIV/UREM/SDIV on RV64 so we can use divuw/remuw/divw.
This makes our i8/i16 codegen more similar to the i32 codegen.
I've also added computeKnownBits support for DIVUW/REMUW so
that we can remove zero extending ANDs from the output. Without
this we end up turning DIVUW/REMUW back into DIVU/REMU via some
isel patterns.
Reviewed By: frasercrmck, luismarques
Differential Revision: https://reviews.llvm.org/D95322
Added:
Modified:
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
llvm/lib/Target/RISCV/RISCVISelLowering.h
llvm/test/CodeGen/RISCV/rv64m-exhaustive-w-insts.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 54208fc187c9..7d2dae71fc00 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -199,6 +199,13 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
if (Subtarget.is64Bit() && Subtarget.hasStdExtM()) {
setOperationAction(ISD::MUL, MVT::i32, Custom);
+
+ setOperationAction(ISD::SDIV, MVT::i8, Custom);
+ setOperationAction(ISD::UDIV, MVT::i8, Custom);
+ setOperationAction(ISD::UREM, MVT::i8, Custom);
+ setOperationAction(ISD::SDIV, MVT::i16, Custom);
+ setOperationAction(ISD::UDIV, MVT::i16, Custom);
+ setOperationAction(ISD::UREM, MVT::i16, Custom);
setOperationAction(ISD::SDIV, MVT::i32, Custom);
setOperationAction(ISD::UDIV, MVT::i32, Custom);
setOperationAction(ISD::UREM, MVT::i32, Custom);
@@ -1436,11 +1443,12 @@ static RISCVISD::NodeType getRISCVWOpcode(unsigned Opcode) {
// be promoted to i64, making it
diff icult 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) {
+static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG,
+ unsigned ExtOpc = ISD::ANY_EXTEND) {
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 NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
+ SDValue NewOp1 = DAG.getNode(ExtOpc, 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);
@@ -1537,14 +1545,26 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
break;
case ISD::SDIV:
case ISD::UDIV:
- case ISD::UREM:
- assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
- Subtarget.hasStdExtM() && "Unexpected custom legalisation");
+ case ISD::UREM: {
+ MVT VT = N->getSimpleValueType(0);
+ assert((VT == MVT::i8 || VT == MVT::i16 || VT == MVT::i32) &&
+ Subtarget.is64Bit() && Subtarget.hasStdExtM() &&
+ "Unexpected custom legalisation");
if (N->getOperand(0).getOpcode() == ISD::Constant ||
N->getOperand(1).getOpcode() == ISD::Constant)
return;
- Results.push_back(customLegalizeToWOp(N, DAG));
+
+ // If the input is i32, use ANY_EXTEND since the W instructions don't read
+ // the upper 32 bits. For other types we need to sign or zero extend
+ // based on the opcode.
+ unsigned ExtOpc = ISD::ANY_EXTEND;
+ if (VT != MVT::i32)
+ ExtOpc = N->getOpcode() == ISD::SDIV ? ISD::SIGN_EXTEND
+ : ISD::ZERO_EXTEND;
+
+ Results.push_back(customLegalizeToWOp(N, DAG, ExtOpc));
break;
+ }
case ISD::BITCAST: {
assert(((N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
Subtarget.hasStdExtF()) ||
@@ -2147,6 +2167,7 @@ void RISCVTargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
const APInt &DemandedElts,
const SelectionDAG &DAG,
unsigned Depth) const {
+ unsigned BitWidth = Known.getBitWidth();
unsigned Opc = Op.getOpcode();
assert((Opc >= ISD::BUILTIN_OP_END ||
Opc == ISD::INTRINSIC_WO_CHAIN ||
@@ -2158,6 +2179,26 @@ void RISCVTargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
Known.resetAll();
switch (Opc) {
default: break;
+ case RISCVISD::REMUW: {
+ KnownBits Known2;
+ Known = DAG.computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
+ Known2 = DAG.computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
+ // We only care about the lower 32 bits.
+ Known = KnownBits::urem(Known.trunc(32), Known2.trunc(32));
+ // Restore the original width by sign extending.
+ Known = Known.sext(BitWidth);
+ break;
+ }
+ case RISCVISD::DIVUW: {
+ KnownBits Known2;
+ Known = DAG.computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
+ Known2 = DAG.computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
+ // We only care about the lower 32 bits.
+ Known = KnownBits::udiv(Known.trunc(32), Known2.trunc(32));
+ // Restore the original width by sign extending.
+ Known = Known.sext(BitWidth);
+ break;
+ }
case RISCVISD::READ_VLENB:
// We assume VLENB is at least 8 bytes.
// FIXME: The 1.0 draft spec defines minimum VLEN as 128 bits.
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h
index da16c6970d33..14cf1cadd499 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h
@@ -44,7 +44,8 @@ enum NodeType : unsigned {
SRAW,
SRLW,
// 32-bit operations from RV64M that can't be simply matched with a pattern
- // at instruction selection time.
+ // at instruction selection time. These have undefined behavior for division
+ // by 0 or overflow (divw) like their target independent counterparts.
DIVW,
DIVUW,
REMUW,
diff --git a/llvm/test/CodeGen/RISCV/rv64m-exhaustive-w-insts.ll b/llvm/test/CodeGen/RISCV/rv64m-exhaustive-w-insts.ll
index 2f13680933b3..734d2bb21cc3 100644
--- a/llvm/test/CodeGen/RISCV/rv64m-exhaustive-w-insts.ll
+++ b/llvm/test/CodeGen/RISCV/rv64m-exhaustive-w-insts.ll
@@ -529,7 +529,7 @@ define zeroext i32 @zext_divuw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwin
define zeroext i8 @zext_divuw_zext_zext_i8(i8 zeroext %a, i8 zeroext %b) nounwind {
; RV64IM-LABEL: zext_divuw_zext_zext_i8:
; RV64IM: # %bb.0:
-; RV64IM-NEXT: divu a0, a0, a1
+; RV64IM-NEXT: divuw a0, a0, a1
; RV64IM-NEXT: ret
%1 = udiv i8 %a, %b
ret i8 %1
@@ -538,7 +538,7 @@ define zeroext i8 @zext_divuw_zext_zext_i8(i8 zeroext %a, i8 zeroext %b) nounwin
define zeroext i16 @zext_divuw_zext_zext_i16(i16 zeroext %a, i16 zeroext %b) nounwind {
; RV64IM-LABEL: zext_divuw_zext_zext_i16:
; RV64IM: # %bb.0:
-; RV64IM-NEXT: divu a0, a0, a1
+; RV64IM-NEXT: divuw a0, a0, a1
; RV64IM-NEXT: ret
%1 = udiv i16 %a, %b
ret i16 %1
@@ -808,9 +808,7 @@ define zeroext i32 @zext_divw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind
define signext i8 @sext_divw_sext_sext_i8(i8 signext %a, i8 signext %b) nounwind {
; RV64IM-LABEL: sext_divw_sext_sext_i8:
; RV64IM: # %bb.0:
-; RV64IM-NEXT: div a0, a0, a1
-; RV64IM-NEXT: slli a0, a0, 56
-; RV64IM-NEXT: srai a0, a0, 56
+; RV64IM-NEXT: divw a0, a0, a1
; RV64IM-NEXT: ret
%1 = sdiv i8 %a, %b
ret i8 %1
@@ -819,9 +817,7 @@ define signext i8 @sext_divw_sext_sext_i8(i8 signext %a, i8 signext %b) nounwind
define signext i16 @sext_divw_sext_sext_i16(i16 signext %a, i16 signext %b) nounwind {
; RV64IM-LABEL: sext_divw_sext_sext_i16:
; RV64IM: # %bb.0:
-; RV64IM-NEXT: div a0, a0, a1
-; RV64IM-NEXT: slli a0, a0, 48
-; RV64IM-NEXT: srai a0, a0, 48
+; RV64IM-NEXT: divw a0, a0, a1
; RV64IM-NEXT: ret
%1 = sdiv i16 %a, %b
ret i16 %1
@@ -1372,7 +1368,7 @@ define zeroext i32 @zext_remuw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwin
define zeroext i8 @zext_remuw_zext_zext_i8(i8 zeroext %a, i8 zeroext %b) nounwind {
; RV64IM-LABEL: zext_remuw_zext_zext_i8:
; RV64IM: # %bb.0:
-; RV64IM-NEXT: remu a0, a0, a1
+; RV64IM-NEXT: remuw a0, a0, a1
; RV64IM-NEXT: ret
%1 = urem i8 %a, %b
ret i8 %1
@@ -1381,7 +1377,7 @@ define zeroext i8 @zext_remuw_zext_zext_i8(i8 zeroext %a, i8 zeroext %b) nounwin
define zeroext i16 @zext_remuw_zext_zext_i16(i16 zeroext %a, i16 zeroext %b) nounwind {
; RV64IM-LABEL: zext_remuw_zext_zext_i16:
; RV64IM: # %bb.0:
-; RV64IM-NEXT: remu a0, a0, a1
+; RV64IM-NEXT: remuw a0, a0, a1
; RV64IM-NEXT: ret
%1 = urem i16 %a, %b
ret i16 %1
More information about the llvm-branch-commits
mailing list