diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -4704,17 +4704,18 @@ } } -// 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 @@ 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 --- a/llvm/test/CodeGen/RISCV/div.ll +++ b/llvm/test/CodeGen/RISCV/div.ll @@ -146,10 +146,8 @@ ; ; 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 @@ ; 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 @@ ; 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 @@ ; ; 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 @@ ; 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 @@ ; 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 --- a/llvm/test/CodeGen/RISCV/rem.ll +++ b/llvm/test/CodeGen/RISCV/rem.ll @@ -76,10 +76,8 @@ ; ; 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 @@ ; 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 @@ ; 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