xref: /llvm-project/llvm/lib/CodeGen/CallBrPrepare.cpp (revision e390c229a438ed1eb3396df8fbeeda89c49474e6)
1fb471158SNick Desaulniers //===-- CallBrPrepare - Prepare callbr for code generation ----------------===//
2fb471158SNick Desaulniers //
3fb471158SNick Desaulniers // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fb471158SNick Desaulniers // See https://llvm.org/LICENSE.txt for license information.
5fb471158SNick Desaulniers // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fb471158SNick Desaulniers //
7fb471158SNick Desaulniers //===----------------------------------------------------------------------===//
8fb471158SNick Desaulniers //
9fb471158SNick Desaulniers // This pass lowers callbrs in LLVM IR in order to to assist SelectionDAG's
10fb471158SNick Desaulniers // codegen.
11fb471158SNick Desaulniers //
12fb471158SNick Desaulniers // In particular, this pass assists in inserting register copies for the output
13fb471158SNick Desaulniers // values of a callbr along the edges leading to the indirect target blocks.
14fb471158SNick Desaulniers // Though the output SSA value is defined by the callbr instruction itself in
15fb471158SNick Desaulniers // the IR representation, the value cannot be copied to the appropriate virtual
16fb471158SNick Desaulniers // registers prior to jumping to an indirect label, since the jump occurs
17fb471158SNick Desaulniers // within the user-provided assembly blob.
18fb471158SNick Desaulniers //
19fb471158SNick Desaulniers // Instead, those copies must occur separately at the beginning of each
20fb471158SNick Desaulniers // indirect target. That requires that we create a separate SSA definition in
21fb471158SNick Desaulniers // each of them (via llvm.callbr.landingpad), and may require splitting
22fb471158SNick Desaulniers // critical edges so we have a location to place the intrinsic. Finally, we
23fb471158SNick Desaulniers // remap users of the original callbr output SSA value to instead point to the
24fb471158SNick Desaulniers // appropriate llvm.callbr.landingpad value.
25fb471158SNick Desaulniers //
26fb471158SNick Desaulniers // Ideally, this could be done inside SelectionDAG, or in the
27fb471158SNick Desaulniers // MachineInstruction representation, without the use of an IR-level intrinsic.
28fb471158SNick Desaulniers // But, within the current framework, it’s simpler to implement as an IR pass.
29fb471158SNick Desaulniers // (If support for callbr in GlobalISel is implemented, it’s worth considering
30fb471158SNick Desaulniers // whether this is still required.)
31fb471158SNick Desaulniers //
32fb471158SNick Desaulniers //===----------------------------------------------------------------------===//
33fb471158SNick Desaulniers 
341debbae9Spaperchalice #include "llvm/CodeGen/CallBrPrepare.h"
350a39af0eSNick Desaulniers #include "llvm/ADT/ArrayRef.h"
36094190c2SNick Desaulniers #include "llvm/ADT/SmallPtrSet.h"
370a39af0eSNick Desaulniers #include "llvm/ADT/SmallVector.h"
3828d45c84SNick Desaulniers #include "llvm/ADT/iterator.h"
390a39af0eSNick Desaulniers #include "llvm/Analysis/CFG.h"
40fb471158SNick Desaulniers #include "llvm/CodeGen/Passes.h"
41fb471158SNick Desaulniers #include "llvm/IR/BasicBlock.h"
420a39af0eSNick Desaulniers #include "llvm/IR/Dominators.h"
43fb471158SNick Desaulniers #include "llvm/IR/Function.h"
44094190c2SNick Desaulniers #include "llvm/IR/IRBuilder.h"
45fb471158SNick Desaulniers #include "llvm/IR/Instructions.h"
46094190c2SNick Desaulniers #include "llvm/IR/IntrinsicInst.h"
47094190c2SNick Desaulniers #include "llvm/IR/Intrinsics.h"
48fb471158SNick Desaulniers #include "llvm/InitializePasses.h"
49fb471158SNick Desaulniers #include "llvm/Pass.h"
500a39af0eSNick Desaulniers #include "llvm/Transforms/Utils/BasicBlockUtils.h"
5128d45c84SNick Desaulniers #include "llvm/Transforms/Utils/SSAUpdater.h"
52fb471158SNick Desaulniers 
53fb471158SNick Desaulniers using namespace llvm;
54fb471158SNick Desaulniers 
55*e390c229Spaperchalice #define DEBUG_TYPE "callbr-prepare"
56fb471158SNick Desaulniers 
571debbae9Spaperchalice static bool SplitCriticalEdges(ArrayRef<CallBrInst *> CBRs, DominatorTree &DT);
581debbae9Spaperchalice static bool InsertIntrinsicCalls(ArrayRef<CallBrInst *> CBRs,
591debbae9Spaperchalice                                  DominatorTree &DT);
601debbae9Spaperchalice static void UpdateSSA(DominatorTree &DT, CallBrInst *CBR, CallInst *Intrinsic,
611debbae9Spaperchalice                       SSAUpdater &SSAUpdate);
621debbae9Spaperchalice static SmallVector<CallBrInst *, 2> FindCallBrs(Function &Fn);
631debbae9Spaperchalice 
64fb471158SNick Desaulniers namespace {
65fb471158SNick Desaulniers 
66fb471158SNick Desaulniers class CallBrPrepare : public FunctionPass {
67fb471158SNick Desaulniers public:
CallBrPrepare()68fb471158SNick Desaulniers   CallBrPrepare() : FunctionPass(ID) {}
69fb471158SNick Desaulniers   void getAnalysisUsage(AnalysisUsage &AU) const override;
70fb471158SNick Desaulniers   bool runOnFunction(Function &Fn) override;
710a39af0eSNick Desaulniers   static char ID;
72fb471158SNick Desaulniers };
73fb471158SNick Desaulniers 
74fb471158SNick Desaulniers } // end anonymous namespace
75fb471158SNick Desaulniers 
run(Function & Fn,FunctionAnalysisManager & FAM)761debbae9Spaperchalice PreservedAnalyses CallBrPreparePass::run(Function &Fn,
771debbae9Spaperchalice                                          FunctionAnalysisManager &FAM) {
781debbae9Spaperchalice   bool Changed = false;
791debbae9Spaperchalice   SmallVector<CallBrInst *, 2> CBRs = FindCallBrs(Fn);
801debbae9Spaperchalice 
811debbae9Spaperchalice   if (CBRs.empty())
821debbae9Spaperchalice     return PreservedAnalyses::all();
831debbae9Spaperchalice 
841debbae9Spaperchalice   auto &DT = FAM.getResult<DominatorTreeAnalysis>(Fn);
851debbae9Spaperchalice 
861debbae9Spaperchalice   Changed |= SplitCriticalEdges(CBRs, DT);
871debbae9Spaperchalice   Changed |= InsertIntrinsicCalls(CBRs, DT);
881debbae9Spaperchalice 
891debbae9Spaperchalice   if (!Changed)
901debbae9Spaperchalice     return PreservedAnalyses::all();
911debbae9Spaperchalice   PreservedAnalyses PA;
921debbae9Spaperchalice   PA.preserve<DominatorTreeAnalysis>();
931debbae9Spaperchalice   return PA;
941debbae9Spaperchalice }
951debbae9Spaperchalice 
96fb471158SNick Desaulniers char CallBrPrepare::ID = 0;
97*e390c229Spaperchalice INITIALIZE_PASS_BEGIN(CallBrPrepare, "callbrprepare", "Prepare callbr", false,
98*e390c229Spaperchalice                       false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)990a39af0eSNick Desaulniers INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
100*e390c229Spaperchalice INITIALIZE_PASS_END(CallBrPrepare, "callbrprepare", "Prepare callbr", false,
101*e390c229Spaperchalice                     false)
102fb471158SNick Desaulniers 
103fb471158SNick Desaulniers FunctionPass *llvm::createCallBrPass() { return new CallBrPrepare(); }
104fb471158SNick Desaulniers 
getAnalysisUsage(AnalysisUsage & AU) const105fb471158SNick Desaulniers void CallBrPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
1060a39af0eSNick Desaulniers   AU.addPreserved<DominatorTreeWrapperPass>();
1070a39af0eSNick Desaulniers }
1080a39af0eSNick Desaulniers 
FindCallBrs(Function & Fn)1091debbae9Spaperchalice SmallVector<CallBrInst *, 2> FindCallBrs(Function &Fn) {
1100a39af0eSNick Desaulniers   SmallVector<CallBrInst *, 2> CBRs;
1110a39af0eSNick Desaulniers   for (BasicBlock &BB : Fn)
1120a39af0eSNick Desaulniers     if (auto *CBR = dyn_cast<CallBrInst>(BB.getTerminator()))
1130a39af0eSNick Desaulniers       if (!CBR->getType()->isVoidTy() && !CBR->use_empty())
1140a39af0eSNick Desaulniers         CBRs.push_back(CBR);
1150a39af0eSNick Desaulniers   return CBRs;
1160a39af0eSNick Desaulniers }
1170a39af0eSNick Desaulniers 
SplitCriticalEdges(ArrayRef<CallBrInst * > CBRs,DominatorTree & DT)1181debbae9Spaperchalice bool SplitCriticalEdges(ArrayRef<CallBrInst *> CBRs, DominatorTree &DT) {
1190a39af0eSNick Desaulniers   bool Changed = false;
1200a39af0eSNick Desaulniers   CriticalEdgeSplittingOptions Options(&DT);
1210a39af0eSNick Desaulniers   Options.setMergeIdenticalEdges();
1220a39af0eSNick Desaulniers 
1230a39af0eSNick Desaulniers   // The indirect destination might be duplicated between another parameter...
1240a39af0eSNick Desaulniers   //   %0 = callbr ... [label %x, label %x]
1250a39af0eSNick Desaulniers   // ...hence MergeIdenticalEdges and AllowIndentical edges, but we don't need
1260a39af0eSNick Desaulniers   // to split the default destination if it's duplicated between an indirect
1270a39af0eSNick Desaulniers   // destination...
1280a39af0eSNick Desaulniers   //   %1 = callbr ... to label %x [label %x]
1290a39af0eSNick Desaulniers   // ...hence starting at 1 and checking against successor 0 (aka the default
1300a39af0eSNick Desaulniers   // destination).
1310a39af0eSNick Desaulniers   for (CallBrInst *CBR : CBRs)
1320a39af0eSNick Desaulniers     for (unsigned i = 1, e = CBR->getNumSuccessors(); i != e; ++i)
1330a39af0eSNick Desaulniers       if (CBR->getSuccessor(i) == CBR->getSuccessor(0) ||
1340a39af0eSNick Desaulniers           isCriticalEdge(CBR, i, /*AllowIdenticalEdges*/ true))
1350a39af0eSNick Desaulniers         if (SplitKnownCriticalEdge(CBR, i, Options))
1360a39af0eSNick Desaulniers           Changed = true;
1370a39af0eSNick Desaulniers   return Changed;
138fb471158SNick Desaulniers }
139fb471158SNick Desaulniers 
InsertIntrinsicCalls(ArrayRef<CallBrInst * > CBRs,DominatorTree & DT)1401debbae9Spaperchalice bool InsertIntrinsicCalls(ArrayRef<CallBrInst *> CBRs, DominatorTree &DT) {
141094190c2SNick Desaulniers   bool Changed = false;
142094190c2SNick Desaulniers   SmallPtrSet<const BasicBlock *, 4> Visited;
143094190c2SNick Desaulniers   IRBuilder<> Builder(CBRs[0]->getContext());
144094190c2SNick Desaulniers   for (CallBrInst *CBR : CBRs) {
14528d45c84SNick Desaulniers     if (!CBR->getNumIndirectDests())
14628d45c84SNick Desaulniers       continue;
14728d45c84SNick Desaulniers 
14828d45c84SNick Desaulniers     SSAUpdater SSAUpdate;
14928d45c84SNick Desaulniers     SSAUpdate.Initialize(CBR->getType(), CBR->getName());
15028d45c84SNick Desaulniers     SSAUpdate.AddAvailableValue(CBR->getParent(), CBR);
15128d45c84SNick Desaulniers     SSAUpdate.AddAvailableValue(CBR->getDefaultDest(), CBR);
15228d45c84SNick Desaulniers 
153094190c2SNick Desaulniers     for (BasicBlock *IndDest : CBR->getIndirectDests()) {
154094190c2SNick Desaulniers       if (!Visited.insert(IndDest).second)
155094190c2SNick Desaulniers         continue;
156094190c2SNick Desaulniers       Builder.SetInsertPoint(&*IndDest->begin());
15728d45c84SNick Desaulniers       CallInst *Intrinsic = Builder.CreateIntrinsic(
15828d45c84SNick Desaulniers           CBR->getType(), Intrinsic::callbr_landingpad, {CBR});
15928d45c84SNick Desaulniers       SSAUpdate.AddAvailableValue(IndDest, Intrinsic);
16028d45c84SNick Desaulniers       UpdateSSA(DT, CBR, Intrinsic, SSAUpdate);
161094190c2SNick Desaulniers       Changed = true;
162094190c2SNick Desaulniers     }
163094190c2SNick Desaulniers   }
164094190c2SNick Desaulniers   return Changed;
165094190c2SNick Desaulniers }
166094190c2SNick Desaulniers 
IsInSameBasicBlock(const Use & U,const BasicBlock * BB)16728d45c84SNick Desaulniers static bool IsInSameBasicBlock(const Use &U, const BasicBlock *BB) {
16828d45c84SNick Desaulniers   const auto *I = dyn_cast<Instruction>(U.getUser());
16928d45c84SNick Desaulniers   return I && I->getParent() == BB;
17028d45c84SNick Desaulniers }
17128d45c84SNick Desaulniers 
17293de5f13SKazu Hirata #ifndef NDEBUG
PrintDebugDomInfo(const DominatorTree & DT,const Use & U,const BasicBlock * BB,bool IsDefaultDest)17328d45c84SNick Desaulniers static void PrintDebugDomInfo(const DominatorTree &DT, const Use &U,
17428d45c84SNick Desaulniers                               const BasicBlock *BB, bool IsDefaultDest) {
17528d45c84SNick Desaulniers   if (!isa<Instruction>(U.getUser()))
17628d45c84SNick Desaulniers     return;
17728d45c84SNick Desaulniers   LLVM_DEBUG(dbgs() << "Use: " << *U.getUser() << ", in block "
17828d45c84SNick Desaulniers                     << cast<Instruction>(U.getUser())->getParent()->getName()
17993de5f13SKazu Hirata                     << ", is " << (DT.dominates(BB, U) ? "" : "NOT ")
18093de5f13SKazu Hirata                     << "dominated by " << BB->getName() << " ("
18193de5f13SKazu Hirata                     << (IsDefaultDest ? "in" : "") << "direct)\n");
18228d45c84SNick Desaulniers }
18393de5f13SKazu Hirata #endif
18428d45c84SNick Desaulniers 
UpdateSSA(DominatorTree & DT,CallBrInst * CBR,CallInst * Intrinsic,SSAUpdater & SSAUpdate)1851debbae9Spaperchalice void UpdateSSA(DominatorTree &DT, CallBrInst *CBR, CallInst *Intrinsic,
1861debbae9Spaperchalice                SSAUpdater &SSAUpdate) {
18728d45c84SNick Desaulniers 
18828d45c84SNick Desaulniers   SmallPtrSet<Use *, 4> Visited;
18928d45c84SNick Desaulniers   BasicBlock *DefaultDest = CBR->getDefaultDest();
19028d45c84SNick Desaulniers   BasicBlock *LandingPad = Intrinsic->getParent();
19128d45c84SNick Desaulniers 
19228d45c84SNick Desaulniers   SmallVector<Use *, 4> Uses(make_pointer_range(CBR->uses()));
19328d45c84SNick Desaulniers   for (Use *U : Uses) {
19428d45c84SNick Desaulniers     if (!Visited.insert(U).second)
19528d45c84SNick Desaulniers       continue;
19628d45c84SNick Desaulniers 
19728d45c84SNick Desaulniers #ifndef NDEBUG
19828d45c84SNick Desaulniers     PrintDebugDomInfo(DT, *U, LandingPad, /*IsDefaultDest*/ false);
19928d45c84SNick Desaulniers     PrintDebugDomInfo(DT, *U, DefaultDest, /*IsDefaultDest*/ true);
20028d45c84SNick Desaulniers #endif
20128d45c84SNick Desaulniers 
20228d45c84SNick Desaulniers     // Don't rewrite the use in the newly inserted intrinsic.
20328d45c84SNick Desaulniers     if (const auto *II = dyn_cast<IntrinsicInst>(U->getUser()))
20428d45c84SNick Desaulniers       if (II->getIntrinsicID() == Intrinsic::callbr_landingpad)
20528d45c84SNick Desaulniers         continue;
20628d45c84SNick Desaulniers 
20728d45c84SNick Desaulniers     // If the Use is in the same BasicBlock as the Intrinsic call, replace
20828d45c84SNick Desaulniers     // the Use with the value of the Intrinsic call.
20928d45c84SNick Desaulniers     if (IsInSameBasicBlock(*U, LandingPad)) {
21028d45c84SNick Desaulniers       U->set(Intrinsic);
21128d45c84SNick Desaulniers       continue;
21228d45c84SNick Desaulniers     }
21328d45c84SNick Desaulniers 
21428d45c84SNick Desaulniers     // If the Use is dominated by the default dest, do not touch it.
21528d45c84SNick Desaulniers     if (DT.dominates(DefaultDest, *U))
21628d45c84SNick Desaulniers       continue;
21728d45c84SNick Desaulniers 
21828d45c84SNick Desaulniers     SSAUpdate.RewriteUse(*U);
21928d45c84SNick Desaulniers   }
22028d45c84SNick Desaulniers }
22128d45c84SNick Desaulniers 
runOnFunction(Function & Fn)222fb471158SNick Desaulniers bool CallBrPrepare::runOnFunction(Function &Fn) {
2230a39af0eSNick Desaulniers   bool Changed = false;
2240a39af0eSNick Desaulniers   SmallVector<CallBrInst *, 2> CBRs = FindCallBrs(Fn);
2250a39af0eSNick Desaulniers 
2260a39af0eSNick Desaulniers   if (CBRs.empty())
2270a39af0eSNick Desaulniers     return Changed;
2280a39af0eSNick Desaulniers 
2290a39af0eSNick Desaulniers   // It's highly likely that most programs do not contain CallBrInsts. Follow a
2300a39af0eSNick Desaulniers   // similar pattern from SafeStackLegacyPass::runOnFunction to reuse previous
2310a39af0eSNick Desaulniers   // domtree analysis if available, otherwise compute it lazily. This avoids
2320a39af0eSNick Desaulniers   // forcing Dominator Tree Construction at -O0 for programs that likely do not
2330a39af0eSNick Desaulniers   // contain CallBrInsts. It does pessimize programs with callbr at higher
2340a39af0eSNick Desaulniers   // optimization levels, as the DominatorTree created here is not reused by
2350a39af0eSNick Desaulniers   // subsequent passes.
2360a39af0eSNick Desaulniers   DominatorTree *DT;
2370a39af0eSNick Desaulniers   std::optional<DominatorTree> LazilyComputedDomTree;
2380a39af0eSNick Desaulniers   if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
2390a39af0eSNick Desaulniers     DT = &DTWP->getDomTree();
2400a39af0eSNick Desaulniers   else {
2410a39af0eSNick Desaulniers     LazilyComputedDomTree.emplace(Fn);
2420a39af0eSNick Desaulniers     DT = &*LazilyComputedDomTree;
243fb471158SNick Desaulniers   }
2440a39af0eSNick Desaulniers 
2450a39af0eSNick Desaulniers   if (SplitCriticalEdges(CBRs, *DT))
2460a39af0eSNick Desaulniers     Changed = true;
2470a39af0eSNick Desaulniers 
24828d45c84SNick Desaulniers   if (InsertIntrinsicCalls(CBRs, *DT))
249094190c2SNick Desaulniers     Changed = true;
250094190c2SNick Desaulniers 
2510a39af0eSNick Desaulniers   return Changed;
252fb471158SNick Desaulniers }
253