[RISCV] Use DIVUW/REMUW/DIVW instructions for i8/i16/i32 udiv/urem/sdiv when LHS...
authorCraig Topper <craig.topper@sifive.com>
Tue, 13 Jul 2021 17:27:29 +0000 (10:27 -0700)
committerCraig Topper <craig.topper@sifive.com>
Tue, 13 Jul 2021 17:33:57 +0000 (10:33 -0700)
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

llvm/lib/Target/RISCV/RISCVISelLowering.cpp
llvm/test/CodeGen/RISCV/div.ll
llvm/test/CodeGen/RISCV/rem.ll

index a81aec1..9d2ae67 100644 (file)
@@ -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 difficult 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 difficult 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:
index 8bfc66e..279329d 100644 (file)
@@ -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
index 87f7558..dea41e1 100644 (file)
@@ -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