43#define DEBUG_TYPE "bypass-slow-division"
51 QuotRemPair(
Value *InQuotient,
Value *InRemainder)
52 : Quotient(InQuotient), Remainder(InRemainder) {}
60 Value *Quotient =
nullptr;
61 Value *Remainder =
nullptr;
78class FastDivInsertionTask {
79 bool IsValidTask =
false;
88 bool isHashLikeValue(
Value *
V, VisitedSetTy &Visited);
89 ValueRange getValueRange(
Value *
Op, VisitedSetTy &Visited);
92 QuotRemPair createDivRemPhiNodes(QuotRemWithBB &
LHS, QuotRemWithBB &
RHS,
95 std::optional<QuotRemPair> insertFastDivAndRem();
98 return SlowDivOrRem->
getOpcode() == Instruction::SDiv ||
99 SlowDivOrRem->
getOpcode() == Instruction::SRem;
102 bool isDivisionOp() {
103 return SlowDivOrRem->
getOpcode() == Instruction::SDiv ||
104 SlowDivOrRem->
getOpcode() == Instruction::UDiv;
107 Type *getSlowType() {
return SlowDivOrRem->
getType(); }
110 FastDivInsertionTask(
Instruction *
I,
const BypassWidthsTy &BypassWidths,
114 Value *getReplacement(DivCacheTy &Cache);
119FastDivInsertionTask::FastDivInsertionTask(
Instruction *
I,
120 const BypassWidthsTy &BypassWidths,
123 : DTU(DTU), LI(LI), BPI(BPI) {
124 switch (
I->getOpcode()) {
125 case Instruction::UDiv:
126 case Instruction::SDiv:
127 case Instruction::URem:
128 case Instruction::SRem:
142 auto BI = BypassWidths.find(SlowType->getBitWidth());
143 if (BI == BypassWidths.end())
151 MainBB =
I->getParent();
161Value *FastDivInsertionTask::getReplacement(DivCacheTy &Cache) {
170 auto CacheI = Cache.find(
Key);
172 if (CacheI == Cache.end()) {
174 std::optional<QuotRemPair> OptResult = insertFastDivAndRem();
178 CacheI = Cache.insert({
Key, *OptResult}).first;
181 QuotRemPair &
Value = CacheI->second;
182 return isDivisionOp() ?
Value.Quotient :
Value.Remainder;
200bool FastDivInsertionTask::isHashLikeValue(
Value *
V, VisitedSetTy &Visited) {
205 switch (
I->getOpcode()) {
206 case Instruction::Xor:
208 case Instruction::Mul: {
213 Value *Op1 =
I->getOperand(1);
217 return C &&
C->getValue().getSignificantBits() > BypassType->
getBitWidth();
219 case Instruction::PHI:
222 if (Visited.size() >= 16)
226 if (!Visited.insert(
I).second)
231 return getValueRange(
V, Visited) == VALRNG_LIKELY_LONG ||
240ValueRange FastDivInsertionTask::getValueRange(
Value *
V,
241 VisitedSetTy &Visited) {
243 unsigned LongLen =
V->getType()->getIntegerBitWidth();
245 assert(LongLen > ShortLen &&
"Value type must be wider than BypassType");
246 unsigned HiBits = LongLen - ShortLen;
249 KnownBits
Known(LongLen);
253 if (
Known.countMinLeadingZeros() >= HiBits)
254 return VALRNG_KNOWN_SHORT;
256 if (
Known.countMaxLeadingZeros() < HiBits)
257 return VALRNG_LIKELY_LONG;
263 if (isHashLikeValue(
V, Visited))
264 return VALRNG_LIKELY_LONG;
266 return VALRNG_UNKNOWN;
270BasicBlock *FastDivInsertionTask::splitMainBB() {
289QuotRemWithBB FastDivInsertionTask::createSlowBB(BasicBlock *SuccessorBB) {
290 QuotRemWithBB DivRemPair;
294 Builder.SetCurrentDebugLocation(SlowDivOrRem->
getDebugLoc());
300 DivRemPair.Quotient = Builder.CreateSDiv(Dividend, Divisor);
301 DivRemPair.Remainder = Builder.CreateSRem(Dividend, Divisor);
303 DivRemPair.Quotient = Builder.CreateUDiv(Dividend, Divisor);
304 DivRemPair.Remainder = Builder.CreateURem(Dividend, Divisor);
307 Builder.CreateBr(SuccessorBB);
313QuotRemWithBB FastDivInsertionTask::createFastBB(BasicBlock *SuccessorBB) {
314 QuotRemWithBB DivRemPair;
318 Builder.SetCurrentDebugLocation(SlowDivOrRem->
getDebugLoc());
322 Value *ShortDivisorV =
323 Builder.CreateCast(Instruction::Trunc, Divisor, BypassType);
324 Value *ShortDividendV =
325 Builder.CreateCast(Instruction::Trunc, Dividend, BypassType);
328 Value *ShortQV = Builder.CreateUDiv(ShortDividendV, ShortDivisorV);
329 Value *ShortRV = Builder.CreateURem(ShortDividendV, ShortDivisorV);
330 DivRemPair.Quotient =
331 Builder.CreateCast(Instruction::ZExt, ShortQV, getSlowType());
332 DivRemPair.Remainder =
333 Builder.CreateCast(Instruction::ZExt, ShortRV, getSlowType());
334 Builder.CreateBr(SuccessorBB);
340QuotRemPair FastDivInsertionTask::createDivRemPhiNodes(QuotRemWithBB &
LHS,
344 Builder.SetCurrentDebugLocation(SlowDivOrRem->
getDebugLoc());
345 PHINode *QuoPhi = Builder.CreatePHI(getSlowType(), 2);
348 PHINode *RemPhi = Builder.CreatePHI(getSlowType(), 2);
351 return QuotRemPair(QuoPhi, RemPhi);
358Value *FastDivInsertionTask::insertOperandRuntimeCheck(
Value *Op1,
Value *Op2) {
359 assert((Op1 || Op2) &&
"Nothing to check");
361 Builder.SetCurrentDebugLocation(SlowDivOrRem->
getDebugLoc());
365 OrV = Builder.CreateOr(Op1, Op2);
367 OrV = Op1 ? Op1 : Op2;
370 Value *AndV = Builder.CreateAnd(
376 return Builder.CreateICmpEQ(AndV, ZeroV);
381std::optional<QuotRemPair> FastDivInsertionTask::insertFastDivAndRem() {
386 ValueRange DividendRange = getValueRange(Dividend, SetL);
387 if (DividendRange == VALRNG_LIKELY_LONG)
391 ValueRange DivisorRange = getValueRange(Divisor, SetR);
392 if (DivisorRange == VALRNG_LIKELY_LONG)
395 bool DividendShort = (DividendRange == VALRNG_KNOWN_SHORT);
396 bool DivisorShort = (DivisorRange == VALRNG_KNOWN_SHORT);
398 if (DividendShort && DivisorShort) {
405 Value *TruncDividend = Builder.CreateTrunc(Dividend, BypassType);
406 Value *TruncDivisor = Builder.CreateTrunc(Divisor, BypassType);
407 Value *TruncDiv = Builder.CreateUDiv(TruncDividend, TruncDivisor);
408 Value *TruncRem = Builder.CreateURem(TruncDividend, TruncDivisor);
409 Value *ExtDiv = Builder.CreateZExt(TruncDiv, getSlowType());
410 Value *ExtRem = Builder.CreateZExt(TruncRem, getSlowType());
411 return QuotRemPair(ExtDiv, ExtRem);
426 if (BCI->getParent() == SlowDivOrRem->
getParent() &&
431 Builder.SetCurrentDebugLocation(SlowDivOrRem->
getDebugLoc());
449 Long.Quotient = ConstantInt::get(getSlowType(), 0);
450 Long.Remainder = Dividend;
451 QuotRemWithBB
Fast = createFastBB(SuccessorBB);
452 QuotRemPair
Result = createDivRemPhiNodes(
Fast, Long, SuccessorBB);
453 Value *CmpV = Builder.CreateICmpUGE(Dividend, Divisor);
454 CondBrInst *CB = Builder.CreateCondBr(CmpV,
Fast.BB, SuccessorBB);
459 {DominatorTree::Insert,
Fast.BB, SuccessorBB}});
462 L->addBasicBlockToLoop(
Fast.BB, *LI);
473 QuotRemWithBB
Fast = createFastBB(SuccessorBB);
474 QuotRemWithBB Slow = createSlowBB(SuccessorBB);
475 QuotRemPair
Result = createDivRemPhiNodes(
Fast, Slow, SuccessorBB);
476 Value *CmpV = insertOperandRuntimeCheck(DividendShort ?
nullptr : Dividend,
477 DivisorShort ?
nullptr : Divisor);
478 CondBrInst *CB = Builder.CreateCondBr(CmpV,
Fast.BB, Slow.BB);
482 {DominatorTree::Insert, MainBB, Slow.BB},
483 {DominatorTree::Insert,
Fast.BB, SuccessorBB},
484 {DominatorTree::Insert, Slow.BB, SuccessorBB},
485 {DominatorTree::Delete, MainBB, SuccessorBB}});
488 L->addBasicBlockToLoop(
Fast.BB, *LI);
489 L->addBasicBlockToLoop(Slow.BB, *LI);
498 const BypassWidthsTy &BypassWidths,
499 DomTreeUpdater *DTU, LoopInfo *LI,
500 BranchProbabilityInfo *BPI) {
501 DivCacheTy PerBBDivCache;
503 bool MadeChange =
false;
505 while (
Next !=
nullptr) {
515 FastDivInsertionTask Task(
I, BypassWidths, DTU, LI, BPI);
516 if (
Value *Replacement = Task.getReplacement(PerBBDivCache)) {
517 I->replaceAllUsesWith(Replacement);
518 I->eraseFromParent();
526 for (
auto &KV : PerBBDivCache)
527 for (
Value *
V : {KV.second.Quotient, KV.second.Remainder})
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines the DenseMap class.
This file contains the declarations for profiling metadata utility functions.
static int isSignedOp(ISD::CondCode Opcode)
For an integer comparison, return 1 if the comparison is a signed operation and 2 if the result is an...
This file defines the SmallPtrSet class.
static APInt getBitsSetFrom(unsigned numBits, unsigned loBit)
Constructs an APInt value that has a contiguous range of bits set.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
const Function * getParent() const
Return the enclosing method, or null if none.
const Instruction & back() const
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Analysis providing branch probability information.
LLVM_ABI void eraseBlock(const BasicBlock *BB)
Forget analysis results for the given basic block.
LLVM_ABI BranchProbability getEdgeProbability(const BasicBlock *Src, unsigned IndexInSuccessors) const
Get an edge's probability, relative to other out-edges of the Src.
LLVM_ABI void setEdgeProbability(const BasicBlock *Src, ArrayRef< BranchProbability > Probs)
Set the raw probabilities for all edges from the given block.
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
void applyUpdates(ArrayRef< UpdateT > Updates)
Submit updates to all available trees.
LLVM_ABI unsigned getNumSuccessors() const LLVM_READONLY
Return the number of successors that this instruction has.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Class to represent integer types.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getIntegerBitWidth() const
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
const ParentTy * getParent() const
@ BasicBlock
Various leaf nodes.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI bool RecursivelyDeleteTriviallyDeadInstructions(Value *V, const TargetLibraryInfo *TLI=nullptr, MemorySSAUpdater *MSSAU=nullptr, std::function< void(Value *)> AboutToDeleteCallback=std::function< void(Value *)>())
If the specified value is a trivially dead instruction, delete it.
LLVM_ABI bool bypassSlowDivision(BasicBlock *BB, const DenseMap< unsigned int, unsigned int > &BypassWidth, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BranchProbabilityInfo *BPI=nullptr)
This optimization identifies DIV instructions in a BB that can be profitably bypassed and carried out...
@ Known
Known to have no common set bits.
LLVM_ABI void setExplicitlyUnknownBranchWeightsIfProfiled(Instruction &I, StringRef PassName, const Function *F=nullptr)
Like setExplicitlyUnknownBranchWeights(...), but only sets unknown branch weights in the new instruct...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Determine which bits of V are known to be either zero or one and return them in the KnownZero/KnownOn...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
LLVM_ABI BasicBlock * SplitBlock(BasicBlock *Old, BasicBlock::iterator SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the specified block at the specified instruction.
@ Fast
Assign the register banks as fast as possible (default).
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next