1*ae8a8c2dSTsang Whitney W.H //===- CodeMoverUtils.cpp - CodeMover Utilities ----------------------------==// 2*ae8a8c2dSTsang Whitney W.H // 3*ae8a8c2dSTsang Whitney W.H // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*ae8a8c2dSTsang Whitney W.H // See https://llvm.org/LICENSE.txt for license information. 5*ae8a8c2dSTsang Whitney W.H // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*ae8a8c2dSTsang Whitney W.H // 7*ae8a8c2dSTsang Whitney W.H //===----------------------------------------------------------------------===// 8*ae8a8c2dSTsang Whitney W.H // 9*ae8a8c2dSTsang Whitney W.H // This family of functions perform movements on basic blocks, and instructions 10*ae8a8c2dSTsang Whitney W.H // contained within a function. 11*ae8a8c2dSTsang Whitney W.H // 12*ae8a8c2dSTsang Whitney W.H //===----------------------------------------------------------------------===// 13*ae8a8c2dSTsang Whitney W.H 14*ae8a8c2dSTsang Whitney W.H #include "llvm/Transforms/Utils/CodeMoverUtils.h" 15*ae8a8c2dSTsang Whitney W.H #include "llvm/ADT/Statistic.h" 16*ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/DependenceAnalysis.h" 17*ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/PostDominators.h" 18*ae8a8c2dSTsang Whitney W.H #include "llvm/Analysis/ValueTracking.h" 19*ae8a8c2dSTsang Whitney W.H #include "llvm/IR/Dominators.h" 20*ae8a8c2dSTsang Whitney W.H 21*ae8a8c2dSTsang Whitney W.H using namespace llvm; 22*ae8a8c2dSTsang Whitney W.H 23*ae8a8c2dSTsang Whitney W.H #define DEBUG_TYPE "codemover-utils" 24*ae8a8c2dSTsang Whitney W.H 25*ae8a8c2dSTsang Whitney W.H STATISTIC(HasDependences, 26*ae8a8c2dSTsang Whitney W.H "Cannot move across instructions that has memory dependences"); 27*ae8a8c2dSTsang Whitney W.H STATISTIC(MayThrowException, "Cannot move across instructions that may throw"); 28*ae8a8c2dSTsang Whitney W.H STATISTIC(NotControlFlowEquivalent, 29*ae8a8c2dSTsang Whitney W.H "Instructions are not control flow equivalent"); 30*ae8a8c2dSTsang Whitney W.H STATISTIC(NotMovedPHINode, "Movement of PHINodes are not supported"); 31*ae8a8c2dSTsang Whitney W.H STATISTIC(NotMovedTerminator, "Movement of Terminator are not supported"); 32*ae8a8c2dSTsang Whitney W.H 33*ae8a8c2dSTsang Whitney W.H bool llvm::isControlFlowEquivalent(const Instruction &I0, const Instruction &I1, 34*ae8a8c2dSTsang Whitney W.H const DominatorTree &DT, 35*ae8a8c2dSTsang Whitney W.H const PostDominatorTree &PDT) { 36*ae8a8c2dSTsang Whitney W.H const BasicBlock *BB0 = I0.getParent(); 37*ae8a8c2dSTsang Whitney W.H const BasicBlock *BB1 = I1.getParent(); 38*ae8a8c2dSTsang Whitney W.H return ((DT.dominates(BB0, BB1) && PDT.dominates(BB1, BB0)) || 39*ae8a8c2dSTsang Whitney W.H (PDT.dominates(BB0, BB1) && DT.dominates(BB1, BB0))); 40*ae8a8c2dSTsang Whitney W.H } 41*ae8a8c2dSTsang Whitney W.H 42*ae8a8c2dSTsang Whitney W.H static bool reportInvalidCandidate(const Instruction &I, 43*ae8a8c2dSTsang Whitney W.H llvm::Statistic &Stat) { 44*ae8a8c2dSTsang Whitney W.H ++Stat; 45*ae8a8c2dSTsang Whitney W.H LLVM_DEBUG(dbgs() << "Unable to move instruction: " << I << ". " 46*ae8a8c2dSTsang Whitney W.H << Stat.getDesc()); 47*ae8a8c2dSTsang Whitney W.H return false; 48*ae8a8c2dSTsang Whitney W.H } 49*ae8a8c2dSTsang Whitney W.H 50*ae8a8c2dSTsang Whitney W.H /// Collect all instructions in between \p StartInst and \p EndInst, and store 51*ae8a8c2dSTsang Whitney W.H /// them in \p InBetweenInsts. 52*ae8a8c2dSTsang Whitney W.H static void 53*ae8a8c2dSTsang Whitney W.H collectInstructionsInBetween(Instruction &StartInst, const Instruction &EndInst, 54*ae8a8c2dSTsang Whitney W.H SmallPtrSetImpl<Instruction *> &InBetweenInsts) { 55*ae8a8c2dSTsang Whitney W.H assert(InBetweenInsts.empty() && "Expecting InBetweenInsts to be empty"); 56*ae8a8c2dSTsang Whitney W.H 57*ae8a8c2dSTsang Whitney W.H /// Get the next instructions of \p I, and push them to \p WorkList. 58*ae8a8c2dSTsang Whitney W.H auto getNextInsts = [](Instruction &I, 59*ae8a8c2dSTsang Whitney W.H SmallPtrSetImpl<Instruction *> &WorkList) { 60*ae8a8c2dSTsang Whitney W.H if (Instruction *NextInst = I.getNextNode()) 61*ae8a8c2dSTsang Whitney W.H WorkList.insert(NextInst); 62*ae8a8c2dSTsang Whitney W.H else { 63*ae8a8c2dSTsang Whitney W.H assert(I.isTerminator() && "Expecting a terminator instruction"); 64*ae8a8c2dSTsang Whitney W.H for (BasicBlock *Succ : successors(&I)) 65*ae8a8c2dSTsang Whitney W.H WorkList.insert(&Succ->front()); 66*ae8a8c2dSTsang Whitney W.H } 67*ae8a8c2dSTsang Whitney W.H }; 68*ae8a8c2dSTsang Whitney W.H 69*ae8a8c2dSTsang Whitney W.H SmallPtrSet<Instruction *, 10> WorkList; 70*ae8a8c2dSTsang Whitney W.H getNextInsts(StartInst, WorkList); 71*ae8a8c2dSTsang Whitney W.H while (!WorkList.empty()) { 72*ae8a8c2dSTsang Whitney W.H Instruction *CurInst = *WorkList.begin(); 73*ae8a8c2dSTsang Whitney W.H WorkList.erase(CurInst); 74*ae8a8c2dSTsang Whitney W.H 75*ae8a8c2dSTsang Whitney W.H if (CurInst == &EndInst) 76*ae8a8c2dSTsang Whitney W.H continue; 77*ae8a8c2dSTsang Whitney W.H 78*ae8a8c2dSTsang Whitney W.H if (!InBetweenInsts.insert(CurInst).second) 79*ae8a8c2dSTsang Whitney W.H continue; 80*ae8a8c2dSTsang Whitney W.H 81*ae8a8c2dSTsang Whitney W.H getNextInsts(*CurInst, WorkList); 82*ae8a8c2dSTsang Whitney W.H } 83*ae8a8c2dSTsang Whitney W.H } 84*ae8a8c2dSTsang Whitney W.H 85*ae8a8c2dSTsang Whitney W.H bool llvm::isSafeToMoveBefore(Instruction &I, Instruction &InsertPoint, 86*ae8a8c2dSTsang Whitney W.H const DominatorTree &DT, 87*ae8a8c2dSTsang Whitney W.H const PostDominatorTree &PDT, 88*ae8a8c2dSTsang Whitney W.H DependenceInfo &DI) { 89*ae8a8c2dSTsang Whitney W.H // Cannot move itself before itself. 90*ae8a8c2dSTsang Whitney W.H if (&I == &InsertPoint) 91*ae8a8c2dSTsang Whitney W.H return false; 92*ae8a8c2dSTsang Whitney W.H 93*ae8a8c2dSTsang Whitney W.H // Not moved. 94*ae8a8c2dSTsang Whitney W.H if (I.getNextNode() == &InsertPoint) 95*ae8a8c2dSTsang Whitney W.H return true; 96*ae8a8c2dSTsang Whitney W.H 97*ae8a8c2dSTsang Whitney W.H if (isa<PHINode>(I) || isa<PHINode>(InsertPoint)) 98*ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, NotMovedPHINode); 99*ae8a8c2dSTsang Whitney W.H 100*ae8a8c2dSTsang Whitney W.H if (I.isTerminator()) 101*ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, NotMovedTerminator); 102*ae8a8c2dSTsang Whitney W.H 103*ae8a8c2dSTsang Whitney W.H // TODO remove this limitation. 104*ae8a8c2dSTsang Whitney W.H if (!isControlFlowEquivalent(I, InsertPoint, DT, PDT)) 105*ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, NotControlFlowEquivalent); 106*ae8a8c2dSTsang Whitney W.H 107*ae8a8c2dSTsang Whitney W.H // As I and InsertPoint are control flow equivalent, if I dominates 108*ae8a8c2dSTsang Whitney W.H // InsertPoint, then I comes before InsertPoint. 109*ae8a8c2dSTsang Whitney W.H const bool MoveForward = DT.dominates(&I, &InsertPoint); 110*ae8a8c2dSTsang Whitney W.H if (MoveForward) { 111*ae8a8c2dSTsang Whitney W.H // When I is being moved forward, we need to make sure the InsertPoint 112*ae8a8c2dSTsang Whitney W.H // dominates every users. Or else, a user may be using an undefined I. 113*ae8a8c2dSTsang Whitney W.H for (const Value *User : I.users()) 114*ae8a8c2dSTsang Whitney W.H if (auto *UserInst = dyn_cast<Instruction>(User)) 115*ae8a8c2dSTsang Whitney W.H if (!DT.dominates(&InsertPoint, UserInst)) 116*ae8a8c2dSTsang Whitney W.H return false; 117*ae8a8c2dSTsang Whitney W.H } else { 118*ae8a8c2dSTsang Whitney W.H // When I is being moved backward, we need to make sure all its opernads 119*ae8a8c2dSTsang Whitney W.H // dominates the InsertPoint. Or else, an operand may be undefined for I. 120*ae8a8c2dSTsang Whitney W.H for (const Value *Op : I.operands()) 121*ae8a8c2dSTsang Whitney W.H if (auto *OpInst = dyn_cast<Instruction>(Op)) 122*ae8a8c2dSTsang Whitney W.H if (&InsertPoint == OpInst || !DT.dominates(OpInst, &InsertPoint)) 123*ae8a8c2dSTsang Whitney W.H return false; 124*ae8a8c2dSTsang Whitney W.H } 125*ae8a8c2dSTsang Whitney W.H 126*ae8a8c2dSTsang Whitney W.H Instruction &StartInst = (MoveForward ? I : InsertPoint); 127*ae8a8c2dSTsang Whitney W.H Instruction &EndInst = (MoveForward ? InsertPoint : I); 128*ae8a8c2dSTsang Whitney W.H SmallPtrSet<Instruction *, 10> InstsToCheck; 129*ae8a8c2dSTsang Whitney W.H collectInstructionsInBetween(StartInst, EndInst, InstsToCheck); 130*ae8a8c2dSTsang Whitney W.H if (!MoveForward) 131*ae8a8c2dSTsang Whitney W.H InstsToCheck.insert(&InsertPoint); 132*ae8a8c2dSTsang Whitney W.H 133*ae8a8c2dSTsang Whitney W.H // Check if there exists instructions which may throw, may synchonize, or may 134*ae8a8c2dSTsang Whitney W.H // never return, from I to InsertPoint. 135*ae8a8c2dSTsang Whitney W.H if (!isSafeToSpeculativelyExecute(&I)) 136*ae8a8c2dSTsang Whitney W.H if (std::any_of(InstsToCheck.begin(), InstsToCheck.end(), 137*ae8a8c2dSTsang Whitney W.H [](Instruction *I) { 138*ae8a8c2dSTsang Whitney W.H if (I->mayThrow()) 139*ae8a8c2dSTsang Whitney W.H return true; 140*ae8a8c2dSTsang Whitney W.H 141*ae8a8c2dSTsang Whitney W.H const CallBase *CB = dyn_cast<CallBase>(I); 142*ae8a8c2dSTsang Whitney W.H if (!CB) 143*ae8a8c2dSTsang Whitney W.H return false; 144*ae8a8c2dSTsang Whitney W.H if (!CB->hasFnAttr(Attribute::WillReturn)) 145*ae8a8c2dSTsang Whitney W.H return true; 146*ae8a8c2dSTsang Whitney W.H if (!CB->hasFnAttr(Attribute::NoSync)) 147*ae8a8c2dSTsang Whitney W.H return true; 148*ae8a8c2dSTsang Whitney W.H 149*ae8a8c2dSTsang Whitney W.H return false; 150*ae8a8c2dSTsang Whitney W.H })) { 151*ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, MayThrowException); 152*ae8a8c2dSTsang Whitney W.H } 153*ae8a8c2dSTsang Whitney W.H 154*ae8a8c2dSTsang Whitney W.H // Check if I has any output/flow/anti dependences with instructions from \p 155*ae8a8c2dSTsang Whitney W.H // StartInst to \p EndInst. 156*ae8a8c2dSTsang Whitney W.H if (std::any_of(InstsToCheck.begin(), InstsToCheck.end(), 157*ae8a8c2dSTsang Whitney W.H [&DI, &I](Instruction *CurInst) { 158*ae8a8c2dSTsang Whitney W.H auto DepResult = DI.depends(&I, CurInst, true); 159*ae8a8c2dSTsang Whitney W.H if (DepResult && 160*ae8a8c2dSTsang Whitney W.H (DepResult->isOutput() || DepResult->isFlow() || 161*ae8a8c2dSTsang Whitney W.H DepResult->isAnti())) 162*ae8a8c2dSTsang Whitney W.H return true; 163*ae8a8c2dSTsang Whitney W.H return false; 164*ae8a8c2dSTsang Whitney W.H })) 165*ae8a8c2dSTsang Whitney W.H return reportInvalidCandidate(I, HasDependences); 166*ae8a8c2dSTsang Whitney W.H 167*ae8a8c2dSTsang Whitney W.H return true; 168*ae8a8c2dSTsang Whitney W.H } 169