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