Skip to content

Commit 239cfbc

Browse files
committed
[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
1 parent 9d50958 commit 239cfbc

File tree

3 files changed

+56
-18
lines changed

3 files changed

+56
-18
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,13 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
199199

200200
if (Subtarget.is64Bit() && Subtarget.hasStdExtM()) {
201201
setOperationAction(ISD::MUL, MVT::i32, Custom);
202+
203+
setOperationAction(ISD::SDIV, MVT::i8, Custom);
204+
setOperationAction(ISD::UDIV, MVT::i8, Custom);
205+
setOperationAction(ISD::UREM, MVT::i8, Custom);
206+
setOperationAction(ISD::SDIV, MVT::i16, Custom);
207+
setOperationAction(ISD::UDIV, MVT::i16, Custom);
208+
setOperationAction(ISD::UREM, MVT::i16, Custom);
202209
setOperationAction(ISD::SDIV, MVT::i32, Custom);
203210
setOperationAction(ISD::UDIV, MVT::i32, Custom);
204211
setOperationAction(ISD::UREM, MVT::i32, Custom);
@@ -1436,11 +1443,12 @@ static RISCVISD::NodeType getRISCVWOpcode(unsigned Opcode) {
14361443
// be promoted to i64, making it difficult to select the SLLW/DIVUW/.../*W
14371444
// later one because the fact the operation was originally of type i32 is
14381445
// lost.
1439-
static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG) {
1446+
static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG,
1447+
unsigned ExtOpc = ISD::ANY_EXTEND) {
14401448
SDLoc DL(N);
14411449
RISCVISD::NodeType WOpcode = getRISCVWOpcode(N->getOpcode());
1442-
SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0));
1443-
SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1));
1450+
SDValue NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
1451+
SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
14441452
SDValue NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1);
14451453
// ReplaceNodeResults requires we maintain the same type for the return value.
14461454
return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes);
@@ -1537,14 +1545,26 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
15371545
break;
15381546
case ISD::SDIV:
15391547
case ISD::UDIV:
1540-
case ISD::UREM:
1541-
assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
1542-
Subtarget.hasStdExtM() && "Unexpected custom legalisation");
1548+
case ISD::UREM: {
1549+
MVT VT = N->getSimpleValueType(0);
1550+
assert((VT == MVT::i8 || VT == MVT::i16 || VT == MVT::i32) &&
1551+
Subtarget.is64Bit() && Subtarget.hasStdExtM() &&
1552+
"Unexpected custom legalisation");
15431553
if (N->getOperand(0).getOpcode() == ISD::Constant ||
15441554
N->getOperand(1).getOpcode() == ISD::Constant)
15451555
return;
1546-
Results.push_back(customLegalizeToWOp(N, DAG));
1556+
1557+
// If the input is i32, use ANY_EXTEND since the W instructions don't read
1558+
// the upper 32 bits. For other types we need to sign or zero extend
1559+
// based on the opcode.
1560+
unsigned ExtOpc = ISD::ANY_EXTEND;
1561+
if (VT != MVT::i32)
1562+
ExtOpc = N->getOpcode() == ISD::SDIV ? ISD::SIGN_EXTEND
1563+
: ISD::ZERO_EXTEND;
1564+
1565+
Results.push_back(customLegalizeToWOp(N, DAG, ExtOpc));
15471566
break;
1567+
}
15481568
case ISD::BITCAST: {
15491569
assert(((N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() &&
15501570
Subtarget.hasStdExtF()) ||
@@ -2147,6 +2167,7 @@ void RISCVTargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
21472167
const APInt &DemandedElts,
21482168
const SelectionDAG &DAG,
21492169
unsigned Depth) const {
2170+
unsigned BitWidth = Known.getBitWidth();
21502171
unsigned Opc = Op.getOpcode();
21512172
assert((Opc >= ISD::BUILTIN_OP_END ||
21522173
Opc == ISD::INTRINSIC_WO_CHAIN ||
@@ -2158,6 +2179,26 @@ void RISCVTargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
21582179
Known.resetAll();
21592180
switch (Opc) {
21602181
default: break;
2182+
case RISCVISD::REMUW: {
2183+
KnownBits Known2;
2184+
Known = DAG.computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
2185+
Known2 = DAG.computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
2186+
// We only care about the lower 32 bits.
2187+
Known = KnownBits::urem(Known.trunc(32), Known2.trunc(32));
2188+
// Restore the original width by sign extending.
2189+
Known = Known.sext(BitWidth);
2190+
break;
2191+
}
2192+
case RISCVISD::DIVUW: {
2193+
KnownBits Known2;
2194+
Known = DAG.computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
2195+
Known2 = DAG.computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
2196+
// We only care about the lower 32 bits.
2197+
Known = KnownBits::udiv(Known.trunc(32), Known2.trunc(32));
2198+
// Restore the original width by sign extending.
2199+
Known = Known.sext(BitWidth);
2200+
break;
2201+
}
21612202
case RISCVISD::READ_VLENB:
21622203
// We assume VLENB is at least 8 bytes.
21632204
// FIXME: The 1.0 draft spec defines minimum VLEN as 128 bits.

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ enum NodeType : unsigned {
4444
SRAW,
4545
SRLW,
4646
// 32-bit operations from RV64M that can't be simply matched with a pattern
47-
// at instruction selection time.
47+
// at instruction selection time. These have undefined behavior for division
48+
// by 0 or overflow (divw) like their target independent counterparts.
4849
DIVW,
4950
DIVUW,
5051
REMUW,

llvm/test/CodeGen/RISCV/rv64m-exhaustive-w-insts.ll

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ define zeroext i32 @zext_divuw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwin
529529
define zeroext i8 @zext_divuw_zext_zext_i8(i8 zeroext %a, i8 zeroext %b) nounwind {
530530
; RV64IM-LABEL: zext_divuw_zext_zext_i8:
531531
; RV64IM: # %bb.0:
532-
; RV64IM-NEXT: divu a0, a0, a1
532+
; RV64IM-NEXT: divuw a0, a0, a1
533533
; RV64IM-NEXT: ret
534534
%1 = udiv i8 %a, %b
535535
ret i8 %1
@@ -538,7 +538,7 @@ define zeroext i8 @zext_divuw_zext_zext_i8(i8 zeroext %a, i8 zeroext %b) nounwin
538538
define zeroext i16 @zext_divuw_zext_zext_i16(i16 zeroext %a, i16 zeroext %b) nounwind {
539539
; RV64IM-LABEL: zext_divuw_zext_zext_i16:
540540
; RV64IM: # %bb.0:
541-
; RV64IM-NEXT: divu a0, a0, a1
541+
; RV64IM-NEXT: divuw a0, a0, a1
542542
; RV64IM-NEXT: ret
543543
%1 = udiv i16 %a, %b
544544
ret i16 %1
@@ -808,9 +808,7 @@ define zeroext i32 @zext_divw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwind
808808
define signext i8 @sext_divw_sext_sext_i8(i8 signext %a, i8 signext %b) nounwind {
809809
; RV64IM-LABEL: sext_divw_sext_sext_i8:
810810
; RV64IM: # %bb.0:
811-
; RV64IM-NEXT: div a0, a0, a1
812-
; RV64IM-NEXT: slli a0, a0, 56
813-
; RV64IM-NEXT: srai a0, a0, 56
811+
; RV64IM-NEXT: divw a0, a0, a1
814812
; RV64IM-NEXT: ret
815813
%1 = sdiv i8 %a, %b
816814
ret i8 %1
@@ -819,9 +817,7 @@ define signext i8 @sext_divw_sext_sext_i8(i8 signext %a, i8 signext %b) nounwind
819817
define signext i16 @sext_divw_sext_sext_i16(i16 signext %a, i16 signext %b) nounwind {
820818
; RV64IM-LABEL: sext_divw_sext_sext_i16:
821819
; RV64IM: # %bb.0:
822-
; RV64IM-NEXT: div a0, a0, a1
823-
; RV64IM-NEXT: slli a0, a0, 48
824-
; RV64IM-NEXT: srai a0, a0, 48
820+
; RV64IM-NEXT: divw a0, a0, a1
825821
; RV64IM-NEXT: ret
826822
%1 = sdiv i16 %a, %b
827823
ret i16 %1
@@ -1372,7 +1368,7 @@ define zeroext i32 @zext_remuw_zext_zext(i32 zeroext %a, i32 zeroext %b) nounwin
13721368
define zeroext i8 @zext_remuw_zext_zext_i8(i8 zeroext %a, i8 zeroext %b) nounwind {
13731369
; RV64IM-LABEL: zext_remuw_zext_zext_i8:
13741370
; RV64IM: # %bb.0:
1375-
; RV64IM-NEXT: remu a0, a0, a1
1371+
; RV64IM-NEXT: remuw a0, a0, a1
13761372
; RV64IM-NEXT: ret
13771373
%1 = urem i8 %a, %b
13781374
ret i8 %1
@@ -1381,7 +1377,7 @@ define zeroext i8 @zext_remuw_zext_zext_i8(i8 zeroext %a, i8 zeroext %b) nounwin
13811377
define zeroext i16 @zext_remuw_zext_zext_i16(i16 zeroext %a, i16 zeroext %b) nounwind {
13821378
; RV64IM-LABEL: zext_remuw_zext_zext_i16:
13831379
; RV64IM: # %bb.0:
1384-
; RV64IM-NEXT: remu a0, a0, a1
1380+
; RV64IM-NEXT: remuw a0, a0, a1
13851381
; RV64IM-NEXT: ret
13861382
%1 = urem i16 %a, %b
13871383
ret i16 %1

0 commit comments

Comments
 (0)