23#define DEBUG_TYPE "codemover-utils"
26 "Cannot move across instructions that has memory dependences");
27STATISTIC(MayThrowException,
"Cannot move across instructions that may throw");
29 "Instructions are not control flow equivalent");
30STATISTIC(NotMovedPHINode,
"Movement of PHINodes are not supported");
31STATISTIC(NotMovedTerminator,
"Movement of Terminator are not supported");
44 OS <<
"[" << *
C.getPointer() <<
", " << (
C.getInt() ?
"true" :
"false")
51class ControlConditions {
55 ConditionVectorTy Conditions;
62 static const std::optional<ControlConditions>
66 unsigned MaxLookup = 6);
70 bool isUnconditional()
const {
return Conditions.empty(); }
73 const ConditionVectorTy &getControlConditions()
const {
return Conditions; }
77 bool addControlCondition(ControlCondition
C);
81 bool isEquivalent(
const ControlConditions &
Other)
const;
84 static bool isEquivalent(
const ControlCondition &C1,
85 const ControlCondition &C2);
88 ControlConditions() =
default;
90 static bool isEquivalent(
const Value &V1,
const Value &V2);
91 static bool isInverse(
const Value &V1,
const Value &V2);
104 return DA->getLevel() < DB->getLevel();
107const std::optional<ControlConditions>
108ControlConditions::collectControlConditions(
const BasicBlock &BB,
112 unsigned MaxLookup) {
113 assert(DT.
dominates(&Dominator, &BB) &&
"Expecting Dominator to dominate BB");
115 ControlConditions Conditions;
116 unsigned NumConditions = 0;
119 if (&Dominator == &BB)
126 assert(DT.
getNode(CurBlock) &&
"Expecting a valid DT node for CurBlock");
129 "Expecting Dominator to dominate IDom");
139 <<
" is executed unconditionally from "
145 Inserted = Conditions.addControlCondition(
151 Inserted = Conditions.addControlCondition(
159 if (MaxLookup != 0 && NumConditions > MaxLookup)
163 }
while (CurBlock != &Dominator);
168bool ControlConditions::addControlCondition(ControlCondition
C) {
170 if (
none_of(Conditions, [&](ControlCondition &Exists) {
171 return ControlConditions::isEquivalent(
C, Exists);
173 Conditions.push_back(
C);
177 LLVM_DEBUG(
dbgs() << (Inserted ?
"Inserted " :
"Not inserted ") <<
C <<
"\n");
181bool ControlConditions::isEquivalent(
const ControlConditions &
Other)
const {
182 if (Conditions.empty() &&
Other.Conditions.empty())
185 if (Conditions.size() !=
Other.Conditions.size())
188 return all_of(Conditions, [&](
const ControlCondition &
C) {
189 return any_of(
Other.Conditions, [&](
const ControlCondition &OtherC) {
190 return ControlConditions::isEquivalent(C, OtherC);
195bool ControlConditions::isEquivalent(
const ControlCondition &C1,
196 const ControlCondition &C2) {
197 if (C1.getInt() == C2.getInt()) {
198 if (isEquivalent(*C1.getPointer(), *C2.getPointer()))
200 }
else if (isInverse(*C1.getPointer(), *C2.getPointer()))
210bool ControlConditions::isEquivalent(
const Value &V1,
const Value &V2) {
214bool ControlConditions::isInverse(
const Value &V1,
const Value &V2) {
215 if (
const CmpInst *Cmp1 = dyn_cast<CmpInst>(&V1))
216 if (
const CmpInst *Cmp2 = dyn_cast<CmpInst>(&V2)) {
217 if (Cmp1->getPredicate() == Cmp2->getInversePredicate() &&
218 Cmp1->getOperand(0) == Cmp2->getOperand(0) &&
219 Cmp1->getOperand(1) == Cmp2->getOperand(1))
222 if (Cmp1->getPredicate() ==
224 Cmp1->getOperand(0) == Cmp2->getOperand(1) &&
225 Cmp1->getOperand(1) == Cmp2->getOperand(0))
251 <<
" and " << BB1.
getName() <<
" is "
252 << CommonDominator->
getName() <<
"\n");
254 const std::optional<ControlConditions> BB0Conditions =
255 ControlConditions::collectControlConditions(BB0, *CommonDominator, DT,
257 if (BB0Conditions == std::nullopt)
260 const std::optional<ControlConditions> BB1Conditions =
261 ControlConditions::collectControlConditions(BB1, *CommonDominator, DT,
263 if (BB1Conditions == std::nullopt)
266 return BB0Conditions->isEquivalent(*BB1Conditions);
282 assert(InBetweenInsts.
empty() &&
"Expecting InBetweenInsts to be empty");
288 WorkList.insert(NextInst);
290 assert(
I.isTerminator() &&
"Expecting a terminator instruction");
292 WorkList.insert(&Succ->front());
297 getNextInsts(StartInst, WorkList);
298 while (!WorkList.
empty()) {
300 WorkList.
erase(CurInst);
302 if (CurInst == &EndInst)
305 if (!InBetweenInsts.
insert(CurInst).second)
308 getNextInsts(*CurInst, WorkList);
320 if (&
I == &InsertPoint)
324 if (
I.getNextNode() == &InsertPoint)
327 if (isa<PHINode>(
I) || isa<PHINode>(InsertPoint))
330 if (
I.isTerminator())
338 for (
const Use &U :
I.uses())
339 if (
auto *UserInst = dyn_cast<Instruction>(U.getUser())) {
342 if (
I.getParent() == InsertPoint.
getParent() &&
343 UserInst ==
I.getParent()->getTerminator())
345 if (UserInst != &InsertPoint && !DT.
dominates(&InsertPoint, U)) {
349 if (CheckForEntireBlock &&
I.getParent() == UserInst->getParent() &&
356 for (
const Value *
Op :
I.operands())
357 if (
auto *OpInst = dyn_cast<Instruction>(
Op)) {
358 if (&InsertPoint == OpInst)
362 if (CheckForEntireBlock &&
I.getParent() == OpInst->getParent() &&
371 Instruction &StartInst = (MoveForward ?
I : InsertPoint);
376 InstsToCheck.
insert(&InsertPoint);
385 const CallBase *CB = dyn_cast<CallBase>(
I);
388 if (!CB->hasFnAttr(Attribute::WillReturn))
390 if (!CB->hasFnAttr(Attribute::NoSync))
401 auto DepResult = DI->
depends(&
I, CurInst,
true);
402 if (DepResult && (DepResult->isOutput() || DepResult->isFlow() ||
403 DepResult->isAnti()))
433 I.moveBeforePreserving(MovePos);
442 while (FromBB.
size() > 1) {
445 I.moveBeforePreserving(MovePos);
454 "ThisBlock and OtherBlock must be CFG equivalent!");
457 if (CommonDominator ==
nullptr)
466 while (!WorkList.
empty()) {
470 if (PDT->
dominates(CurBlock, OtherBlock))
474 if (Pred == CommonDominator || Visited.
count(Pred))
static bool reportInvalidCandidate(const Instruction &I, llvm::Statistic &Stat)
static bool domTreeLevelBefore(DominatorTree *DT, const Instruction *InstA, const Instruction *InstB)
static void collectInstructionsInBetween(Instruction &StartInst, const Instruction &EndInst, SmallPtrSetImpl< Instruction * > &InBetweenInsts)
Collect all instructions in between StartInst and EndInst, and store them in InBetweenInsts.
std::optional< std::vector< StOtherPiece > > Other
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
LLVM Basic Block Representation.
const Instruction & front() const
const Instruction * getFirstNonPHIOrDbg(bool SkipPseudoOp=true) const
Returns a pointer to the first instruction in this block that is not a PHINode or a debug intrinsic,...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Conditional or Unconditional Branch instruction.
BasicBlock * getSuccessor(unsigned i) const
Value * getCondition() const
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
This class is the base class for the comparison instructions.
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
This class represents an Operation in the Expression.
DependenceInfo - This class is the main dependence-analysis driver.
std::unique_ptr< Dependence > depends(Instruction *Src, Instruction *Dst, bool PossiblyLoopIndependent)
depends - Tests for a dependence between the Src and Dst instructions.
DomTreeNodeBase * getIDom() const
void updateDFSNumbers() const
updateDFSNumbers - Assign In and Out numbers to the nodes while walking dominator tree in dfs order.
DomTreeNodeBase< NodeT > * getNode(const NodeT *BB) const
getNode - return the (Post)DominatorTree node for the specified basic block.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Instruction * findNearestCommonDominator(Instruction *I1, Instruction *I2) const
Find the nearest instruction I that dominates both I1 and I2, in the sense that a result produced bef...
bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
PointerIntPair - This class implements a pair of a pointer and small integer.
PostDominatorTree Class - Concrete subclass of DominatorTree that is used to compute the post-dominat...
bool dominates(const Instruction *I1, const Instruction *I2) const
Return true if I1 dominates I2.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
StringRef getName() const
Return a constant reference to the value's name.
const ParentTy * getParent() const
This class implements an extremely fast bulk output stream that can only output to a stream.
@ C
The default llvm calling convention, compatible with C.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
auto successors(const MachineBasicBlock *BB)
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
void moveInstructionsToTheEnd(BasicBlock &FromBB, BasicBlock &ToBB, DominatorTree &DT, const PostDominatorTree &PDT, DependenceInfo &DI)
Move instructions, in an order-preserving manner, from FromBB to the end of ToBB when proven safe.
bool isReachedBefore(const Instruction *I0, const Instruction *I1, const DominatorTree *DT, const PostDominatorTree *PDT)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
bool isSafeToSpeculativelyExecute(const Instruction *I, const Instruction *CtxI=nullptr, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr, const TargetLibraryInfo *TLI=nullptr, bool UseVariableInfo=true)
Return true if the instruction does not have any effects besides calculating the result and does not ...
bool isControlFlowEquivalent(const Instruction &I0, const Instruction &I1, const DominatorTree &DT, const PostDominatorTree &PDT)
Return true if I0 and I1 are control flow equivalent.
bool nonStrictlyPostDominate(const BasicBlock *ThisBlock, const BasicBlock *OtherBlock, const DominatorTree *DT, const PostDominatorTree *PDT)
In case that two BBs ThisBlock and OtherBlock are control flow equivalent but they do not strictly do...
void moveInstructionsToTheBeginning(BasicBlock &FromBB, BasicBlock &ToBB, DominatorTree &DT, const PostDominatorTree &PDT, DependenceInfo &DI)
Move instructions, in an order-preserving manner, from FromBB to the beginning of ToBB when proven sa...
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
auto predecessors(const MachineBasicBlock *BB)
bool isSafeToMoveBefore(Instruction &I, Instruction &InsertPoint, DominatorTree &DT, const PostDominatorTree *PDT=nullptr, DependenceInfo *DI=nullptr, bool CheckForEntireBlock=false)
Return true if I can be safely moved before InsertPoint.