xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/CallBrPrepare.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===-- CallBrPrepare - Prepare callbr for code generation ----------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric //
906c3fb27SDimitry Andric // This pass lowers callbrs in LLVM IR in order to to assist SelectionDAG's
1006c3fb27SDimitry Andric // codegen.
1106c3fb27SDimitry Andric //
1206c3fb27SDimitry Andric // In particular, this pass assists in inserting register copies for the output
1306c3fb27SDimitry Andric // values of a callbr along the edges leading to the indirect target blocks.
1406c3fb27SDimitry Andric // Though the output SSA value is defined by the callbr instruction itself in
1506c3fb27SDimitry Andric // the IR representation, the value cannot be copied to the appropriate virtual
1606c3fb27SDimitry Andric // registers prior to jumping to an indirect label, since the jump occurs
1706c3fb27SDimitry Andric // within the user-provided assembly blob.
1806c3fb27SDimitry Andric //
1906c3fb27SDimitry Andric // Instead, those copies must occur separately at the beginning of each
2006c3fb27SDimitry Andric // indirect target. That requires that we create a separate SSA definition in
2106c3fb27SDimitry Andric // each of them (via llvm.callbr.landingpad), and may require splitting
2206c3fb27SDimitry Andric // critical edges so we have a location to place the intrinsic. Finally, we
2306c3fb27SDimitry Andric // remap users of the original callbr output SSA value to instead point to the
2406c3fb27SDimitry Andric // appropriate llvm.callbr.landingpad value.
2506c3fb27SDimitry Andric //
2606c3fb27SDimitry Andric // Ideally, this could be done inside SelectionDAG, or in the
2706c3fb27SDimitry Andric // MachineInstruction representation, without the use of an IR-level intrinsic.
2806c3fb27SDimitry Andric // But, within the current framework, it’s simpler to implement as an IR pass.
2906c3fb27SDimitry Andric // (If support for callbr in GlobalISel is implemented, it’s worth considering
3006c3fb27SDimitry Andric // whether this is still required.)
3106c3fb27SDimitry Andric //
3206c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
3306c3fb27SDimitry Andric 
345f757f3fSDimitry Andric #include "llvm/CodeGen/CallBrPrepare.h"
3506c3fb27SDimitry Andric #include "llvm/ADT/ArrayRef.h"
3606c3fb27SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
3706c3fb27SDimitry Andric #include "llvm/ADT/SmallVector.h"
3806c3fb27SDimitry Andric #include "llvm/ADT/iterator.h"
3906c3fb27SDimitry Andric #include "llvm/Analysis/CFG.h"
4006c3fb27SDimitry Andric #include "llvm/CodeGen/Passes.h"
4106c3fb27SDimitry Andric #include "llvm/IR/BasicBlock.h"
4206c3fb27SDimitry Andric #include "llvm/IR/Dominators.h"
4306c3fb27SDimitry Andric #include "llvm/IR/Function.h"
4406c3fb27SDimitry Andric #include "llvm/IR/IRBuilder.h"
4506c3fb27SDimitry Andric #include "llvm/IR/Instructions.h"
4606c3fb27SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
4706c3fb27SDimitry Andric #include "llvm/IR/Intrinsics.h"
4806c3fb27SDimitry Andric #include "llvm/InitializePasses.h"
4906c3fb27SDimitry Andric #include "llvm/Pass.h"
5006c3fb27SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
5106c3fb27SDimitry Andric #include "llvm/Transforms/Utils/SSAUpdater.h"
5206c3fb27SDimitry Andric 
5306c3fb27SDimitry Andric using namespace llvm;
5406c3fb27SDimitry Andric 
55*0fca6ea1SDimitry Andric #define DEBUG_TYPE "callbr-prepare"
5606c3fb27SDimitry Andric 
575f757f3fSDimitry Andric static bool SplitCriticalEdges(ArrayRef<CallBrInst *> CBRs, DominatorTree &DT);
585f757f3fSDimitry Andric static bool InsertIntrinsicCalls(ArrayRef<CallBrInst *> CBRs,
595f757f3fSDimitry Andric                                  DominatorTree &DT);
605f757f3fSDimitry Andric static void UpdateSSA(DominatorTree &DT, CallBrInst *CBR, CallInst *Intrinsic,
615f757f3fSDimitry Andric                       SSAUpdater &SSAUpdate);
625f757f3fSDimitry Andric static SmallVector<CallBrInst *, 2> FindCallBrs(Function &Fn);
635f757f3fSDimitry Andric 
6406c3fb27SDimitry Andric namespace {
6506c3fb27SDimitry Andric 
6606c3fb27SDimitry Andric class CallBrPrepare : public FunctionPass {
6706c3fb27SDimitry Andric public:
CallBrPrepare()6806c3fb27SDimitry Andric   CallBrPrepare() : FunctionPass(ID) {}
6906c3fb27SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
7006c3fb27SDimitry Andric   bool runOnFunction(Function &Fn) override;
7106c3fb27SDimitry Andric   static char ID;
7206c3fb27SDimitry Andric };
7306c3fb27SDimitry Andric 
7406c3fb27SDimitry Andric } // end anonymous namespace
7506c3fb27SDimitry Andric 
run(Function & Fn,FunctionAnalysisManager & FAM)765f757f3fSDimitry Andric PreservedAnalyses CallBrPreparePass::run(Function &Fn,
775f757f3fSDimitry Andric                                          FunctionAnalysisManager &FAM) {
785f757f3fSDimitry Andric   bool Changed = false;
795f757f3fSDimitry Andric   SmallVector<CallBrInst *, 2> CBRs = FindCallBrs(Fn);
805f757f3fSDimitry Andric 
815f757f3fSDimitry Andric   if (CBRs.empty())
825f757f3fSDimitry Andric     return PreservedAnalyses::all();
835f757f3fSDimitry Andric 
845f757f3fSDimitry Andric   auto &DT = FAM.getResult<DominatorTreeAnalysis>(Fn);
855f757f3fSDimitry Andric 
865f757f3fSDimitry Andric   Changed |= SplitCriticalEdges(CBRs, DT);
875f757f3fSDimitry Andric   Changed |= InsertIntrinsicCalls(CBRs, DT);
885f757f3fSDimitry Andric 
895f757f3fSDimitry Andric   if (!Changed)
905f757f3fSDimitry Andric     return PreservedAnalyses::all();
915f757f3fSDimitry Andric   PreservedAnalyses PA;
925f757f3fSDimitry Andric   PA.preserve<DominatorTreeAnalysis>();
935f757f3fSDimitry Andric   return PA;
945f757f3fSDimitry Andric }
955f757f3fSDimitry Andric 
9606c3fb27SDimitry Andric char CallBrPrepare::ID = 0;
97*0fca6ea1SDimitry Andric INITIALIZE_PASS_BEGIN(CallBrPrepare, "callbrprepare", "Prepare callbr", false,
98*0fca6ea1SDimitry Andric                       false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)9906c3fb27SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
100*0fca6ea1SDimitry Andric INITIALIZE_PASS_END(CallBrPrepare, "callbrprepare", "Prepare callbr", false,
101*0fca6ea1SDimitry Andric                     false)
10206c3fb27SDimitry Andric 
10306c3fb27SDimitry Andric FunctionPass *llvm::createCallBrPass() { return new CallBrPrepare(); }
10406c3fb27SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const10506c3fb27SDimitry Andric void CallBrPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
10606c3fb27SDimitry Andric   AU.addPreserved<DominatorTreeWrapperPass>();
10706c3fb27SDimitry Andric }
10806c3fb27SDimitry Andric 
FindCallBrs(Function & Fn)1095f757f3fSDimitry Andric SmallVector<CallBrInst *, 2> FindCallBrs(Function &Fn) {
11006c3fb27SDimitry Andric   SmallVector<CallBrInst *, 2> CBRs;
11106c3fb27SDimitry Andric   for (BasicBlock &BB : Fn)
11206c3fb27SDimitry Andric     if (auto *CBR = dyn_cast<CallBrInst>(BB.getTerminator()))
11306c3fb27SDimitry Andric       if (!CBR->getType()->isVoidTy() && !CBR->use_empty())
11406c3fb27SDimitry Andric         CBRs.push_back(CBR);
11506c3fb27SDimitry Andric   return CBRs;
11606c3fb27SDimitry Andric }
11706c3fb27SDimitry Andric 
SplitCriticalEdges(ArrayRef<CallBrInst * > CBRs,DominatorTree & DT)1185f757f3fSDimitry Andric bool SplitCriticalEdges(ArrayRef<CallBrInst *> CBRs, DominatorTree &DT) {
11906c3fb27SDimitry Andric   bool Changed = false;
12006c3fb27SDimitry Andric   CriticalEdgeSplittingOptions Options(&DT);
12106c3fb27SDimitry Andric   Options.setMergeIdenticalEdges();
12206c3fb27SDimitry Andric 
12306c3fb27SDimitry Andric   // The indirect destination might be duplicated between another parameter...
12406c3fb27SDimitry Andric   //   %0 = callbr ... [label %x, label %x]
12506c3fb27SDimitry Andric   // ...hence MergeIdenticalEdges and AllowIndentical edges, but we don't need
12606c3fb27SDimitry Andric   // to split the default destination if it's duplicated between an indirect
12706c3fb27SDimitry Andric   // destination...
12806c3fb27SDimitry Andric   //   %1 = callbr ... to label %x [label %x]
12906c3fb27SDimitry Andric   // ...hence starting at 1 and checking against successor 0 (aka the default
13006c3fb27SDimitry Andric   // destination).
13106c3fb27SDimitry Andric   for (CallBrInst *CBR : CBRs)
13206c3fb27SDimitry Andric     for (unsigned i = 1, e = CBR->getNumSuccessors(); i != e; ++i)
13306c3fb27SDimitry Andric       if (CBR->getSuccessor(i) == CBR->getSuccessor(0) ||
13406c3fb27SDimitry Andric           isCriticalEdge(CBR, i, /*AllowIdenticalEdges*/ true))
13506c3fb27SDimitry Andric         if (SplitKnownCriticalEdge(CBR, i, Options))
13606c3fb27SDimitry Andric           Changed = true;
13706c3fb27SDimitry Andric   return Changed;
13806c3fb27SDimitry Andric }
13906c3fb27SDimitry Andric 
InsertIntrinsicCalls(ArrayRef<CallBrInst * > CBRs,DominatorTree & DT)1405f757f3fSDimitry Andric bool InsertIntrinsicCalls(ArrayRef<CallBrInst *> CBRs, DominatorTree &DT) {
14106c3fb27SDimitry Andric   bool Changed = false;
14206c3fb27SDimitry Andric   SmallPtrSet<const BasicBlock *, 4> Visited;
14306c3fb27SDimitry Andric   IRBuilder<> Builder(CBRs[0]->getContext());
14406c3fb27SDimitry Andric   for (CallBrInst *CBR : CBRs) {
14506c3fb27SDimitry Andric     if (!CBR->getNumIndirectDests())
14606c3fb27SDimitry Andric       continue;
14706c3fb27SDimitry Andric 
14806c3fb27SDimitry Andric     SSAUpdater SSAUpdate;
14906c3fb27SDimitry Andric     SSAUpdate.Initialize(CBR->getType(), CBR->getName());
15006c3fb27SDimitry Andric     SSAUpdate.AddAvailableValue(CBR->getParent(), CBR);
15106c3fb27SDimitry Andric     SSAUpdate.AddAvailableValue(CBR->getDefaultDest(), CBR);
15206c3fb27SDimitry Andric 
15306c3fb27SDimitry Andric     for (BasicBlock *IndDest : CBR->getIndirectDests()) {
15406c3fb27SDimitry Andric       if (!Visited.insert(IndDest).second)
15506c3fb27SDimitry Andric         continue;
15606c3fb27SDimitry Andric       Builder.SetInsertPoint(&*IndDest->begin());
15706c3fb27SDimitry Andric       CallInst *Intrinsic = Builder.CreateIntrinsic(
15806c3fb27SDimitry Andric           CBR->getType(), Intrinsic::callbr_landingpad, {CBR});
15906c3fb27SDimitry Andric       SSAUpdate.AddAvailableValue(IndDest, Intrinsic);
16006c3fb27SDimitry Andric       UpdateSSA(DT, CBR, Intrinsic, SSAUpdate);
16106c3fb27SDimitry Andric       Changed = true;
16206c3fb27SDimitry Andric     }
16306c3fb27SDimitry Andric   }
16406c3fb27SDimitry Andric   return Changed;
16506c3fb27SDimitry Andric }
16606c3fb27SDimitry Andric 
IsInSameBasicBlock(const Use & U,const BasicBlock * BB)16706c3fb27SDimitry Andric static bool IsInSameBasicBlock(const Use &U, const BasicBlock *BB) {
16806c3fb27SDimitry Andric   const auto *I = dyn_cast<Instruction>(U.getUser());
16906c3fb27SDimitry Andric   return I && I->getParent() == BB;
17006c3fb27SDimitry Andric }
17106c3fb27SDimitry Andric 
17206c3fb27SDimitry Andric #ifndef NDEBUG
PrintDebugDomInfo(const DominatorTree & DT,const Use & U,const BasicBlock * BB,bool IsDefaultDest)17306c3fb27SDimitry Andric static void PrintDebugDomInfo(const DominatorTree &DT, const Use &U,
17406c3fb27SDimitry Andric                               const BasicBlock *BB, bool IsDefaultDest) {
17506c3fb27SDimitry Andric   if (!isa<Instruction>(U.getUser()))
17606c3fb27SDimitry Andric     return;
17706c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "Use: " << *U.getUser() << ", in block "
17806c3fb27SDimitry Andric                     << cast<Instruction>(U.getUser())->getParent()->getName()
17906c3fb27SDimitry Andric                     << ", is " << (DT.dominates(BB, U) ? "" : "NOT ")
18006c3fb27SDimitry Andric                     << "dominated by " << BB->getName() << " ("
18106c3fb27SDimitry Andric                     << (IsDefaultDest ? "in" : "") << "direct)\n");
18206c3fb27SDimitry Andric }
18306c3fb27SDimitry Andric #endif
18406c3fb27SDimitry Andric 
UpdateSSA(DominatorTree & DT,CallBrInst * CBR,CallInst * Intrinsic,SSAUpdater & SSAUpdate)1855f757f3fSDimitry Andric void UpdateSSA(DominatorTree &DT, CallBrInst *CBR, CallInst *Intrinsic,
1865f757f3fSDimitry Andric                SSAUpdater &SSAUpdate) {
18706c3fb27SDimitry Andric 
18806c3fb27SDimitry Andric   SmallPtrSet<Use *, 4> Visited;
18906c3fb27SDimitry Andric   BasicBlock *DefaultDest = CBR->getDefaultDest();
19006c3fb27SDimitry Andric   BasicBlock *LandingPad = Intrinsic->getParent();
19106c3fb27SDimitry Andric 
19206c3fb27SDimitry Andric   SmallVector<Use *, 4> Uses(make_pointer_range(CBR->uses()));
19306c3fb27SDimitry Andric   for (Use *U : Uses) {
19406c3fb27SDimitry Andric     if (!Visited.insert(U).second)
19506c3fb27SDimitry Andric       continue;
19606c3fb27SDimitry Andric 
19706c3fb27SDimitry Andric #ifndef NDEBUG
19806c3fb27SDimitry Andric     PrintDebugDomInfo(DT, *U, LandingPad, /*IsDefaultDest*/ false);
19906c3fb27SDimitry Andric     PrintDebugDomInfo(DT, *U, DefaultDest, /*IsDefaultDest*/ true);
20006c3fb27SDimitry Andric #endif
20106c3fb27SDimitry Andric 
20206c3fb27SDimitry Andric     // Don't rewrite the use in the newly inserted intrinsic.
20306c3fb27SDimitry Andric     if (const auto *II = dyn_cast<IntrinsicInst>(U->getUser()))
20406c3fb27SDimitry Andric       if (II->getIntrinsicID() == Intrinsic::callbr_landingpad)
20506c3fb27SDimitry Andric         continue;
20606c3fb27SDimitry Andric 
20706c3fb27SDimitry Andric     // If the Use is in the same BasicBlock as the Intrinsic call, replace
20806c3fb27SDimitry Andric     // the Use with the value of the Intrinsic call.
20906c3fb27SDimitry Andric     if (IsInSameBasicBlock(*U, LandingPad)) {
21006c3fb27SDimitry Andric       U->set(Intrinsic);
21106c3fb27SDimitry Andric       continue;
21206c3fb27SDimitry Andric     }
21306c3fb27SDimitry Andric 
21406c3fb27SDimitry Andric     // If the Use is dominated by the default dest, do not touch it.
21506c3fb27SDimitry Andric     if (DT.dominates(DefaultDest, *U))
21606c3fb27SDimitry Andric       continue;
21706c3fb27SDimitry Andric 
21806c3fb27SDimitry Andric     SSAUpdate.RewriteUse(*U);
21906c3fb27SDimitry Andric   }
22006c3fb27SDimitry Andric }
22106c3fb27SDimitry Andric 
runOnFunction(Function & Fn)22206c3fb27SDimitry Andric bool CallBrPrepare::runOnFunction(Function &Fn) {
22306c3fb27SDimitry Andric   bool Changed = false;
22406c3fb27SDimitry Andric   SmallVector<CallBrInst *, 2> CBRs = FindCallBrs(Fn);
22506c3fb27SDimitry Andric 
22606c3fb27SDimitry Andric   if (CBRs.empty())
22706c3fb27SDimitry Andric     return Changed;
22806c3fb27SDimitry Andric 
22906c3fb27SDimitry Andric   // It's highly likely that most programs do not contain CallBrInsts. Follow a
23006c3fb27SDimitry Andric   // similar pattern from SafeStackLegacyPass::runOnFunction to reuse previous
23106c3fb27SDimitry Andric   // domtree analysis if available, otherwise compute it lazily. This avoids
23206c3fb27SDimitry Andric   // forcing Dominator Tree Construction at -O0 for programs that likely do not
23306c3fb27SDimitry Andric   // contain CallBrInsts. It does pessimize programs with callbr at higher
23406c3fb27SDimitry Andric   // optimization levels, as the DominatorTree created here is not reused by
23506c3fb27SDimitry Andric   // subsequent passes.
23606c3fb27SDimitry Andric   DominatorTree *DT;
23706c3fb27SDimitry Andric   std::optional<DominatorTree> LazilyComputedDomTree;
23806c3fb27SDimitry Andric   if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
23906c3fb27SDimitry Andric     DT = &DTWP->getDomTree();
24006c3fb27SDimitry Andric   else {
24106c3fb27SDimitry Andric     LazilyComputedDomTree.emplace(Fn);
24206c3fb27SDimitry Andric     DT = &*LazilyComputedDomTree;
24306c3fb27SDimitry Andric   }
24406c3fb27SDimitry Andric 
24506c3fb27SDimitry Andric   if (SplitCriticalEdges(CBRs, *DT))
24606c3fb27SDimitry Andric     Changed = true;
24706c3fb27SDimitry Andric 
24806c3fb27SDimitry Andric   if (InsertIntrinsicCalls(CBRs, *DT))
24906c3fb27SDimitry Andric     Changed = true;
25006c3fb27SDimitry Andric 
25106c3fb27SDimitry Andric   return Changed;
25206c3fb27SDimitry Andric }
253