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" 15ae8a8c2dSTsang Whitney W.H #include "llvm/ADT/Statistic.h" 16ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/DependenceAnalysis.h" 17ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/PostDominators.h" 18ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/ValueTracking.h" 19ae8a8c2dSTsang Whitney W.H #include "llvm/IR/Dominators.h" 20ae8a8c2dSTsang Whitney W.H 21ae8a8c2dSTsang Whitney W.H using namespace llvm; 22ae8a8c2dSTsang Whitney W.H 23ae8a8c2dSTsang Whitney W.H #define DEBUG_TYPE "codemover-utils" 24ae8a8c2dSTsang Whitney W.H 25ae8a8c2dSTsang Whitney W.H STATISTIC(HasDependences, 26ae8a8c2dSTsang Whitney W.H "Cannot move across instructions that has memory dependences"); 27ae8a8c2dSTsang Whitney W.H STATISTIC(MayThrowException, "Cannot move across instructions that may throw"); 28ae8a8c2dSTsang Whitney W.H STATISTIC(NotControlFlowEquivalent, 29ae8a8c2dSTsang Whitney W.H "Instructions are not control flow equivalent"); 30ae8a8c2dSTsang Whitney W.H STATISTIC(NotMovedPHINode, "Movement of PHINodes are not supported"); 31ae8a8c2dSTsang Whitney W.H STATISTIC(NotMovedTerminator, "Movement of Terminator are not supported"); 32ae8a8c2dSTsang Whitney W.H 33ae8a8c2dSTsang Whitney W.H bool llvm::isControlFlowEquivalent(const Instruction &I0, const Instruction &I1, 34ae8a8c2dSTsang Whitney W.H const DominatorTree &DT, 35ae8a8c2dSTsang Whitney W.H const PostDominatorTree &PDT) { 36aaf7f05aSWhitney Tsang return isControlFlowEquivalent(*I0.getParent(), *I1.getParent(), DT, PDT); 37aaf7f05aSWhitney Tsang } 38aaf7f05aSWhitney Tsang 39aaf7f05aSWhitney Tsang bool llvm::isControlFlowEquivalent(const BasicBlock &BB0, const BasicBlock &BB1, 40aaf7f05aSWhitney Tsang const DominatorTree &DT, 41aaf7f05aSWhitney Tsang const PostDominatorTree &PDT) { 42aaf7f05aSWhitney Tsang if (&BB0 == &BB1) 43aaf7f05aSWhitney Tsang return true; 44aaf7f05aSWhitney Tsang 45aaf7f05aSWhitney Tsang return ((DT.dominates(&BB0, &BB1) && PDT.dominates(&BB1, &BB0)) || 46aaf7f05aSWhitney Tsang (PDT.dominates(&BB0, &BB1) && DT.dominates(&BB1, &BB0))); 47ae8a8c2dSTsang Whitney W.H } 48ae8a8c2dSTsang Whitney W.H 49ae8a8c2dSTsang Whitney W.H static bool reportInvalidCandidate(const Instruction &I, 50ae8a8c2dSTsang Whitney W.H llvm::Statistic &Stat) { 51ae8a8c2dSTsang Whitney W.H ++Stat; 52ae8a8c2dSTsang Whitney W.H LLVM_DEBUG(dbgs() << "Unable to move instruction: " << I << ". " 53ae8a8c2dSTsang Whitney W.H << Stat.getDesc()); 54ae8a8c2dSTsang Whitney W.H return false; 55ae8a8c2dSTsang Whitney W.H } 56ae8a8c2dSTsang Whitney W.H 57ae8a8c2dSTsang Whitney W.H /// Collect all instructions in between \p StartInst and \p EndInst, and store 58ae8a8c2dSTsang Whitney W.H /// them in \p InBetweenInsts. 59ae8a8c2dSTsang Whitney W.H static void 60ae8a8c2dSTsang Whitney W.H collectInstructionsInBetween(Instruction &StartInst, const Instruction &EndInst, 61ae8a8c2dSTsang Whitney W.H SmallPtrSetImpl<Instruction *> &InBetweenInsts) { 62ae8a8c2dSTsang Whitney W.H assert(InBetweenInsts.empty() && "Expecting InBetweenInsts to be empty"); 63ae8a8c2dSTsang Whitney W.H 64ae8a8c2dSTsang Whitney W.H /// Get the next instructions of \p I, and push them to \p WorkList. 65ae8a8c2dSTsang Whitney W.H auto getNextInsts = [](Instruction &I, 66ae8a8c2dSTsang Whitney W.H SmallPtrSetImpl<Instruction *> &WorkList) { 67ae8a8c2dSTsang Whitney W.H if (Instruction *NextInst = I.getNextNode()) 68ae8a8c2dSTsang Whitney W.H WorkList.insert(NextInst); 69ae8a8c2dSTsang Whitney W.H else { 70ae8a8c2dSTsang Whitney W.H assert(I.isTerminator() && "Expecting a terminator instruction"); 71ae8a8c2dSTsang Whitney W.H for (BasicBlock *Succ : successors(&I)) 72ae8a8c2dSTsang Whitney W.H WorkList.insert(&Succ->front()); 73ae8a8c2dSTsang Whitney W.H } 74ae8a8c2dSTsang Whitney W.H }; 75ae8a8c2dSTsang Whitney W.H 76ae8a8c2dSTsang Whitney W.H SmallPtrSet<Instruction *, 10> WorkList; 77ae8a8c2dSTsang Whitney W.H getNextInsts(StartInst, WorkList); 78ae8a8c2dSTsang Whitney W.H while (!WorkList.empty()) { 79ae8a8c2dSTsang Whitney W.H Instruction *CurInst = *WorkList.begin(); 80ae8a8c2dSTsang Whitney W.H WorkList.erase(CurInst); 81ae8a8c2dSTsang Whitney W.H 82ae8a8c2dSTsang Whitney W.H if (CurInst == &EndInst) 83ae8a8c2dSTsang Whitney W.H continue; 84ae8a8c2dSTsang Whitney W.H 85ae8a8c2dSTsang Whitney W.H if (!InBetweenInsts.insert(CurInst).second) 86ae8a8c2dSTsang Whitney W.H continue; 87ae8a8c2dSTsang Whitney W.H 88ae8a8c2dSTsang Whitney W.H getNextInsts(*CurInst, WorkList); 89ae8a8c2dSTsang Whitney W.H } 90ae8a8c2dSTsang Whitney W.H } 91ae8a8c2dSTsang Whitney W.H 92ae8a8c2dSTsang Whitney W.H bool llvm::isSafeToMoveBefore(Instruction &I, Instruction &InsertPoint, 93ae8a8c2dSTsang Whitney W.H const DominatorTree &DT, 94ae8a8c2dSTsang Whitney W.H const PostDominatorTree &PDT, 95ae8a8c2dSTsang Whitney W.H DependenceInfo &DI) { 96ae8a8c2dSTsang Whitney W.H // Cannot move itself before itself. 97ae8a8c2dSTsang Whitney W.H if (&I == &InsertPoint) 98ae8a8c2dSTsang Whitney W.H return false; 99ae8a8c2dSTsang Whitney W.H 100ae8a8c2dSTsang Whitney W.H // Not moved. 101ae8a8c2dSTsang Whitney W.H if (I.getNextNode() == &InsertPoint) 102ae8a8c2dSTsang Whitney W.H return true; 103ae8a8c2dSTsang Whitney W.H 104ae8a8c2dSTsang Whitney W.H if (isa<PHINode>(I) || isa<PHINode>(InsertPoint)) 105ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, NotMovedPHINode); 106ae8a8c2dSTsang Whitney W.H 107ae8a8c2dSTsang Whitney W.H if (I.isTerminator()) 108ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, NotMovedTerminator); 109ae8a8c2dSTsang Whitney W.H 110ae8a8c2dSTsang Whitney W.H // TODO remove this limitation. 111ae8a8c2dSTsang Whitney W.H if (!isControlFlowEquivalent(I, InsertPoint, DT, PDT)) 112ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, NotControlFlowEquivalent); 113ae8a8c2dSTsang Whitney W.H 114ae8a8c2dSTsang Whitney W.H // As I and InsertPoint are control flow equivalent, if I dominates 115ae8a8c2dSTsang Whitney W.H // InsertPoint, then I comes before InsertPoint. 116ae8a8c2dSTsang Whitney W.H const bool MoveForward = DT.dominates(&I, &InsertPoint); 117ae8a8c2dSTsang Whitney W.H if (MoveForward) { 118ae8a8c2dSTsang Whitney W.H // When I is being moved forward, we need to make sure the InsertPoint 119ae8a8c2dSTsang Whitney W.H // dominates every users. Or else, a user may be using an undefined I. 120*36bdc3dcSWhitney Tsang for (const Use &U : I.uses()) 121*36bdc3dcSWhitney Tsang if (auto *UserInst = dyn_cast<Instruction>(U.getUser())) 122*36bdc3dcSWhitney Tsang if (UserInst != &InsertPoint && !DT.dominates(&InsertPoint, U)) 123ae8a8c2dSTsang Whitney W.H return false; 124ae8a8c2dSTsang Whitney W.H } else { 125ae8a8c2dSTsang Whitney W.H // When I is being moved backward, we need to make sure all its opernads 126ae8a8c2dSTsang Whitney W.H // dominates the InsertPoint. Or else, an operand may be undefined for I. 127ae8a8c2dSTsang Whitney W.H for (const Value *Op : I.operands()) 128ae8a8c2dSTsang Whitney W.H if (auto *OpInst = dyn_cast<Instruction>(Op)) 129ae8a8c2dSTsang Whitney W.H if (&InsertPoint == OpInst || !DT.dominates(OpInst, &InsertPoint)) 130ae8a8c2dSTsang Whitney W.H return false; 131ae8a8c2dSTsang Whitney W.H } 132ae8a8c2dSTsang Whitney W.H 133ae8a8c2dSTsang Whitney W.H Instruction &StartInst = (MoveForward ? I : InsertPoint); 134ae8a8c2dSTsang Whitney W.H Instruction &EndInst = (MoveForward ? InsertPoint : I); 135ae8a8c2dSTsang Whitney W.H SmallPtrSet<Instruction *, 10> InstsToCheck; 136ae8a8c2dSTsang Whitney W.H collectInstructionsInBetween(StartInst, EndInst, InstsToCheck); 137ae8a8c2dSTsang Whitney W.H if (!MoveForward) 138ae8a8c2dSTsang Whitney W.H InstsToCheck.insert(&InsertPoint); 139ae8a8c2dSTsang Whitney W.H 140ae8a8c2dSTsang Whitney W.H // Check if there exists instructions which may throw, may synchonize, or may 141ae8a8c2dSTsang Whitney W.H // never return, from I to InsertPoint. 142ae8a8c2dSTsang Whitney W.H if (!isSafeToSpeculativelyExecute(&I)) 143ae8a8c2dSTsang Whitney W.H if (std::any_of(InstsToCheck.begin(), InstsToCheck.end(), 144ae8a8c2dSTsang Whitney W.H [](Instruction *I) { 145ae8a8c2dSTsang Whitney W.H if (I->mayThrow()) 146ae8a8c2dSTsang Whitney W.H return true; 147ae8a8c2dSTsang Whitney W.H 148ae8a8c2dSTsang Whitney W.H const CallBase *CB = dyn_cast<CallBase>(I); 149ae8a8c2dSTsang Whitney W.H if (!CB) 150ae8a8c2dSTsang Whitney W.H return false; 151ae8a8c2dSTsang Whitney W.H if (!CB->hasFnAttr(Attribute::WillReturn)) 152ae8a8c2dSTsang Whitney W.H return true; 153ae8a8c2dSTsang Whitney W.H if (!CB->hasFnAttr(Attribute::NoSync)) 154ae8a8c2dSTsang Whitney W.H return true; 155ae8a8c2dSTsang Whitney W.H 156ae8a8c2dSTsang Whitney W.H return false; 157ae8a8c2dSTsang Whitney W.H })) { 158ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, MayThrowException); 159ae8a8c2dSTsang Whitney W.H } 160ae8a8c2dSTsang Whitney W.H 161ae8a8c2dSTsang Whitney W.H // Check if I has any output/flow/anti dependences with instructions from \p 162ae8a8c2dSTsang Whitney W.H // StartInst to \p EndInst. 163ae8a8c2dSTsang Whitney W.H if (std::any_of(InstsToCheck.begin(), InstsToCheck.end(), 164ae8a8c2dSTsang Whitney W.H [&DI, &I](Instruction *CurInst) { 165ae8a8c2dSTsang Whitney W.H auto DepResult = DI.depends(&I, CurInst, true); 166ae8a8c2dSTsang Whitney W.H if (DepResult && 167ae8a8c2dSTsang Whitney W.H (DepResult->isOutput() || DepResult->isFlow() || 168ae8a8c2dSTsang Whitney W.H DepResult->isAnti())) 169ae8a8c2dSTsang Whitney W.H return true; 170ae8a8c2dSTsang Whitney W.H return false; 171ae8a8c2dSTsang Whitney W.H })) 172ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, HasDependences); 173ae8a8c2dSTsang Whitney W.H 174ae8a8c2dSTsang Whitney W.H return true; 175ae8a8c2dSTsang Whitney W.H } 176*36bdc3dcSWhitney Tsang 177*36bdc3dcSWhitney Tsang void llvm::moveInstsBottomUp(BasicBlock &FromBB, BasicBlock &ToBB, 178*36bdc3dcSWhitney Tsang const DominatorTree &DT, 179*36bdc3dcSWhitney Tsang const PostDominatorTree &PDT, DependenceInfo &DI) { 180*36bdc3dcSWhitney Tsang for (auto It = ++FromBB.rbegin(); It != FromBB.rend();) { 181*36bdc3dcSWhitney Tsang Instruction *MovePos = ToBB.getFirstNonPHIOrDbg(); 182*36bdc3dcSWhitney Tsang Instruction &I = *It; 183*36bdc3dcSWhitney Tsang // Increment the iterator before modifying FromBB. 184*36bdc3dcSWhitney Tsang ++It; 185*36bdc3dcSWhitney Tsang 186*36bdc3dcSWhitney Tsang if (isSafeToMoveBefore(I, *MovePos, DT, PDT, DI)) 187*36bdc3dcSWhitney Tsang I.moveBefore(MovePos); 188*36bdc3dcSWhitney Tsang } 189*36bdc3dcSWhitney Tsang } 190