xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/CallBrPrepare.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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