[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / CodeGen / DwarfEHPrepare.cpp
blob5ca1e91cc5f412feb6d67ece7598ebb55c2936db
1 //===- DwarfEHPrepare - Prepare exception handling for code generation ----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This pass mulches exception handling code into a form adapted to code
10 // generation. Required if using dwarf exception handling.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/BitVector.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/Analysis/CFG.h"
18 #include "llvm/Analysis/DomTreeUpdater.h"
19 #include "llvm/Analysis/EHPersonalities.h"
20 #include "llvm/Analysis/TargetTransformInfo.h"
21 #include "llvm/CodeGen/RuntimeLibcalls.h"
22 #include "llvm/CodeGen/TargetLowering.h"
23 #include "llvm/CodeGen/TargetPassConfig.h"
24 #include "llvm/CodeGen/TargetSubtargetInfo.h"
25 #include "llvm/IR/BasicBlock.h"
26 #include "llvm/IR/Constants.h"
27 #include "llvm/IR/DerivedTypes.h"
28 #include "llvm/IR/Dominators.h"
29 #include "llvm/IR/Function.h"
30 #include "llvm/IR/Instructions.h"
31 #include "llvm/IR/Module.h"
32 #include "llvm/IR/Type.h"
33 #include "llvm/InitializePasses.h"
34 #include "llvm/Pass.h"
35 #include "llvm/Support/Casting.h"
36 #include "llvm/Target/TargetMachine.h"
37 #include "llvm/Transforms/Utils/Local.h"
38 #include <cstddef>
40 using namespace llvm;
42 #define DEBUG_TYPE "dwarfehprepare"
44 STATISTIC(NumResumesLowered, "Number of resume calls lowered");
45 STATISTIC(NumCleanupLandingPadsUnreachable,
46 "Number of cleanup landing pads found unreachable");
47 STATISTIC(NumCleanupLandingPadsRemaining,
48 "Number of cleanup landing pads remaining");
49 STATISTIC(NumNoUnwind, "Number of functions with nounwind");
50 STATISTIC(NumUnwind, "Number of functions with unwind");
52 namespace {
54 class DwarfEHPrepare {
55 CodeGenOpt::Level OptLevel;
57 // RewindFunction - _Unwind_Resume or the target equivalent.
58 FunctionCallee &RewindFunction;
60 Function &F;
61 const TargetLowering &TLI;
62 DomTreeUpdater *DTU;
63 const TargetTransformInfo *TTI;
65 /// Return the exception object from the value passed into
66 /// the 'resume' instruction (typically an aggregate). Clean up any dead
67 /// instructions, including the 'resume' instruction.
68 Value *GetExceptionObject(ResumeInst *RI);
70 /// Replace resumes that are not reachable from a cleanup landing pad with
71 /// unreachable and then simplify those blocks.
72 size_t
73 pruneUnreachableResumes(SmallVectorImpl<ResumeInst *> &Resumes,
74 SmallVectorImpl<LandingPadInst *> &CleanupLPads);
76 /// Convert the ResumeInsts that are still present
77 /// into calls to the appropriate _Unwind_Resume function.
78 bool InsertUnwindResumeCalls();
80 public:
81 DwarfEHPrepare(CodeGenOpt::Level OptLevel_, FunctionCallee &RewindFunction_,
82 Function &F_, const TargetLowering &TLI_, DomTreeUpdater *DTU_,
83 const TargetTransformInfo *TTI_)
84 : OptLevel(OptLevel_), RewindFunction(RewindFunction_), F(F_), TLI(TLI_),
85 DTU(DTU_), TTI(TTI_) {}
87 bool run();
90 } // namespace
92 Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
93 Value *V = RI->getOperand(0);
94 Value *ExnObj = nullptr;
95 InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V);
96 LoadInst *SelLoad = nullptr;
97 InsertValueInst *ExcIVI = nullptr;
98 bool EraseIVIs = false;
100 if (SelIVI) {
101 if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) {
102 ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0));
103 if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
104 ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
105 ExnObj = ExcIVI->getOperand(1);
106 SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
107 EraseIVIs = true;
112 if (!ExnObj)
113 ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI);
115 RI->eraseFromParent();
117 if (EraseIVIs) {
118 if (SelIVI->use_empty())
119 SelIVI->eraseFromParent();
120 if (ExcIVI->use_empty())
121 ExcIVI->eraseFromParent();
122 if (SelLoad && SelLoad->use_empty())
123 SelLoad->eraseFromParent();
126 return ExnObj;
129 size_t DwarfEHPrepare::pruneUnreachableResumes(
130 SmallVectorImpl<ResumeInst *> &Resumes,
131 SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
132 assert(DTU && "Should have DomTreeUpdater here.");
134 BitVector ResumeReachable(Resumes.size());
135 size_t ResumeIndex = 0;
136 for (auto *RI : Resumes) {
137 for (auto *LP : CleanupLPads) {
138 if (isPotentiallyReachable(LP, RI, nullptr, &DTU->getDomTree())) {
139 ResumeReachable.set(ResumeIndex);
140 break;
143 ++ResumeIndex;
146 // If everything is reachable, there is no change.
147 if (ResumeReachable.all())
148 return Resumes.size();
150 LLVMContext &Ctx = F.getContext();
152 // Otherwise, insert unreachable instructions and call simplifycfg.
153 size_t ResumesLeft = 0;
154 for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
155 ResumeInst *RI = Resumes[I];
156 if (ResumeReachable[I]) {
157 Resumes[ResumesLeft++] = RI;
158 } else {
159 BasicBlock *BB = RI->getParent();
160 new UnreachableInst(Ctx, RI);
161 RI->eraseFromParent();
162 simplifyCFG(BB, *TTI, DTU);
165 Resumes.resize(ResumesLeft);
166 return ResumesLeft;
169 bool DwarfEHPrepare::InsertUnwindResumeCalls() {
170 SmallVector<ResumeInst *, 16> Resumes;
171 SmallVector<LandingPadInst *, 16> CleanupLPads;
172 if (F.doesNotThrow())
173 NumNoUnwind++;
174 else
175 NumUnwind++;
176 for (BasicBlock &BB : F) {
177 if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
178 Resumes.push_back(RI);
179 if (auto *LP = BB.getLandingPadInst())
180 if (LP->isCleanup())
181 CleanupLPads.push_back(LP);
184 NumCleanupLandingPadsRemaining += CleanupLPads.size();
186 if (Resumes.empty())
187 return false;
189 // Check the personality, don't do anything if it's scope-based.
190 EHPersonality Pers = classifyEHPersonality(F.getPersonalityFn());
191 if (isScopedEHPersonality(Pers))
192 return false;
194 LLVMContext &Ctx = F.getContext();
196 size_t ResumesLeft = Resumes.size();
197 if (OptLevel != CodeGenOpt::None) {
198 ResumesLeft = pruneUnreachableResumes(Resumes, CleanupLPads);
199 #if LLVM_ENABLE_STATS
200 unsigned NumRemainingLPs = 0;
201 for (BasicBlock &BB : F) {
202 if (auto *LP = BB.getLandingPadInst())
203 if (LP->isCleanup())
204 NumRemainingLPs++;
206 NumCleanupLandingPadsUnreachable += CleanupLPads.size() - NumRemainingLPs;
207 NumCleanupLandingPadsRemaining -= CleanupLPads.size() - NumRemainingLPs;
208 #endif
211 if (ResumesLeft == 0)
212 return true; // We pruned them all.
214 // Find the rewind function if we didn't already.
215 if (!RewindFunction) {
216 FunctionType *FTy =
217 FunctionType::get(Type::getVoidTy(Ctx), Type::getInt8PtrTy(Ctx), false);
218 const char *RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME);
219 RewindFunction = F.getParent()->getOrInsertFunction(RewindName, FTy);
222 // Create the basic block where the _Unwind_Resume call will live.
223 if (ResumesLeft == 1) {
224 // Instead of creating a new BB and PHI node, just append the call to
225 // _Unwind_Resume to the end of the single resume block.
226 ResumeInst *RI = Resumes.front();
227 BasicBlock *UnwindBB = RI->getParent();
228 Value *ExnObj = GetExceptionObject(RI);
230 // Call the _Unwind_Resume function.
231 CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB);
232 CI->setCallingConv(TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME));
234 // We never expect _Unwind_Resume to return.
235 CI->setDoesNotReturn();
236 new UnreachableInst(Ctx, UnwindBB);
237 return true;
240 std::vector<DominatorTree::UpdateType> Updates;
241 Updates.reserve(Resumes.size());
243 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F);
244 PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft, "exn.obj",
245 UnwindBB);
247 // Extract the exception object from the ResumeInst and add it to the PHI node
248 // that feeds the _Unwind_Resume call.
249 for (ResumeInst *RI : Resumes) {
250 BasicBlock *Parent = RI->getParent();
251 BranchInst::Create(UnwindBB, Parent);
252 Updates.push_back({DominatorTree::Insert, Parent, UnwindBB});
254 Value *ExnObj = GetExceptionObject(RI);
255 PN->addIncoming(ExnObj, Parent);
257 ++NumResumesLowered;
260 // Call the function.
261 CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB);
262 CI->setCallingConv(TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME));
264 // We never expect _Unwind_Resume to return.
265 CI->setDoesNotReturn();
266 new UnreachableInst(Ctx, UnwindBB);
268 if (DTU)
269 DTU->applyUpdates(Updates);
271 return true;
274 bool DwarfEHPrepare::run() {
275 bool Changed = InsertUnwindResumeCalls();
277 return Changed;
280 static bool prepareDwarfEH(CodeGenOpt::Level OptLevel,
281 FunctionCallee &RewindFunction, Function &F,
282 const TargetLowering &TLI, DominatorTree *DT,
283 const TargetTransformInfo *TTI) {
284 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
286 return DwarfEHPrepare(OptLevel, RewindFunction, F, TLI, DT ? &DTU : nullptr,
287 TTI)
288 .run();
291 namespace {
293 class DwarfEHPrepareLegacyPass : public FunctionPass {
294 // RewindFunction - _Unwind_Resume or the target equivalent.
295 FunctionCallee RewindFunction = nullptr;
297 CodeGenOpt::Level OptLevel;
299 public:
300 static char ID; // Pass identification, replacement for typeid.
302 DwarfEHPrepareLegacyPass(CodeGenOpt::Level OptLevel = CodeGenOpt::Default)
303 : FunctionPass(ID), OptLevel(OptLevel) {}
305 bool runOnFunction(Function &F) override {
306 const TargetMachine &TM =
307 getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
308 const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering();
309 DominatorTree *DT = nullptr;
310 const TargetTransformInfo *TTI = nullptr;
311 if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
312 DT = &DTWP->getDomTree();
313 if (OptLevel != CodeGenOpt::None) {
314 if (!DT)
315 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
316 TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
318 return prepareDwarfEH(OptLevel, RewindFunction, F, TLI, DT, TTI);
321 void getAnalysisUsage(AnalysisUsage &AU) const override {
322 AU.addRequired<TargetPassConfig>();
323 AU.addRequired<TargetTransformInfoWrapperPass>();
324 if (OptLevel != CodeGenOpt::None) {
325 AU.addRequired<DominatorTreeWrapperPass>();
326 AU.addRequired<TargetTransformInfoWrapperPass>();
328 AU.addPreserved<DominatorTreeWrapperPass>();
331 StringRef getPassName() const override {
332 return "Exception handling preparation";
336 } // end anonymous namespace
338 char DwarfEHPrepareLegacyPass::ID = 0;
340 INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
341 "Prepare DWARF exceptions", false, false)
342 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
343 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
344 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
345 INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
346 "Prepare DWARF exceptions", false, false)
348 FunctionPass *llvm::createDwarfEHPass(CodeGenOpt::Level OptLevel) {
349 return new DwarfEHPrepareLegacyPass(OptLevel);