1 //===--- ExpandLargeDivRem.cpp - Expand large div/rem ---------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This pass expands div/rem instructions with a bitwidth above a threshold
10 // into a call to auto-generated functions.
11 // This is useful for targets like x86_64 that cannot lower divisions
12 // with more than 128 bits or targets like x86_32 that cannot lower divisions
13 // with more than 64 bits.
15 //===----------------------------------------------------------------------===//
17 #include "llvm/CodeGen/ExpandLargeDivRem.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/Analysis/GlobalsModRef.h"
21 #include "llvm/CodeGen/Passes.h"
22 #include "llvm/CodeGen/TargetLowering.h"
23 #include "llvm/CodeGen/TargetPassConfig.h"
24 #include "llvm/CodeGen/TargetSubtargetInfo.h"
25 #include "llvm/IR/IRBuilder.h"
26 #include "llvm/IR/InstIterator.h"
27 #include "llvm/IR/PassManager.h"
28 #include "llvm/InitializePasses.h"
29 #include "llvm/Pass.h"
30 #include "llvm/Support/CommandLine.h"
31 #include "llvm/Target/TargetMachine.h"
32 #include "llvm/Transforms/Utils/IntegerDivision.h"
36 static cl::opt
<unsigned>
37 ExpandDivRemBits("expand-div-rem-bits", cl::Hidden
,
38 cl::init(llvm::IntegerType::MAX_INT_BITS
),
39 cl::desc("div and rem instructions on integers with "
40 "more than <N> bits are expanded."));
42 static bool isConstantPowerOfTwo(llvm::Value
*V
, bool SignedOp
) {
43 auto *C
= dyn_cast
<ConstantInt
>(V
);
47 APInt Val
= C
->getValue();
48 if (SignedOp
&& Val
.isNegative())
50 return Val
.isPowerOf2();
53 static bool isSigned(unsigned int Opcode
) {
54 return Opcode
== Instruction::SDiv
|| Opcode
== Instruction::SRem
;
57 static bool runImpl(Function
&F
, const TargetLowering
&TLI
) {
58 SmallVector
<BinaryOperator
*, 4> Replace
;
59 bool Modified
= false;
61 unsigned MaxLegalDivRemBitWidth
= TLI
.getMaxDivRemBitWidthSupported();
62 if (ExpandDivRemBits
!= llvm::IntegerType::MAX_INT_BITS
)
63 MaxLegalDivRemBitWidth
= ExpandDivRemBits
;
65 if (MaxLegalDivRemBitWidth
>= llvm::IntegerType::MAX_INT_BITS
)
68 for (auto &I
: instructions(F
)) {
69 switch (I
.getOpcode()) {
70 case Instruction::UDiv
:
71 case Instruction::SDiv
:
72 case Instruction::URem
:
73 case Instruction::SRem
: {
74 // TODO: This doesn't handle vectors.
75 auto *IntTy
= dyn_cast
<IntegerType
>(I
.getType());
76 if (!IntTy
|| IntTy
->getIntegerBitWidth() <= MaxLegalDivRemBitWidth
)
79 // The backend has peephole optimizations for powers of two.
80 if (isConstantPowerOfTwo(I
.getOperand(1), isSigned(I
.getOpcode())))
83 Replace
.push_back(&cast
<BinaryOperator
>(I
));
95 while (!Replace
.empty()) {
96 BinaryOperator
*I
= Replace
.pop_back_val();
98 if (I
->getOpcode() == Instruction::UDiv
||
99 I
->getOpcode() == Instruction::SDiv
) {
110 class ExpandLargeDivRemLegacyPass
: public FunctionPass
{
114 ExpandLargeDivRemLegacyPass() : FunctionPass(ID
) {
115 initializeExpandLargeDivRemLegacyPassPass(*PassRegistry::getPassRegistry());
118 bool runOnFunction(Function
&F
) override
{
119 auto *TM
= &getAnalysis
<TargetPassConfig
>().getTM
<TargetMachine
>();
120 auto *TLI
= TM
->getSubtargetImpl(F
)->getTargetLowering();
121 return runImpl(F
, *TLI
);
124 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
125 AU
.addRequired
<TargetPassConfig
>();
126 AU
.addPreserved
<AAResultsWrapperPass
>();
127 AU
.addPreserved
<GlobalsAAWrapperPass
>();
132 PreservedAnalyses
ExpandLargeDivRemPass::run(Function
&F
,
133 FunctionAnalysisManager
&FAM
) {
134 const TargetSubtargetInfo
*STI
= TM
->getSubtargetImpl(F
);
135 return runImpl(F
, *STI
->getTargetLowering()) ? PreservedAnalyses::none()
136 : PreservedAnalyses::all();
139 char ExpandLargeDivRemLegacyPass::ID
= 0;
140 INITIALIZE_PASS_BEGIN(ExpandLargeDivRemLegacyPass
, "expand-large-div-rem",
141 "Expand large div/rem", false, false)
142 INITIALIZE_PASS_END(ExpandLargeDivRemLegacyPass
, "expand-large-div-rem",
143 "Expand large div/rem", false, false)
145 FunctionPass
*llvm::createExpandLargeDivRemPass() {
146 return new ExpandLargeDivRemLegacyPass();