42#define DEBUG_TYPE "bypass-slow-division"
50 QuotRemPair(
Value *InQuotient,
Value *InRemainder)
51 : Quotient(InQuotient), Remainder(InRemainder) {}
59 Value *Quotient =
nullptr;
60 Value *Remainder =
nullptr;
77class FastDivInsertionTask {
78 bool IsValidTask =
false;
87 bool isHashLikeValue(
Value *V, VisitedSetTy &Visited);
88 ValueRange getValueRange(
Value *
Op, VisitedSetTy &Visited);
91 QuotRemPair createDivRemPhiNodes(QuotRemWithBB &
LHS, QuotRemWithBB &
RHS,
94 std::optional<QuotRemPair> insertFastDivAndRem();
97 return SlowDivOrRem->
getOpcode() == Instruction::SDiv ||
98 SlowDivOrRem->
getOpcode() == Instruction::SRem;
101 bool isDivisionOp() {
102 return SlowDivOrRem->
getOpcode() == Instruction::SDiv ||
103 SlowDivOrRem->
getOpcode() == Instruction::UDiv;
106 Type *getSlowType() {
return SlowDivOrRem->
getType(); }
109 FastDivInsertionTask(
Instruction *
I,
const BypassWidthsTy &BypassWidths,
113 Value *getReplacement(DivCacheTy &Cache);
118FastDivInsertionTask::FastDivInsertionTask(
Instruction *
I,
119 const BypassWidthsTy &BypassWidths,
122 : DTU(DTU), LI(LI), BPI(BPI) {
123 switch (
I->getOpcode()) {
124 case Instruction::UDiv:
125 case Instruction::SDiv:
126 case Instruction::URem:
127 case Instruction::SRem:
141 auto BI = BypassWidths.find(SlowType->getBitWidth());
142 if (BI == BypassWidths.end())
150 MainBB =
I->getParent();
160Value *FastDivInsertionTask::getReplacement(DivCacheTy &Cache) {
169 auto CacheI = Cache.find(
Key);
171 if (CacheI == Cache.end()) {
173 std::optional<QuotRemPair> OptResult = insertFastDivAndRem();
177 CacheI = Cache.insert({
Key, *OptResult}).first;
180 QuotRemPair &
Value = CacheI->second;
181 return isDivisionOp() ?
Value.Quotient :
Value.Remainder;
199bool FastDivInsertionTask::isHashLikeValue(
Value *V, VisitedSetTy &Visited) {
204 switch (
I->getOpcode()) {
205 case Instruction::Xor:
207 case Instruction::Mul: {
212 Value *Op1 =
I->getOperand(1);
216 return C &&
C->getValue().getSignificantBits() > BypassType->
getBitWidth();
218 case Instruction::PHI:
221 if (Visited.size() >= 16)
225 if (!Visited.insert(
I).second)
230 return getValueRange(V, Visited) == VALRNG_LIKELY_LONG ||
239ValueRange FastDivInsertionTask::getValueRange(
Value *V,
240 VisitedSetTy &Visited) {
242 unsigned LongLen =
V->getType()->getIntegerBitWidth();
244 assert(LongLen > ShortLen &&
"Value type must be wider than BypassType");
245 unsigned HiBits = LongLen - ShortLen;
248 KnownBits
Known(LongLen);
252 if (
Known.countMinLeadingZeros() >= HiBits)
253 return VALRNG_KNOWN_SHORT;
255 if (
Known.countMaxLeadingZeros() < HiBits)
256 return VALRNG_LIKELY_LONG;
262 if (isHashLikeValue(V, Visited))
263 return VALRNG_LIKELY_LONG;
265 return VALRNG_UNKNOWN;
269BasicBlock *FastDivInsertionTask::splitMainBB() {
288QuotRemWithBB FastDivInsertionTask::createSlowBB(BasicBlock *SuccessorBB) {
289 QuotRemWithBB DivRemPair;
293 Builder.SetCurrentDebugLocation(SlowDivOrRem->
getDebugLoc());
299 DivRemPair.Quotient = Builder.CreateSDiv(Dividend, Divisor);
300 DivRemPair.Remainder = Builder.CreateSRem(Dividend, Divisor);
302 DivRemPair.Quotient = Builder.CreateUDiv(Dividend, Divisor);
303 DivRemPair.Remainder = Builder.CreateURem(Dividend, Divisor);
306 Builder.CreateBr(SuccessorBB);
312QuotRemWithBB FastDivInsertionTask::createFastBB(BasicBlock *SuccessorBB) {
313 QuotRemWithBB DivRemPair;
317 Builder.SetCurrentDebugLocation(SlowDivOrRem->
getDebugLoc());
321 Value *ShortDivisorV =
322 Builder.CreateCast(Instruction::Trunc, Divisor, BypassType);
323 Value *ShortDividendV =
324 Builder.CreateCast(Instruction::Trunc, Dividend, BypassType);
327 Value *ShortQV = Builder.CreateUDiv(ShortDividendV, ShortDivisorV);
328 Value *ShortRV = Builder.CreateURem(ShortDividendV, ShortDivisorV);
329 DivRemPair.Quotient =
330 Builder.CreateCast(Instruction::ZExt, ShortQV, getSlowType());
331 DivRemPair.Remainder =
332 Builder.CreateCast(Instruction::ZExt, ShortRV, getSlowType());
333 Builder.CreateBr(SuccessorBB);
339QuotRemPair FastDivInsertionTask::createDivRemPhiNodes(QuotRemWithBB &
LHS,
343 Builder.SetCurrentDebugLocation(SlowDivOrRem->
getDebugLoc());
344 PHINode *QuoPhi = Builder.CreatePHI(getSlowType(), 2);
347 PHINode *RemPhi = Builder.CreatePHI(getSlowType(), 2);
350 return QuotRemPair(QuoPhi, RemPhi);
357Value *FastDivInsertionTask::insertOperandRuntimeCheck(
Value *Op1,
Value *Op2) {
358 assert((Op1 || Op2) &&
"Nothing to check");
360 Builder.SetCurrentDebugLocation(SlowDivOrRem->
getDebugLoc());
364 OrV = Builder.CreateOr(Op1, Op2);
366 OrV = Op1 ? Op1 : Op2;
369 Value *AndV = Builder.CreateAnd(
375 return Builder.CreateICmpEQ(AndV, ZeroV);
380std::optional<QuotRemPair> FastDivInsertionTask::insertFastDivAndRem() {
385 ValueRange DividendRange = getValueRange(Dividend, SetL);
386 if (DividendRange == VALRNG_LIKELY_LONG)
390 ValueRange DivisorRange = getValueRange(Divisor, SetR);
391 if (DivisorRange == VALRNG_LIKELY_LONG)
394 bool DividendShort = (DividendRange == VALRNG_KNOWN_SHORT);
395 bool DivisorShort = (DivisorRange == VALRNG_KNOWN_SHORT);
397 if (DividendShort && DivisorShort) {
404 Value *TruncDividend = Builder.CreateTrunc(Dividend, BypassType);
405 Value *TruncDivisor = Builder.CreateTrunc(Divisor, BypassType);
406 Value *TruncDiv = Builder.CreateUDiv(TruncDividend, TruncDivisor);
407 Value *TruncRem = Builder.CreateURem(TruncDividend, TruncDivisor);
408 Value *ExtDiv = Builder.CreateZExt(TruncDiv, getSlowType());
409 Value *ExtRem = Builder.CreateZExt(TruncRem, getSlowType());
410 return QuotRemPair(ExtDiv, ExtRem);
425 if (BCI->getParent() == SlowDivOrRem->
getParent() &&
430 Builder.SetCurrentDebugLocation(SlowDivOrRem->
getDebugLoc());
448 Long.Quotient = ConstantInt::get(getSlowType(), 0);
449 Long.Remainder = Dividend;
450 QuotRemWithBB
Fast = createFastBB(SuccessorBB);
451 QuotRemPair
Result = createDivRemPhiNodes(
Fast, Long, SuccessorBB);
452 Value *CmpV = Builder.CreateICmpUGE(Dividend, Divisor);
453 Builder.CreateCondBr(CmpV,
Fast.BB, SuccessorBB);
457 {DominatorTree::Insert,
Fast.BB, SuccessorBB}});
460 L->addBasicBlockToLoop(
Fast.BB, *LI);
471 QuotRemWithBB
Fast = createFastBB(SuccessorBB);
472 QuotRemWithBB Slow = createSlowBB(SuccessorBB);
473 QuotRemPair
Result = createDivRemPhiNodes(
Fast, Slow, SuccessorBB);
474 Value *CmpV = insertOperandRuntimeCheck(DividendShort ?
nullptr : Dividend,
475 DivisorShort ?
nullptr : Divisor);
476 Builder.CreateCondBr(CmpV,
Fast.BB, Slow.BB);
479 {DominatorTree::Insert, MainBB, Slow.BB},
480 {DominatorTree::Insert,
Fast.BB, SuccessorBB},
481 {DominatorTree::Insert, Slow.BB, SuccessorBB},
482 {DominatorTree::Delete, MainBB, SuccessorBB}});
485 L->addBasicBlockToLoop(
Fast.BB, *LI);
486 L->addBasicBlockToLoop(Slow.BB, *LI);
495 const BypassWidthsTy &BypassWidths,
496 DomTreeUpdater *DTU, LoopInfo *LI,
497 BranchProbabilityInfo *BPI) {
498 DivCacheTy PerBBDivCache;
500 bool MadeChange =
false;
502 while (
Next !=
nullptr) {
512 FastDivInsertionTask Task(
I, BypassWidths, DTU, LI, BPI);
513 if (
Value *Replacement = Task.getReplacement(PerBBDivCache)) {
514 I->replaceAllUsesWith(Replacement);
515 I->eraseFromParent();
523 for (
auto &KV : PerBBDivCache)
524 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.
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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=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...
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
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
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