Index: lib/Target/AArch64/AArch64ISelLowering.h =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.h +++ lib/Target/AArch64/AArch64ISelLowering.h @@ -378,6 +378,8 @@ return AArch64::X1; } + bool isIntDivCheap(EVT VT, AttributeSet Attr) const override; + bool isCheapToSpeculateCttz() const override { return true; } Index: lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- lib/Target/AArch64/AArch64ISelLowering.cpp +++ lib/Target/AArch64/AArch64ISelLowering.cpp @@ -7516,6 +7516,10 @@ AArch64TargetLowering::BuildSDIVPow2(SDNode *N, const APInt &Divisor, SelectionDAG &DAG, std::vector *Created) const { + AttributeSet Attr = DAG.getMachineFunction().getFunction()->getAttributes(); + if (isIntDivCheap(N->getValueType(0), Attr)) + return SDValue(N,0); // Lower SDIV as SDIV + // fold (sdiv X, pow2) EVT VT = N->getValueType(0); if ((VT != MVT::i32 && VT != MVT::i64) || @@ -10298,3 +10302,16 @@ .addReg(NewVR); } } + +bool AArch64TargetLowering::isIntDivCheap(EVT VT, AttributeSet Attr) const { + // Integer division on AArch64 is expensive. However, when aggressively + // optimizing for code size, we prefer to use a div instruction, as it is + // usually smaller than the alternative sequence. + // The exception to this is vector division. Since AArch64 doesn't have vector + // integer division, leaving the division as-is is a loss even in terms of + // size, because it will have to be scalarized, while the alternative code + // sequence can be performed in vector form. + bool OptSize = + Attr.hasAttribute(AttributeSet::FunctionIndex, Attribute::MinSize); + return OptSize && !VT.isVector(); +} Index: test/CodeGen/AArch64/div_minsize.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/div_minsize.ll @@ -0,0 +1,45 @@ +; RUN: llc < %s -march=aarch64 -mtriple=aarch64-linux-gnu | FileCheck %s + +define i32 @testsize1(i32 %x) minsize nounwind { +entry: + %div = sdiv i32 %x, 32 + ret i32 %div +; CHECK-LABEL: testsize1 +; CHECK: sdiv +} + +define i32 @testsize2(i32 %x) minsize nounwind { +entry: + %div = sdiv i32 %x, 33 + ret i32 %div +; CHECK-LABEL: testsize2 +; CHECK: sdiv +} + +define i32 @testsize3(i32 %x) minsize nounwind { +entry: + %div = udiv i32 %x, 32 + ret i32 %div +; CHECK-LABEL: testsize3 +; CHECK: lsr +} + +define i32 @testsize4(i32 %x) minsize nounwind { +entry: + %div = udiv i32 %x, 33 + ret i32 %div +; CHECK-LABEL: testsize4 +; CHECK: udiv +} + +define <8 x i16> @sdiv_vec8x16_minsize(<8 x i16> %var) minsize { +entry: +; CHECK: sdiv_vec8x16_minsize +; CHECK: sshr v1.8h, v0.8h, #15 +; CHECK: usra v0.8h, v1.8h, #11 +; CHECK: sshr v0.8h, v0.8h, #5 +; CHECK: ret + %0 = sdiv <8 x i16> %var, + ret <8 x i16> %0 +} +