[llvm] 1e670dc - [RISCV] Use DIVUW/REMUW/DIVW instructions for i8/i16/i32 udiv/urem/sdiv when LHS is constant.
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 13 10:34:16 PDT 2021
Author: Craig Topper
Date: 2021-07-13T10:33:57-07:00
New Revision: 1e670dc7d78427156c252317b3571576d465043f
URL: https://github.com/llvm/llvm-project/commit/1e670dc7d78427156c252317b3571576d465043f
DIFF: https://github.com/llvm/llvm-project/commit/1e670dc7d78427156c252317b3571576d465043f.diff
LOG: [RISCV] Use DIVUW/REMUW/DIVW instructions for i8/i16/i32 udiv/urem/sdiv when LHS is constant.
We don't really have optimizations for division with a constant
LHS. If we don't use a W instruction we end up needing to sign
or zero extend the RHS to use the 64-bit instruction.
I had to sign_extend i32 constants on the LHS instead of using
any_extend which becomes zero_extend. If we don't do this, constants
that were originally negative become harder to materialize. I think
this problem exists for more of our W instruction cases. For example
(i32 (shl -1, X)), but we don't have lit tests. I'll work on that
as a follow up.
I also left a FIXME for enabling W instruction for RHS constants
under -Oz.
Reviewed By: luismarques
Differential Revision: https://reviews.llvm.org/D105769
Added:
Modified:
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
llvm/test/CodeGen/RISCV/div.ll
llvm/test/CodeGen/RISCV/rem.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index a81aec185cb4..9d2ae6788a92 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -4704,17 +4704,18 @@ static RISCVISD::NodeType getRISCVWOpcode(unsigned Opcode) {
}
}
-// 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
diff icult to select the SLLW/DIVUW/.../*W
-// later one because the fact the operation was originally of type i32 is
-// lost.
+// Converts the given i8/i16/i32 operation to a target-specific SelectionDAG
+// node. Because i8/i16/i32 isn't a legal type for RV64, these operations would
+// otherwise 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 i8/i16/i32 is lost.
static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG,
- unsigned ExtOpc = ISD::ANY_EXTEND) {
+ unsigned ExtOpc0 = ISD::ANY_EXTEND,
+ unsigned ExtOpc1 = ISD::ANY_EXTEND) {
SDLoc DL(N);
RISCVISD::NodeType WOpcode = getRISCVWOpcode(N->getOpcode());
- SDValue NewOp0 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(0));
- SDValue NewOp1 = DAG.getNode(ExtOpc, DL, MVT::i64, N->getOperand(1));
+ SDValue NewOp0 = DAG.getNode(ExtOpc0, DL, MVT::i64, N->getOperand(0));
+ SDValue NewOp1 = DAG.getNode(ExtOpc1, 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, N->getValueType(0), NewRes);
@@ -4870,19 +4871,26 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
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)
+ // Don't promote division/remainder by constant since we should expand those
+ // to multiply by magic constant.
+ // FIXME: What if the expansion is disabled for minsize.
+ if (N->getOperand(1).getOpcode() == ISD::Constant)
return;
// 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;
+ unsigned ExtOpc0 = ISD::ANY_EXTEND, ExtOpc1 = ISD::ANY_EXTEND;
+ if (VT != MVT::i32) {
+ ExtOpc0 = N->getOpcode() == ISD::SDIV ? ISD::SIGN_EXTEND
+ : ISD::ZERO_EXTEND;
+ ExtOpc1 = ExtOpc0;
+ } else if (N->getOperand(0).getOpcode() == ISD::Constant) {
+ // Sign extend i32 constants to improve materialization.
+ ExtOpc0 = ISD::SIGN_EXTEND;
+ }
- Results.push_back(customLegalizeToWOp(N, DAG, ExtOpc));
+ Results.push_back(customLegalizeToWOp(N, DAG, ExtOpc0, ExtOpc1));
break;
}
case ISD::UADDO:
diff --git a/llvm/test/CodeGen/RISCV/div.ll b/llvm/test/CodeGen/RISCV/div.ll
index 8bfc66e7a82a..279329dd277d 100644
--- a/llvm/test/CodeGen/RISCV/div.ll
+++ b/llvm/test/CodeGen/RISCV/div.ll
@@ -146,10 +146,8 @@ define i32 @udiv_constant_lhs(i32 %a) nounwind {
;
; RV64IM-LABEL: udiv_constant_lhs:
; RV64IM: # %bb.0:
-; RV64IM-NEXT: slli a0, a0, 32
-; RV64IM-NEXT: srli a0, a0, 32
; RV64IM-NEXT: addi a1, zero, 10
-; RV64IM-NEXT: divu a0, a1, a0
+; RV64IM-NEXT: divuw a0, a1, a0
; RV64IM-NEXT: ret
%1 = udiv i32 10, %a
ret i32 %1
@@ -432,7 +430,7 @@ define i8 @udiv8_constant_lhs(i8 %a) nounwind {
; RV64IM: # %bb.0:
; RV64IM-NEXT: andi a0, a0, 255
; RV64IM-NEXT: addi a1, zero, 10
-; RV64IM-NEXT: divu a0, a1, a0
+; RV64IM-NEXT: divuw a0, a1, a0
; RV64IM-NEXT: ret
%1 = udiv i8 10, %a
ret i8 %1
@@ -608,7 +606,7 @@ define i16 @udiv16_constant_lhs(i16 %a) nounwind {
; RV64IM-NEXT: addiw a1, a1, -1
; RV64IM-NEXT: and a0, a0, a1
; RV64IM-NEXT: addi a1, zero, 10
-; RV64IM-NEXT: divu a0, a1, a0
+; RV64IM-NEXT: divuw a0, a1, a0
; RV64IM-NEXT: ret
%1 = udiv i16 10, %a
ret i16 %1
@@ -763,9 +761,8 @@ define i32 @sdiv_constant_lhs(i32 %a) nounwind {
;
; RV64IM-LABEL: sdiv_constant_lhs:
; RV64IM: # %bb.0:
-; RV64IM-NEXT: sext.w a0, a0
; RV64IM-NEXT: addi a1, zero, -10
-; RV64IM-NEXT: div a0, a1, a0
+; RV64IM-NEXT: divw a0, a1, a0
; RV64IM-NEXT: ret
%1 = sdiv i32 -10, %a
ret i32 %1
@@ -1143,7 +1140,7 @@ define i8 @sdiv8_constant_lhs(i8 %a) nounwind {
; RV64IM-NEXT: slli a0, a0, 56
; RV64IM-NEXT: srai a0, a0, 56
; RV64IM-NEXT: addi a1, zero, -10
-; RV64IM-NEXT: div a0, a1, a0
+; RV64IM-NEXT: divw a0, a1, a0
; RV64IM-NEXT: ret
%1 = sdiv i8 -10, %a
ret i8 %1
@@ -1336,7 +1333,7 @@ define i16 @sdiv16_constant_lhs(i16 %a) nounwind {
; RV64IM-NEXT: slli a0, a0, 48
; RV64IM-NEXT: srai a0, a0, 48
; RV64IM-NEXT: addi a1, zero, -10
-; RV64IM-NEXT: div a0, a1, a0
+; RV64IM-NEXT: divw a0, a1, a0
; RV64IM-NEXT: ret
%1 = sdiv i16 -10, %a
ret i16 %1
diff --git a/llvm/test/CodeGen/RISCV/rem.ll b/llvm/test/CodeGen/RISCV/rem.ll
index 87f75586a5b2..dea41e1d727d 100644
--- a/llvm/test/CodeGen/RISCV/rem.ll
+++ b/llvm/test/CodeGen/RISCV/rem.ll
@@ -76,10 +76,8 @@ define i32 @urem_constant_lhs(i32 %a) nounwind {
;
; RV64IM-LABEL: urem_constant_lhs:
; RV64IM: # %bb.0:
-; RV64IM-NEXT: slli a0, a0, 32
-; RV64IM-NEXT: srli a0, a0, 32
; RV64IM-NEXT: addi a1, zero, 10
-; RV64IM-NEXT: remu a0, a1, a0
+; RV64IM-NEXT: remuw a0, a1, a0
; RV64IM-NEXT: ret
%1 = urem i32 10, %a
ret i32 %1
@@ -397,7 +395,7 @@ define i8 @urem8_constant_lhs(i8 %a) nounwind {
; RV64IM: # %bb.0:
; RV64IM-NEXT: andi a0, a0, 255
; RV64IM-NEXT: addi a1, zero, 10
-; RV64IM-NEXT: remu a0, a1, a0
+; RV64IM-NEXT: remuw a0, a1, a0
; RV64IM-NEXT: ret
%1 = urem i8 10, %a
ret i8 %1
@@ -587,7 +585,7 @@ define i16 @urem16_constant_lhs(i16 %a) nounwind {
; RV64IM-NEXT: addiw a1, a1, -1
; RV64IM-NEXT: and a0, a0, a1
; RV64IM-NEXT: addi a1, zero, 10
-; RV64IM-NEXT: remu a0, a1, a0
+; RV64IM-NEXT: remuw a0, a1, a0
; RV64IM-NEXT: ret
%1 = urem i16 10, %a
ret i16 %1
More information about the llvm-commits
mailing list