diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -381,6 +381,8 @@ bool isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const override; + bool isIntDivCheap(EVT VT, AttributeList Attr) const override; + bool softPromoteHalfType() const override { return true; } /// Return the register type for a given MVT, ensuring vectors are treated 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 @@ -7010,8 +7010,9 @@ "Unexpected custom legalisation"); // 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) + AttributeList Attr = DAG.getMachineFunction().getFunction().getAttributes(); + if (N->getOperand(1).getOpcode() == ISD::Constant && + !isIntDivCheap(N->getValueType(0), Attr)) return; // If the input is i32, use ANY_EXTEND since the W instructions don't read @@ -12533,6 +12534,14 @@ return DAG.getNode(ISD::SUB, DL, VT, DAG.getConstant(0, DL, VT), SRA); } +bool RISCVTargetLowering::isIntDivCheap(EVT VT, AttributeList Attr) const { + // When aggressively optimizing for code size, we prefer to use a div + // instruction, as it is usually smaller than the alternative sequence. + // TODO: Add vector division? + bool OptSize = Attr.hasFnAttr(Attribute::MinSize); + return OptSize && !VT.isVector(); +} + #define GET_REGISTER_MATCHER #include "RISCVGenAsmMatcher.inc" diff --git a/llvm/test/CodeGen/RISCV/div_minsize.ll b/llvm/test/CodeGen/RISCV/div_minsize.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/div_minsize.ll @@ -0,0 +1,71 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+m -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefixes=RV32IM %s +; RUN: llc -mtriple=riscv64 -mattr=+m -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefixes=RV64IM %s + +define i32 @testsize1(i32 %x) minsize nounwind { +; RV32IM-LABEL: testsize1: +; RV32IM: # %bb.0: # %entry +; RV32IM-NEXT: li a1, 32 +; RV32IM-NEXT: div a0, a0, a1 +; RV32IM-NEXT: ret +; +; RV64IM-LABEL: testsize1: +; RV64IM: # %bb.0: # %entry +; RV64IM-NEXT: li a1, 32 +; RV64IM-NEXT: divw a0, a0, a1 +; RV64IM-NEXT: ret +entry: + %div = sdiv i32 %x, 32 + ret i32 %div +} + +define i32 @testsize2(i32 %x) minsize nounwind { +; RV32IM-LABEL: testsize2: +; RV32IM: # %bb.0: # %entry +; RV32IM-NEXT: li a1, 33 +; RV32IM-NEXT: div a0, a0, a1 +; RV32IM-NEXT: ret +; +; RV64IM-LABEL: testsize2: +; RV64IM: # %bb.0: # %entry +; RV64IM-NEXT: li a1, 33 +; RV64IM-NEXT: divw a0, a0, a1 +; RV64IM-NEXT: ret +entry: + %div = sdiv i32 %x, 33 + ret i32 %div +} + +define i32 @testsize3(i32 %x) minsize nounwind { +; RV32IM-LABEL: testsize3: +; RV32IM: # %bb.0: # %entry +; RV32IM-NEXT: srli a0, a0, 5 +; RV32IM-NEXT: ret +; +; RV64IM-LABEL: testsize3: +; RV64IM: # %bb.0: # %entry +; RV64IM-NEXT: srliw a0, a0, 5 +; RV64IM-NEXT: ret +entry: + %div = udiv i32 %x, 32 + ret i32 %div +} + +define i32 @testsize4(i32 %x) minsize nounwind { +; RV32IM-LABEL: testsize4: +; RV32IM: # %bb.0: +; RV32IM-NEXT: li a1, 33 +; RV32IM-NEXT: divu a0, a0, a1 +; RV32IM-NEXT: ret +; +; RV64IM-LABEL: testsize4: +; RV64IM: # %bb.0: +; RV64IM-NEXT: li a1, 33 +; RV64IM-NEXT: divuw a0, a0, a1 +; RV64IM-NEXT: ret + %div = udiv i32 %x, 33 + ret i32 %div +} +