1ae8a8c2dSTsang Whitney W.H //===- CodeMoverUtils.cpp - CodeMover Utilities ----------------------------==// 2ae8a8c2dSTsang Whitney W.H // 3ae8a8c2dSTsang Whitney W.H // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ae8a8c2dSTsang Whitney W.H // See https://llvm.org/LICENSE.txt for license information. 5ae8a8c2dSTsang Whitney W.H // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ae8a8c2dSTsang Whitney W.H // 7ae8a8c2dSTsang Whitney W.H //===----------------------------------------------------------------------===// 8ae8a8c2dSTsang Whitney W.H // 9ae8a8c2dSTsang Whitney W.H // This family of functions perform movements on basic blocks, and instructions 10ae8a8c2dSTsang Whitney W.H // contained within a function. 11ae8a8c2dSTsang Whitney W.H // 12ae8a8c2dSTsang Whitney W.H //===----------------------------------------------------------------------===// 13ae8a8c2dSTsang Whitney W.H 14ae8a8c2dSTsang Whitney W.H #include "llvm/Transforms/Utils/CodeMoverUtils.h" 1578dc6498SWhitney Tsang #include "llvm/ADT/Optional.h" 16ae8a8c2dSTsang Whitney W.H #include "llvm/ADT/Statistic.h" 17ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/DependenceAnalysis.h" 1878dc6498SWhitney Tsang #include "llvm/Analysis/OrderedInstructions.h" 19ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/PostDominators.h" 20ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/ValueTracking.h" 21ae8a8c2dSTsang Whitney W.H #include "llvm/IR/Dominators.h" 22ae8a8c2dSTsang Whitney W.H 23ae8a8c2dSTsang Whitney W.H using namespace llvm; 24ae8a8c2dSTsang Whitney W.H 25ae8a8c2dSTsang Whitney W.H #define DEBUG_TYPE "codemover-utils" 26ae8a8c2dSTsang Whitney W.H 27ae8a8c2dSTsang Whitney W.H STATISTIC(HasDependences, 28ae8a8c2dSTsang Whitney W.H "Cannot move across instructions that has memory dependences"); 29ae8a8c2dSTsang Whitney W.H STATISTIC(MayThrowException, "Cannot move across instructions that may throw"); 30ae8a8c2dSTsang Whitney W.H STATISTIC(NotControlFlowEquivalent, 31ae8a8c2dSTsang Whitney W.H "Instructions are not control flow equivalent"); 32ae8a8c2dSTsang Whitney W.H STATISTIC(NotMovedPHINode, "Movement of PHINodes are not supported"); 33ae8a8c2dSTsang Whitney W.H STATISTIC(NotMovedTerminator, "Movement of Terminator are not supported"); 34ae8a8c2dSTsang Whitney W.H 3578dc6498SWhitney Tsang namespace { 3678dc6498SWhitney Tsang /// Represent a control condition. A control condition is a condition of a 3778dc6498SWhitney Tsang /// terminator to decide which successors to execute. The pointer field 3878dc6498SWhitney Tsang /// represents the address of the condition of the terminator. The integer field 3978dc6498SWhitney Tsang /// is a bool, it is true when the basic block is executed when V is true. For 4078dc6498SWhitney Tsang /// example, `br %cond, bb0, bb1` %cond is a control condition of bb0 with the 4178dc6498SWhitney Tsang /// integer field equals to true, while %cond is a control condition of bb1 with 4278dc6498SWhitney Tsang /// the integer field equals to false. 4378dc6498SWhitney Tsang using ControlCondition = PointerIntPair<Value *, 1, bool>; 4478dc6498SWhitney Tsang #ifndef NDEBUG 4578dc6498SWhitney Tsang raw_ostream &operator<<(raw_ostream &OS, const ControlCondition &C) { 4678dc6498SWhitney Tsang OS << "[" << *C.getPointer() << ", " << (C.getInt() ? "true" : "false") 4778dc6498SWhitney Tsang << "]"; 4878dc6498SWhitney Tsang return OS; 4978dc6498SWhitney Tsang } 5078dc6498SWhitney Tsang #endif 5178dc6498SWhitney Tsang 5278dc6498SWhitney Tsang /// Represent a set of control conditions required to execute ToBB from FromBB. 5378dc6498SWhitney Tsang class ControlConditions { 5478dc6498SWhitney Tsang using ConditionVectorTy = SmallVector<ControlCondition, 6>; 5578dc6498SWhitney Tsang 5678dc6498SWhitney Tsang /// A SmallVector of control conditions. 5778dc6498SWhitney Tsang ConditionVectorTy Conditions; 5878dc6498SWhitney Tsang 5978dc6498SWhitney Tsang public: 6078dc6498SWhitney Tsang /// Return a ControlConditions which stores all conditions required to execute 6178dc6498SWhitney Tsang /// \p BB from \p Dominator. If \p MaxLookup is non-zero, it limits the 6278dc6498SWhitney Tsang /// number of conditions to collect. Return None if not all conditions are 6378dc6498SWhitney Tsang /// collected successfully, or we hit the limit. 649c54b423SMichael Liao static const Optional<ControlConditions> 6578dc6498SWhitney Tsang collectControlConditions(const BasicBlock &BB, const BasicBlock &Dominator, 6678dc6498SWhitney Tsang const DominatorTree &DT, 6778dc6498SWhitney Tsang const PostDominatorTree &PDT, 6878dc6498SWhitney Tsang unsigned MaxLookup = 6); 6978dc6498SWhitney Tsang 7078dc6498SWhitney Tsang /// Return true if there exists no control conditions required to execute ToBB 7178dc6498SWhitney Tsang /// from FromBB. 7278dc6498SWhitney Tsang bool isUnconditional() const { return Conditions.empty(); } 7378dc6498SWhitney Tsang 7478dc6498SWhitney Tsang /// Return a constant reference of Conditions. 7578dc6498SWhitney Tsang const ConditionVectorTy &getControlConditions() const { return Conditions; } 7678dc6498SWhitney Tsang 7778dc6498SWhitney Tsang /// Add \p V as one of the ControlCondition in Condition with IsTrueCondition 7878dc6498SWhitney Tsang /// equals to \p True. Return true if inserted successfully. 7978dc6498SWhitney Tsang bool addControlCondition(ControlCondition C); 8078dc6498SWhitney Tsang 8178dc6498SWhitney Tsang /// Return true if for all control conditions in Conditions, there exists an 8278dc6498SWhitney Tsang /// equivalent control condition in \p Other.Conditions. 8378dc6498SWhitney Tsang bool isEquivalent(const ControlConditions &Other) const; 8478dc6498SWhitney Tsang 8578dc6498SWhitney Tsang /// Return true if \p C1 and \p C2 are equivalent. 8678dc6498SWhitney Tsang static bool isEquivalent(const ControlCondition &C1, 8778dc6498SWhitney Tsang const ControlCondition &C2); 8878dc6498SWhitney Tsang 8978dc6498SWhitney Tsang private: 9078dc6498SWhitney Tsang ControlConditions() = default; 9178dc6498SWhitney Tsang 9278dc6498SWhitney Tsang static bool isEquivalent(const Value &V1, const Value &V2); 9378dc6498SWhitney Tsang static bool isInverse(const Value &V1, const Value &V2); 9478dc6498SWhitney Tsang }; 9578dc6498SWhitney Tsang } // namespace 9678dc6498SWhitney Tsang 979c54b423SMichael Liao const Optional<ControlConditions> ControlConditions::collectControlConditions( 9878dc6498SWhitney Tsang const BasicBlock &BB, const BasicBlock &Dominator, const DominatorTree &DT, 9978dc6498SWhitney Tsang const PostDominatorTree &PDT, unsigned MaxLookup) { 10078dc6498SWhitney Tsang assert(DT.dominates(&Dominator, &BB) && "Expecting Dominator to dominate BB"); 10178dc6498SWhitney Tsang 10278dc6498SWhitney Tsang ControlConditions Conditions; 10378dc6498SWhitney Tsang unsigned NumConditions = 0; 10478dc6498SWhitney Tsang 10578dc6498SWhitney Tsang // BB is executed unconditional from itself. 10678dc6498SWhitney Tsang if (&Dominator == &BB) 10778dc6498SWhitney Tsang return Conditions; 10878dc6498SWhitney Tsang 10978dc6498SWhitney Tsang const BasicBlock *CurBlock = &BB; 11078dc6498SWhitney Tsang // Walk up the dominator tree from the associated DT node for BB to the 11178dc6498SWhitney Tsang // associated DT node for Dominator. 11278dc6498SWhitney Tsang do { 11378dc6498SWhitney Tsang assert(DT.getNode(CurBlock) && "Expecting a valid DT node for CurBlock"); 11478dc6498SWhitney Tsang BasicBlock *IDom = DT.getNode(CurBlock)->getIDom()->getBlock(); 11578dc6498SWhitney Tsang assert(DT.dominates(&Dominator, IDom) && 11678dc6498SWhitney Tsang "Expecting Dominator to dominate IDom"); 11778dc6498SWhitney Tsang 11878dc6498SWhitney Tsang // Limitation: can only handle branch instruction currently. 11978dc6498SWhitney Tsang const BranchInst *BI = dyn_cast<BranchInst>(IDom->getTerminator()); 12078dc6498SWhitney Tsang if (!BI) 12178dc6498SWhitney Tsang return None; 12278dc6498SWhitney Tsang 12378dc6498SWhitney Tsang bool Inserted = false; 12478dc6498SWhitney Tsang if (PDT.dominates(CurBlock, IDom)) { 12578dc6498SWhitney Tsang LLVM_DEBUG(dbgs() << CurBlock->getName() 12678dc6498SWhitney Tsang << " is executed unconditionally from " 12778dc6498SWhitney Tsang << IDom->getName() << "\n"); 12878dc6498SWhitney Tsang } else if (PDT.dominates(CurBlock, BI->getSuccessor(0))) { 12978dc6498SWhitney Tsang LLVM_DEBUG(dbgs() << CurBlock->getName() << " is executed when \"" 13078dc6498SWhitney Tsang << *BI->getCondition() << "\" is true from " 13178dc6498SWhitney Tsang << IDom->getName() << "\n"); 13278dc6498SWhitney Tsang Inserted = Conditions.addControlCondition( 13378dc6498SWhitney Tsang ControlCondition(BI->getCondition(), true)); 13478dc6498SWhitney Tsang } else if (PDT.dominates(CurBlock, BI->getSuccessor(1))) { 13578dc6498SWhitney Tsang LLVM_DEBUG(dbgs() << CurBlock->getName() << " is executed when \"" 13678dc6498SWhitney Tsang << *BI->getCondition() << "\" is false from " 13778dc6498SWhitney Tsang << IDom->getName() << "\n"); 13878dc6498SWhitney Tsang Inserted = Conditions.addControlCondition( 13978dc6498SWhitney Tsang ControlCondition(BI->getCondition(), false)); 14078dc6498SWhitney Tsang } else 14178dc6498SWhitney Tsang return None; 14278dc6498SWhitney Tsang 14378dc6498SWhitney Tsang if (Inserted) 14478dc6498SWhitney Tsang ++NumConditions; 14578dc6498SWhitney Tsang 14678dc6498SWhitney Tsang if (MaxLookup != 0 && NumConditions > MaxLookup) 14778dc6498SWhitney Tsang return None; 14878dc6498SWhitney Tsang 14978dc6498SWhitney Tsang CurBlock = IDom; 15078dc6498SWhitney Tsang } while (CurBlock != &Dominator); 15178dc6498SWhitney Tsang 15278dc6498SWhitney Tsang return Conditions; 15378dc6498SWhitney Tsang } 15478dc6498SWhitney Tsang 15578dc6498SWhitney Tsang bool ControlConditions::addControlCondition(ControlCondition C) { 15678dc6498SWhitney Tsang bool Inserted = false; 15778dc6498SWhitney Tsang if (none_of(Conditions, [&C](ControlCondition &Exists) { 15878dc6498SWhitney Tsang return ControlConditions::isEquivalent(C, Exists); 15978dc6498SWhitney Tsang })) { 16078dc6498SWhitney Tsang Conditions.push_back(C); 16178dc6498SWhitney Tsang Inserted = true; 16278dc6498SWhitney Tsang } 16378dc6498SWhitney Tsang 16478dc6498SWhitney Tsang LLVM_DEBUG(dbgs() << (Inserted ? "Inserted " : "Not inserted ") << C << "\n"); 16578dc6498SWhitney Tsang return Inserted; 16678dc6498SWhitney Tsang } 16778dc6498SWhitney Tsang 16878dc6498SWhitney Tsang bool ControlConditions::isEquivalent(const ControlConditions &Other) const { 16978dc6498SWhitney Tsang if (Conditions.empty() && Other.Conditions.empty()) 17078dc6498SWhitney Tsang return true; 17178dc6498SWhitney Tsang 17278dc6498SWhitney Tsang if (Conditions.size() != Other.Conditions.size()) 17378dc6498SWhitney Tsang return false; 17478dc6498SWhitney Tsang 17578dc6498SWhitney Tsang return all_of(Conditions, [&Other](const ControlCondition &C) { 17678dc6498SWhitney Tsang return any_of(Other.Conditions, [&C](const ControlCondition &OtherC) { 17778dc6498SWhitney Tsang return ControlConditions::isEquivalent(C, OtherC); 17878dc6498SWhitney Tsang }); 17978dc6498SWhitney Tsang }); 18078dc6498SWhitney Tsang } 18178dc6498SWhitney Tsang 18278dc6498SWhitney Tsang bool ControlConditions::isEquivalent(const ControlCondition &C1, 18378dc6498SWhitney Tsang const ControlCondition &C2) { 18478dc6498SWhitney Tsang if (C1.getInt() == C2.getInt()) { 18578dc6498SWhitney Tsang if (isEquivalent(*C1.getPointer(), *C2.getPointer())) 18678dc6498SWhitney Tsang return true; 18778dc6498SWhitney Tsang } else if (isInverse(*C1.getPointer(), *C2.getPointer())) 18878dc6498SWhitney Tsang return true; 18978dc6498SWhitney Tsang 19078dc6498SWhitney Tsang return false; 19178dc6498SWhitney Tsang } 19278dc6498SWhitney Tsang 19378dc6498SWhitney Tsang // FIXME: Use SCEV and reuse GVN/CSE logic to check for equivalence between 19478dc6498SWhitney Tsang // Values. 19578dc6498SWhitney Tsang // Currently, isEquivalent rely on other passes to ensure equivalent conditions 19678dc6498SWhitney Tsang // have the same value, e.g. GVN. 19778dc6498SWhitney Tsang bool ControlConditions::isEquivalent(const Value &V1, const Value &V2) { 19878dc6498SWhitney Tsang return &V1 == &V2; 19978dc6498SWhitney Tsang } 20078dc6498SWhitney Tsang 20178dc6498SWhitney Tsang bool ControlConditions::isInverse(const Value &V1, const Value &V2) { 20278dc6498SWhitney Tsang if (const CmpInst *Cmp1 = dyn_cast<CmpInst>(&V1)) 20378dc6498SWhitney Tsang if (const CmpInst *Cmp2 = dyn_cast<CmpInst>(&V2)) { 20478dc6498SWhitney Tsang if (Cmp1->getPredicate() == Cmp2->getInversePredicate() && 20578dc6498SWhitney Tsang Cmp1->getOperand(0) == Cmp2->getOperand(0) && 20678dc6498SWhitney Tsang Cmp1->getOperand(1) == Cmp2->getOperand(1)) 20778dc6498SWhitney Tsang return true; 20878dc6498SWhitney Tsang 20978dc6498SWhitney Tsang if (Cmp1->getPredicate() == 21078dc6498SWhitney Tsang CmpInst::getSwappedPredicate(Cmp2->getInversePredicate()) && 21178dc6498SWhitney Tsang Cmp1->getOperand(0) == Cmp2->getOperand(1) && 21278dc6498SWhitney Tsang Cmp1->getOperand(1) == Cmp2->getOperand(0)) 21378dc6498SWhitney Tsang return true; 21478dc6498SWhitney Tsang } 21578dc6498SWhitney Tsang return false; 21678dc6498SWhitney Tsang } 21778dc6498SWhitney Tsang 218ae8a8c2dSTsang Whitney W.H bool llvm::isControlFlowEquivalent(const Instruction &I0, const Instruction &I1, 219ae8a8c2dSTsang Whitney W.H const DominatorTree &DT, 220ae8a8c2dSTsang Whitney W.H const PostDominatorTree &PDT) { 221aaf7f05aSWhitney Tsang return isControlFlowEquivalent(*I0.getParent(), *I1.getParent(), DT, PDT); 222aaf7f05aSWhitney Tsang } 223aaf7f05aSWhitney Tsang 224aaf7f05aSWhitney Tsang bool llvm::isControlFlowEquivalent(const BasicBlock &BB0, const BasicBlock &BB1, 225aaf7f05aSWhitney Tsang const DominatorTree &DT, 226aaf7f05aSWhitney Tsang const PostDominatorTree &PDT) { 227aaf7f05aSWhitney Tsang if (&BB0 == &BB1) 228aaf7f05aSWhitney Tsang return true; 229aaf7f05aSWhitney Tsang 23078dc6498SWhitney Tsang if ((DT.dominates(&BB0, &BB1) && PDT.dominates(&BB1, &BB0)) || 23178dc6498SWhitney Tsang (PDT.dominates(&BB0, &BB1) && DT.dominates(&BB1, &BB0))) 23278dc6498SWhitney Tsang return true; 23378dc6498SWhitney Tsang 23478dc6498SWhitney Tsang // If the set of conditions required to execute BB0 and BB1 from their common 23578dc6498SWhitney Tsang // dominator are the same, then BB0 and BB1 are control flow equivalent. 23678dc6498SWhitney Tsang const BasicBlock *CommonDominator = DT.findNearestCommonDominator(&BB0, &BB1); 23778dc6498SWhitney Tsang LLVM_DEBUG(dbgs() << "The nearest common dominator of " << BB0.getName() 23878dc6498SWhitney Tsang << " and " << BB1.getName() << " is " 23978dc6498SWhitney Tsang << CommonDominator->getName() << "\n"); 24078dc6498SWhitney Tsang 2419c54b423SMichael Liao const Optional<ControlConditions> BB0Conditions = 24278dc6498SWhitney Tsang ControlConditions::collectControlConditions(BB0, *CommonDominator, DT, 24378dc6498SWhitney Tsang PDT); 24478dc6498SWhitney Tsang if (BB0Conditions == None) 24578dc6498SWhitney Tsang return false; 24678dc6498SWhitney Tsang 2479c54b423SMichael Liao const Optional<ControlConditions> BB1Conditions = 24878dc6498SWhitney Tsang ControlConditions::collectControlConditions(BB1, *CommonDominator, DT, 24978dc6498SWhitney Tsang PDT); 25078dc6498SWhitney Tsang if (BB1Conditions == None) 25178dc6498SWhitney Tsang return false; 25278dc6498SWhitney Tsang 25378dc6498SWhitney Tsang return BB0Conditions->isEquivalent(*BB1Conditions); 254ae8a8c2dSTsang Whitney W.H } 255ae8a8c2dSTsang Whitney W.H 256ae8a8c2dSTsang Whitney W.H static bool reportInvalidCandidate(const Instruction &I, 257ae8a8c2dSTsang Whitney W.H llvm::Statistic &Stat) { 258ae8a8c2dSTsang Whitney W.H ++Stat; 259ae8a8c2dSTsang Whitney W.H LLVM_DEBUG(dbgs() << "Unable to move instruction: " << I << ". " 260ae8a8c2dSTsang Whitney W.H << Stat.getDesc()); 261ae8a8c2dSTsang Whitney W.H return false; 262ae8a8c2dSTsang Whitney W.H } 263ae8a8c2dSTsang Whitney W.H 264ae8a8c2dSTsang Whitney W.H /// Collect all instructions in between \p StartInst and \p EndInst, and store 265ae8a8c2dSTsang Whitney W.H /// them in \p InBetweenInsts. 266ae8a8c2dSTsang Whitney W.H static void 267ae8a8c2dSTsang Whitney W.H collectInstructionsInBetween(Instruction &StartInst, const Instruction &EndInst, 268ae8a8c2dSTsang Whitney W.H SmallPtrSetImpl<Instruction *> &InBetweenInsts) { 269ae8a8c2dSTsang Whitney W.H assert(InBetweenInsts.empty() && "Expecting InBetweenInsts to be empty"); 270ae8a8c2dSTsang Whitney W.H 271ae8a8c2dSTsang Whitney W.H /// Get the next instructions of \p I, and push them to \p WorkList. 272ae8a8c2dSTsang Whitney W.H auto getNextInsts = [](Instruction &I, 273ae8a8c2dSTsang Whitney W.H SmallPtrSetImpl<Instruction *> &WorkList) { 274ae8a8c2dSTsang Whitney W.H if (Instruction *NextInst = I.getNextNode()) 275ae8a8c2dSTsang Whitney W.H WorkList.insert(NextInst); 276ae8a8c2dSTsang Whitney W.H else { 277ae8a8c2dSTsang Whitney W.H assert(I.isTerminator() && "Expecting a terminator instruction"); 278ae8a8c2dSTsang Whitney W.H for (BasicBlock *Succ : successors(&I)) 279ae8a8c2dSTsang Whitney W.H WorkList.insert(&Succ->front()); 280ae8a8c2dSTsang Whitney W.H } 281ae8a8c2dSTsang Whitney W.H }; 282ae8a8c2dSTsang Whitney W.H 283ae8a8c2dSTsang Whitney W.H SmallPtrSet<Instruction *, 10> WorkList; 284ae8a8c2dSTsang Whitney W.H getNextInsts(StartInst, WorkList); 285ae8a8c2dSTsang Whitney W.H while (!WorkList.empty()) { 286ae8a8c2dSTsang Whitney W.H Instruction *CurInst = *WorkList.begin(); 287ae8a8c2dSTsang Whitney W.H WorkList.erase(CurInst); 288ae8a8c2dSTsang Whitney W.H 289ae8a8c2dSTsang Whitney W.H if (CurInst == &EndInst) 290ae8a8c2dSTsang Whitney W.H continue; 291ae8a8c2dSTsang Whitney W.H 292ae8a8c2dSTsang Whitney W.H if (!InBetweenInsts.insert(CurInst).second) 293ae8a8c2dSTsang Whitney W.H continue; 294ae8a8c2dSTsang Whitney W.H 295ae8a8c2dSTsang Whitney W.H getNextInsts(*CurInst, WorkList); 296ae8a8c2dSTsang Whitney W.H } 297ae8a8c2dSTsang Whitney W.H } 298ae8a8c2dSTsang Whitney W.H 299ae8a8c2dSTsang Whitney W.H bool llvm::isSafeToMoveBefore(Instruction &I, Instruction &InsertPoint, 30078dc6498SWhitney Tsang DominatorTree &DT, const PostDominatorTree &PDT, 301ae8a8c2dSTsang Whitney W.H DependenceInfo &DI) { 302ae8a8c2dSTsang Whitney W.H // Cannot move itself before itself. 303ae8a8c2dSTsang Whitney W.H if (&I == &InsertPoint) 304ae8a8c2dSTsang Whitney W.H return false; 305ae8a8c2dSTsang Whitney W.H 306ae8a8c2dSTsang Whitney W.H // Not moved. 307ae8a8c2dSTsang Whitney W.H if (I.getNextNode() == &InsertPoint) 308ae8a8c2dSTsang Whitney W.H return true; 309ae8a8c2dSTsang Whitney W.H 310ae8a8c2dSTsang Whitney W.H if (isa<PHINode>(I) || isa<PHINode>(InsertPoint)) 311ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, NotMovedPHINode); 312ae8a8c2dSTsang Whitney W.H 313ae8a8c2dSTsang Whitney W.H if (I.isTerminator()) 314ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, NotMovedTerminator); 315ae8a8c2dSTsang Whitney W.H 316ae8a8c2dSTsang Whitney W.H // TODO remove this limitation. 317ae8a8c2dSTsang Whitney W.H if (!isControlFlowEquivalent(I, InsertPoint, DT, PDT)) 318ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, NotControlFlowEquivalent); 319ae8a8c2dSTsang Whitney W.H 32078dc6498SWhitney Tsang OrderedInstructions OI(&DT); 32178dc6498SWhitney Tsang DT.updateDFSNumbers(); 32278dc6498SWhitney Tsang const bool MoveForward = OI.dfsBefore(&I, &InsertPoint); 323ae8a8c2dSTsang Whitney W.H if (MoveForward) { 324ae8a8c2dSTsang Whitney W.H // When I is being moved forward, we need to make sure the InsertPoint 325ae8a8c2dSTsang Whitney W.H // dominates every users. Or else, a user may be using an undefined I. 32636bdc3dcSWhitney Tsang for (const Use &U : I.uses()) 32736bdc3dcSWhitney Tsang if (auto *UserInst = dyn_cast<Instruction>(U.getUser())) 32836bdc3dcSWhitney Tsang if (UserInst != &InsertPoint && !DT.dominates(&InsertPoint, U)) 329ae8a8c2dSTsang Whitney W.H return false; 330ae8a8c2dSTsang Whitney W.H } else { 331ae8a8c2dSTsang Whitney W.H // When I is being moved backward, we need to make sure all its opernads 332ae8a8c2dSTsang Whitney W.H // dominates the InsertPoint. Or else, an operand may be undefined for I. 333ae8a8c2dSTsang Whitney W.H for (const Value *Op : I.operands()) 334ae8a8c2dSTsang Whitney W.H if (auto *OpInst = dyn_cast<Instruction>(Op)) 33578dc6498SWhitney Tsang if (&InsertPoint == OpInst || !OI.dominates(OpInst, &InsertPoint)) 336ae8a8c2dSTsang Whitney W.H return false; 337ae8a8c2dSTsang Whitney W.H } 338ae8a8c2dSTsang Whitney W.H 339ae8a8c2dSTsang Whitney W.H Instruction &StartInst = (MoveForward ? I : InsertPoint); 340ae8a8c2dSTsang Whitney W.H Instruction &EndInst = (MoveForward ? InsertPoint : I); 341ae8a8c2dSTsang Whitney W.H SmallPtrSet<Instruction *, 10> InstsToCheck; 342ae8a8c2dSTsang Whitney W.H collectInstructionsInBetween(StartInst, EndInst, InstsToCheck); 343ae8a8c2dSTsang Whitney W.H if (!MoveForward) 344ae8a8c2dSTsang Whitney W.H InstsToCheck.insert(&InsertPoint); 345ae8a8c2dSTsang Whitney W.H 346ae8a8c2dSTsang Whitney W.H // Check if there exists instructions which may throw, may synchonize, or may 347ae8a8c2dSTsang Whitney W.H // never return, from I to InsertPoint. 348ae8a8c2dSTsang Whitney W.H if (!isSafeToSpeculativelyExecute(&I)) 349ae8a8c2dSTsang Whitney W.H if (std::any_of(InstsToCheck.begin(), InstsToCheck.end(), 350ae8a8c2dSTsang Whitney W.H [](Instruction *I) { 351ae8a8c2dSTsang Whitney W.H if (I->mayThrow()) 352ae8a8c2dSTsang Whitney W.H return true; 353ae8a8c2dSTsang Whitney W.H 354ae8a8c2dSTsang Whitney W.H const CallBase *CB = dyn_cast<CallBase>(I); 355ae8a8c2dSTsang Whitney W.H if (!CB) 356ae8a8c2dSTsang Whitney W.H return false; 357ae8a8c2dSTsang Whitney W.H if (!CB->hasFnAttr(Attribute::WillReturn)) 358ae8a8c2dSTsang Whitney W.H return true; 359ae8a8c2dSTsang Whitney W.H if (!CB->hasFnAttr(Attribute::NoSync)) 360ae8a8c2dSTsang Whitney W.H return true; 361ae8a8c2dSTsang Whitney W.H 362ae8a8c2dSTsang Whitney W.H return false; 363ae8a8c2dSTsang Whitney W.H })) { 364ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, MayThrowException); 365ae8a8c2dSTsang Whitney W.H } 366ae8a8c2dSTsang Whitney W.H 367ae8a8c2dSTsang Whitney W.H // Check if I has any output/flow/anti dependences with instructions from \p 368ae8a8c2dSTsang Whitney W.H // StartInst to \p EndInst. 369ae8a8c2dSTsang Whitney W.H if (std::any_of(InstsToCheck.begin(), InstsToCheck.end(), 370ae8a8c2dSTsang Whitney W.H [&DI, &I](Instruction *CurInst) { 371ae8a8c2dSTsang Whitney W.H auto DepResult = DI.depends(&I, CurInst, true); 372ae8a8c2dSTsang Whitney W.H if (DepResult && 373ae8a8c2dSTsang Whitney W.H (DepResult->isOutput() || DepResult->isFlow() || 374ae8a8c2dSTsang Whitney W.H DepResult->isAnti())) 375ae8a8c2dSTsang Whitney W.H return true; 376ae8a8c2dSTsang Whitney W.H return false; 377ae8a8c2dSTsang Whitney W.H })) 378ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, HasDependences); 379ae8a8c2dSTsang Whitney W.H 380ae8a8c2dSTsang Whitney W.H return true; 381ae8a8c2dSTsang Whitney W.H } 38236bdc3dcSWhitney Tsang 383*da58e68fSWhitney Tsang bool llvm::isSafeToMoveBefore(BasicBlock &BB, Instruction &InsertPoint, 384*da58e68fSWhitney Tsang DominatorTree &DT, const PostDominatorTree &PDT, 385*da58e68fSWhitney Tsang DependenceInfo &DI) { 386*da58e68fSWhitney Tsang return llvm::all_of(BB, [&](Instruction &I) { 387*da58e68fSWhitney Tsang if (BB.getTerminator() == &I) 388*da58e68fSWhitney Tsang return true; 389*da58e68fSWhitney Tsang 390*da58e68fSWhitney Tsang return isSafeToMoveBefore(I, InsertPoint, DT, PDT, DI); 391*da58e68fSWhitney Tsang }); 392*da58e68fSWhitney Tsang } 393*da58e68fSWhitney Tsang 39478dc6498SWhitney Tsang void llvm::moveInstructionsToTheBeginning(BasicBlock &FromBB, BasicBlock &ToBB, 39578dc6498SWhitney Tsang DominatorTree &DT, 39678dc6498SWhitney Tsang const PostDominatorTree &PDT, 39778dc6498SWhitney Tsang DependenceInfo &DI) { 39836bdc3dcSWhitney Tsang for (auto It = ++FromBB.rbegin(); It != FromBB.rend();) { 39936bdc3dcSWhitney Tsang Instruction *MovePos = ToBB.getFirstNonPHIOrDbg(); 40036bdc3dcSWhitney Tsang Instruction &I = *It; 40136bdc3dcSWhitney Tsang // Increment the iterator before modifying FromBB. 40236bdc3dcSWhitney Tsang ++It; 40336bdc3dcSWhitney Tsang 40436bdc3dcSWhitney Tsang if (isSafeToMoveBefore(I, *MovePos, DT, PDT, DI)) 40536bdc3dcSWhitney Tsang I.moveBefore(MovePos); 40636bdc3dcSWhitney Tsang } 40736bdc3dcSWhitney Tsang } 408*da58e68fSWhitney Tsang 409*da58e68fSWhitney Tsang void llvm::moveInstructionsToTheEnd(BasicBlock &FromBB, BasicBlock &ToBB, 410*da58e68fSWhitney Tsang DominatorTree &DT, 411*da58e68fSWhitney Tsang const PostDominatorTree &PDT, 412*da58e68fSWhitney Tsang DependenceInfo &DI) { 413*da58e68fSWhitney Tsang Instruction *MovePos = ToBB.getTerminator(); 414*da58e68fSWhitney Tsang while (FromBB.size() > 1) { 415*da58e68fSWhitney Tsang Instruction &I = FromBB.front(); 416*da58e68fSWhitney Tsang if (isSafeToMoveBefore(I, *MovePos, DT, PDT, DI)) 417*da58e68fSWhitney Tsang I.moveBefore(MovePos); 418*da58e68fSWhitney Tsang } 419*da58e68fSWhitney Tsang } 420