1*06c3fb27SDimitry Andric //===-- CallBrPrepare - Prepare callbr for code generation ----------------===// 2*06c3fb27SDimitry Andric // 3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*06c3fb27SDimitry Andric // 7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 8*06c3fb27SDimitry Andric // 9*06c3fb27SDimitry Andric // This pass lowers callbrs in LLVM IR in order to to assist SelectionDAG's 10*06c3fb27SDimitry Andric // codegen. 11*06c3fb27SDimitry Andric // 12*06c3fb27SDimitry Andric // In particular, this pass assists in inserting register copies for the output 13*06c3fb27SDimitry Andric // values of a callbr along the edges leading to the indirect target blocks. 14*06c3fb27SDimitry Andric // Though the output SSA value is defined by the callbr instruction itself in 15*06c3fb27SDimitry Andric // the IR representation, the value cannot be copied to the appropriate virtual 16*06c3fb27SDimitry Andric // registers prior to jumping to an indirect label, since the jump occurs 17*06c3fb27SDimitry Andric // within the user-provided assembly blob. 18*06c3fb27SDimitry Andric // 19*06c3fb27SDimitry Andric // Instead, those copies must occur separately at the beginning of each 20*06c3fb27SDimitry Andric // indirect target. That requires that we create a separate SSA definition in 21*06c3fb27SDimitry Andric // each of them (via llvm.callbr.landingpad), and may require splitting 22*06c3fb27SDimitry Andric // critical edges so we have a location to place the intrinsic. Finally, we 23*06c3fb27SDimitry Andric // remap users of the original callbr output SSA value to instead point to the 24*06c3fb27SDimitry Andric // appropriate llvm.callbr.landingpad value. 25*06c3fb27SDimitry Andric // 26*06c3fb27SDimitry Andric // Ideally, this could be done inside SelectionDAG, or in the 27*06c3fb27SDimitry Andric // MachineInstruction representation, without the use of an IR-level intrinsic. 28*06c3fb27SDimitry Andric // But, within the current framework, it’s simpler to implement as an IR pass. 29*06c3fb27SDimitry Andric // (If support for callbr in GlobalISel is implemented, it’s worth considering 30*06c3fb27SDimitry Andric // whether this is still required.) 31*06c3fb27SDimitry Andric // 32*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 33*06c3fb27SDimitry Andric 34*06c3fb27SDimitry Andric #include "llvm/ADT/ArrayRef.h" 35*06c3fb27SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 36*06c3fb27SDimitry Andric #include "llvm/ADT/SmallVector.h" 37*06c3fb27SDimitry Andric #include "llvm/ADT/iterator.h" 38*06c3fb27SDimitry Andric #include "llvm/Analysis/CFG.h" 39*06c3fb27SDimitry Andric #include "llvm/CodeGen/Passes.h" 40*06c3fb27SDimitry Andric #include "llvm/IR/BasicBlock.h" 41*06c3fb27SDimitry Andric #include "llvm/IR/Dominators.h" 42*06c3fb27SDimitry Andric #include "llvm/IR/Function.h" 43*06c3fb27SDimitry Andric #include "llvm/IR/IRBuilder.h" 44*06c3fb27SDimitry Andric #include "llvm/IR/Instructions.h" 45*06c3fb27SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 46*06c3fb27SDimitry Andric #include "llvm/IR/Intrinsics.h" 47*06c3fb27SDimitry Andric #include "llvm/InitializePasses.h" 48*06c3fb27SDimitry Andric #include "llvm/Pass.h" 49*06c3fb27SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h" 50*06c3fb27SDimitry Andric #include "llvm/Transforms/Utils/SSAUpdater.h" 51*06c3fb27SDimitry Andric 52*06c3fb27SDimitry Andric using namespace llvm; 53*06c3fb27SDimitry Andric 54*06c3fb27SDimitry Andric #define DEBUG_TYPE "callbrprepare" 55*06c3fb27SDimitry Andric 56*06c3fb27SDimitry Andric namespace { 57*06c3fb27SDimitry Andric 58*06c3fb27SDimitry Andric class CallBrPrepare : public FunctionPass { 59*06c3fb27SDimitry Andric bool SplitCriticalEdges(ArrayRef<CallBrInst *> CBRs, DominatorTree &DT); 60*06c3fb27SDimitry Andric bool InsertIntrinsicCalls(ArrayRef<CallBrInst *> CBRs, 61*06c3fb27SDimitry Andric DominatorTree &DT) const; 62*06c3fb27SDimitry Andric void UpdateSSA(DominatorTree &DT, CallBrInst *CBR, CallInst *Intrinsic, 63*06c3fb27SDimitry Andric SSAUpdater &SSAUpdate) const; 64*06c3fb27SDimitry Andric 65*06c3fb27SDimitry Andric public: 66*06c3fb27SDimitry Andric CallBrPrepare() : FunctionPass(ID) {} 67*06c3fb27SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 68*06c3fb27SDimitry Andric bool runOnFunction(Function &Fn) override; 69*06c3fb27SDimitry Andric static char ID; 70*06c3fb27SDimitry Andric }; 71*06c3fb27SDimitry Andric 72*06c3fb27SDimitry Andric } // end anonymous namespace 73*06c3fb27SDimitry Andric 74*06c3fb27SDimitry Andric char CallBrPrepare::ID = 0; 75*06c3fb27SDimitry Andric INITIALIZE_PASS_BEGIN(CallBrPrepare, DEBUG_TYPE, "Prepare callbr", false, false) 76*06c3fb27SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 77*06c3fb27SDimitry Andric INITIALIZE_PASS_END(CallBrPrepare, DEBUG_TYPE, "Prepare callbr", false, false) 78*06c3fb27SDimitry Andric 79*06c3fb27SDimitry Andric FunctionPass *llvm::createCallBrPass() { return new CallBrPrepare(); } 80*06c3fb27SDimitry Andric 81*06c3fb27SDimitry Andric void CallBrPrepare::getAnalysisUsage(AnalysisUsage &AU) const { 82*06c3fb27SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>(); 83*06c3fb27SDimitry Andric } 84*06c3fb27SDimitry Andric 85*06c3fb27SDimitry Andric static SmallVector<CallBrInst *, 2> FindCallBrs(Function &Fn) { 86*06c3fb27SDimitry Andric SmallVector<CallBrInst *, 2> CBRs; 87*06c3fb27SDimitry Andric for (BasicBlock &BB : Fn) 88*06c3fb27SDimitry Andric if (auto *CBR = dyn_cast<CallBrInst>(BB.getTerminator())) 89*06c3fb27SDimitry Andric if (!CBR->getType()->isVoidTy() && !CBR->use_empty()) 90*06c3fb27SDimitry Andric CBRs.push_back(CBR); 91*06c3fb27SDimitry Andric return CBRs; 92*06c3fb27SDimitry Andric } 93*06c3fb27SDimitry Andric 94*06c3fb27SDimitry Andric bool CallBrPrepare::SplitCriticalEdges(ArrayRef<CallBrInst *> CBRs, 95*06c3fb27SDimitry Andric DominatorTree &DT) { 96*06c3fb27SDimitry Andric bool Changed = false; 97*06c3fb27SDimitry Andric CriticalEdgeSplittingOptions Options(&DT); 98*06c3fb27SDimitry Andric Options.setMergeIdenticalEdges(); 99*06c3fb27SDimitry Andric 100*06c3fb27SDimitry Andric // The indirect destination might be duplicated between another parameter... 101*06c3fb27SDimitry Andric // %0 = callbr ... [label %x, label %x] 102*06c3fb27SDimitry Andric // ...hence MergeIdenticalEdges and AllowIndentical edges, but we don't need 103*06c3fb27SDimitry Andric // to split the default destination if it's duplicated between an indirect 104*06c3fb27SDimitry Andric // destination... 105*06c3fb27SDimitry Andric // %1 = callbr ... to label %x [label %x] 106*06c3fb27SDimitry Andric // ...hence starting at 1 and checking against successor 0 (aka the default 107*06c3fb27SDimitry Andric // destination). 108*06c3fb27SDimitry Andric for (CallBrInst *CBR : CBRs) 109*06c3fb27SDimitry Andric for (unsigned i = 1, e = CBR->getNumSuccessors(); i != e; ++i) 110*06c3fb27SDimitry Andric if (CBR->getSuccessor(i) == CBR->getSuccessor(0) || 111*06c3fb27SDimitry Andric isCriticalEdge(CBR, i, /*AllowIdenticalEdges*/ true)) 112*06c3fb27SDimitry Andric if (SplitKnownCriticalEdge(CBR, i, Options)) 113*06c3fb27SDimitry Andric Changed = true; 114*06c3fb27SDimitry Andric return Changed; 115*06c3fb27SDimitry Andric } 116*06c3fb27SDimitry Andric 117*06c3fb27SDimitry Andric bool CallBrPrepare::InsertIntrinsicCalls(ArrayRef<CallBrInst *> CBRs, 118*06c3fb27SDimitry Andric DominatorTree &DT) const { 119*06c3fb27SDimitry Andric bool Changed = false; 120*06c3fb27SDimitry Andric SmallPtrSet<const BasicBlock *, 4> Visited; 121*06c3fb27SDimitry Andric IRBuilder<> Builder(CBRs[0]->getContext()); 122*06c3fb27SDimitry Andric for (CallBrInst *CBR : CBRs) { 123*06c3fb27SDimitry Andric if (!CBR->getNumIndirectDests()) 124*06c3fb27SDimitry Andric continue; 125*06c3fb27SDimitry Andric 126*06c3fb27SDimitry Andric SSAUpdater SSAUpdate; 127*06c3fb27SDimitry Andric SSAUpdate.Initialize(CBR->getType(), CBR->getName()); 128*06c3fb27SDimitry Andric SSAUpdate.AddAvailableValue(CBR->getParent(), CBR); 129*06c3fb27SDimitry Andric SSAUpdate.AddAvailableValue(CBR->getDefaultDest(), CBR); 130*06c3fb27SDimitry Andric 131*06c3fb27SDimitry Andric for (BasicBlock *IndDest : CBR->getIndirectDests()) { 132*06c3fb27SDimitry Andric if (!Visited.insert(IndDest).second) 133*06c3fb27SDimitry Andric continue; 134*06c3fb27SDimitry Andric Builder.SetInsertPoint(&*IndDest->begin()); 135*06c3fb27SDimitry Andric CallInst *Intrinsic = Builder.CreateIntrinsic( 136*06c3fb27SDimitry Andric CBR->getType(), Intrinsic::callbr_landingpad, {CBR}); 137*06c3fb27SDimitry Andric SSAUpdate.AddAvailableValue(IndDest, Intrinsic); 138*06c3fb27SDimitry Andric UpdateSSA(DT, CBR, Intrinsic, SSAUpdate); 139*06c3fb27SDimitry Andric Changed = true; 140*06c3fb27SDimitry Andric } 141*06c3fb27SDimitry Andric } 142*06c3fb27SDimitry Andric return Changed; 143*06c3fb27SDimitry Andric } 144*06c3fb27SDimitry Andric 145*06c3fb27SDimitry Andric static bool IsInSameBasicBlock(const Use &U, const BasicBlock *BB) { 146*06c3fb27SDimitry Andric const auto *I = dyn_cast<Instruction>(U.getUser()); 147*06c3fb27SDimitry Andric return I && I->getParent() == BB; 148*06c3fb27SDimitry Andric } 149*06c3fb27SDimitry Andric 150*06c3fb27SDimitry Andric #ifndef NDEBUG 151*06c3fb27SDimitry Andric static void PrintDebugDomInfo(const DominatorTree &DT, const Use &U, 152*06c3fb27SDimitry Andric const BasicBlock *BB, bool IsDefaultDest) { 153*06c3fb27SDimitry Andric if (!isa<Instruction>(U.getUser())) 154*06c3fb27SDimitry Andric return; 155*06c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "Use: " << *U.getUser() << ", in block " 156*06c3fb27SDimitry Andric << cast<Instruction>(U.getUser())->getParent()->getName() 157*06c3fb27SDimitry Andric << ", is " << (DT.dominates(BB, U) ? "" : "NOT ") 158*06c3fb27SDimitry Andric << "dominated by " << BB->getName() << " (" 159*06c3fb27SDimitry Andric << (IsDefaultDest ? "in" : "") << "direct)\n"); 160*06c3fb27SDimitry Andric } 161*06c3fb27SDimitry Andric #endif 162*06c3fb27SDimitry Andric 163*06c3fb27SDimitry Andric void CallBrPrepare::UpdateSSA(DominatorTree &DT, CallBrInst *CBR, 164*06c3fb27SDimitry Andric CallInst *Intrinsic, 165*06c3fb27SDimitry Andric SSAUpdater &SSAUpdate) const { 166*06c3fb27SDimitry Andric 167*06c3fb27SDimitry Andric SmallPtrSet<Use *, 4> Visited; 168*06c3fb27SDimitry Andric BasicBlock *DefaultDest = CBR->getDefaultDest(); 169*06c3fb27SDimitry Andric BasicBlock *LandingPad = Intrinsic->getParent(); 170*06c3fb27SDimitry Andric 171*06c3fb27SDimitry Andric SmallVector<Use *, 4> Uses(make_pointer_range(CBR->uses())); 172*06c3fb27SDimitry Andric for (Use *U : Uses) { 173*06c3fb27SDimitry Andric if (!Visited.insert(U).second) 174*06c3fb27SDimitry Andric continue; 175*06c3fb27SDimitry Andric 176*06c3fb27SDimitry Andric #ifndef NDEBUG 177*06c3fb27SDimitry Andric PrintDebugDomInfo(DT, *U, LandingPad, /*IsDefaultDest*/ false); 178*06c3fb27SDimitry Andric PrintDebugDomInfo(DT, *U, DefaultDest, /*IsDefaultDest*/ true); 179*06c3fb27SDimitry Andric #endif 180*06c3fb27SDimitry Andric 181*06c3fb27SDimitry Andric // Don't rewrite the use in the newly inserted intrinsic. 182*06c3fb27SDimitry Andric if (const auto *II = dyn_cast<IntrinsicInst>(U->getUser())) 183*06c3fb27SDimitry Andric if (II->getIntrinsicID() == Intrinsic::callbr_landingpad) 184*06c3fb27SDimitry Andric continue; 185*06c3fb27SDimitry Andric 186*06c3fb27SDimitry Andric // If the Use is in the same BasicBlock as the Intrinsic call, replace 187*06c3fb27SDimitry Andric // the Use with the value of the Intrinsic call. 188*06c3fb27SDimitry Andric if (IsInSameBasicBlock(*U, LandingPad)) { 189*06c3fb27SDimitry Andric U->set(Intrinsic); 190*06c3fb27SDimitry Andric continue; 191*06c3fb27SDimitry Andric } 192*06c3fb27SDimitry Andric 193*06c3fb27SDimitry Andric // If the Use is dominated by the default dest, do not touch it. 194*06c3fb27SDimitry Andric if (DT.dominates(DefaultDest, *U)) 195*06c3fb27SDimitry Andric continue; 196*06c3fb27SDimitry Andric 197*06c3fb27SDimitry Andric SSAUpdate.RewriteUse(*U); 198*06c3fb27SDimitry Andric } 199*06c3fb27SDimitry Andric } 200*06c3fb27SDimitry Andric 201*06c3fb27SDimitry Andric bool CallBrPrepare::runOnFunction(Function &Fn) { 202*06c3fb27SDimitry Andric bool Changed = false; 203*06c3fb27SDimitry Andric SmallVector<CallBrInst *, 2> CBRs = FindCallBrs(Fn); 204*06c3fb27SDimitry Andric 205*06c3fb27SDimitry Andric if (CBRs.empty()) 206*06c3fb27SDimitry Andric return Changed; 207*06c3fb27SDimitry Andric 208*06c3fb27SDimitry Andric // It's highly likely that most programs do not contain CallBrInsts. Follow a 209*06c3fb27SDimitry Andric // similar pattern from SafeStackLegacyPass::runOnFunction to reuse previous 210*06c3fb27SDimitry Andric // domtree analysis if available, otherwise compute it lazily. This avoids 211*06c3fb27SDimitry Andric // forcing Dominator Tree Construction at -O0 for programs that likely do not 212*06c3fb27SDimitry Andric // contain CallBrInsts. It does pessimize programs with callbr at higher 213*06c3fb27SDimitry Andric // optimization levels, as the DominatorTree created here is not reused by 214*06c3fb27SDimitry Andric // subsequent passes. 215*06c3fb27SDimitry Andric DominatorTree *DT; 216*06c3fb27SDimitry Andric std::optional<DominatorTree> LazilyComputedDomTree; 217*06c3fb27SDimitry Andric if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) 218*06c3fb27SDimitry Andric DT = &DTWP->getDomTree(); 219*06c3fb27SDimitry Andric else { 220*06c3fb27SDimitry Andric LazilyComputedDomTree.emplace(Fn); 221*06c3fb27SDimitry Andric DT = &*LazilyComputedDomTree; 222*06c3fb27SDimitry Andric } 223*06c3fb27SDimitry Andric 224*06c3fb27SDimitry Andric if (SplitCriticalEdges(CBRs, *DT)) 225*06c3fb27SDimitry Andric Changed = true; 226*06c3fb27SDimitry Andric 227*06c3fb27SDimitry Andric if (InsertIntrinsicCalls(CBRs, *DT)) 228*06c3fb27SDimitry Andric Changed = true; 229*06c3fb27SDimitry Andric 230*06c3fb27SDimitry Andric return Changed; 231*06c3fb27SDimitry Andric } 232