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