[WebAssembly] Add new target feature in support of 'extended-const' proposal
[llvm-project.git] / llvm / lib / CodeGen / DwarfEHPrepare.cpp
blobfb8a3e383950cf803606b731d79ec777a80b767b
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/ADT/Triple.h"
18 #include "llvm/Analysis/CFG.h"
19 #include "llvm/Analysis/DomTreeUpdater.h"
20 #include "llvm/Analysis/EHPersonalities.h"
21 #include "llvm/Analysis/TargetTransformInfo.h"
22 #include "llvm/CodeGen/RuntimeLibcalls.h"
23 #include "llvm/CodeGen/TargetLowering.h"
24 #include "llvm/CodeGen/TargetPassConfig.h"
25 #include "llvm/CodeGen/TargetSubtargetInfo.h"
26 #include "llvm/IR/BasicBlock.h"
27 #include "llvm/IR/Constants.h"
28 #include "llvm/IR/DerivedTypes.h"
29 #include "llvm/IR/Dominators.h"
30 #include "llvm/IR/Function.h"
31 #include "llvm/IR/Instructions.h"
32 #include "llvm/IR/Module.h"
33 #include "llvm/IR/Type.h"
34 #include "llvm/InitializePasses.h"
35 #include "llvm/Pass.h"
36 #include "llvm/Support/Casting.h"
37 #include "llvm/Target/TargetMachine.h"
38 #include "llvm/Transforms/Utils/Local.h"
39 #include <cstddef>
41 using namespace llvm;
43 #define DEBUG_TYPE "dwarfehprepare"
45 STATISTIC(NumResumesLowered, "Number of resume calls lowered");
46 STATISTIC(NumCleanupLandingPadsUnreachable,
47 "Number of cleanup landing pads found unreachable");
48 STATISTIC(NumCleanupLandingPadsRemaining,
49 "Number of cleanup landing pads remaining");
50 STATISTIC(NumNoUnwind, "Number of functions with nounwind");
51 STATISTIC(NumUnwind, "Number of functions with unwind");
53 namespace {
55 class DwarfEHPrepare {
56 CodeGenOpt::Level OptLevel;
58 Function &F;
59 const TargetLowering &TLI;
60 DomTreeUpdater *DTU;
61 const TargetTransformInfo *TTI;
62 const Triple &TargetTriple;
64 /// Return the exception object from the value passed into
65 /// the 'resume' instruction (typically an aggregate). Clean up any dead
66 /// instructions, including the 'resume' instruction.
67 Value *GetExceptionObject(ResumeInst *RI);
69 /// Replace resumes that are not reachable from a cleanup landing pad with
70 /// unreachable and then simplify those blocks.
71 size_t
72 pruneUnreachableResumes(SmallVectorImpl<ResumeInst *> &Resumes,
73 SmallVectorImpl<LandingPadInst *> &CleanupLPads);
75 /// Convert the ResumeInsts that are still present
76 /// into calls to the appropriate _Unwind_Resume function.
77 bool InsertUnwindResumeCalls();
79 public:
80 DwarfEHPrepare(CodeGenOpt::Level OptLevel_, Function &F_,
81 const TargetLowering &TLI_, DomTreeUpdater *DTU_,
82 const TargetTransformInfo *TTI_, const Triple &TargetTriple_)
83 : OptLevel(OptLevel_), F(F_), TLI(TLI_), DTU(DTU_), TTI(TTI_),
84 TargetTriple(TargetTriple_) {}
86 bool run();
89 } // namespace
91 Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
92 Value *V = RI->getOperand(0);
93 Value *ExnObj = nullptr;
94 InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V);
95 LoadInst *SelLoad = nullptr;
96 InsertValueInst *ExcIVI = nullptr;
97 bool EraseIVIs = false;
99 if (SelIVI) {
100 if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) {
101 ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0));
102 if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
103 ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
104 ExnObj = ExcIVI->getOperand(1);
105 SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
106 EraseIVIs = true;
111 if (!ExnObj)
112 ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI);
114 RI->eraseFromParent();
116 if (EraseIVIs) {
117 if (SelIVI->use_empty())
118 SelIVI->eraseFromParent();
119 if (ExcIVI->use_empty())
120 ExcIVI->eraseFromParent();
121 if (SelLoad && SelLoad->use_empty())
122 SelLoad->eraseFromParent();
125 return ExnObj;
128 size_t DwarfEHPrepare::pruneUnreachableResumes(
129 SmallVectorImpl<ResumeInst *> &Resumes,
130 SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
131 assert(DTU && "Should have DomTreeUpdater here.");
133 BitVector ResumeReachable(Resumes.size());
134 size_t ResumeIndex = 0;
135 for (auto *RI : Resumes) {
136 for (auto *LP : CleanupLPads) {
137 if (isPotentiallyReachable(LP, RI, nullptr, &DTU->getDomTree())) {
138 ResumeReachable.set(ResumeIndex);
139 break;
142 ++ResumeIndex;
145 // If everything is reachable, there is no change.
146 if (ResumeReachable.all())
147 return Resumes.size();
149 LLVMContext &Ctx = F.getContext();
151 // Otherwise, insert unreachable instructions and call simplifycfg.
152 size_t ResumesLeft = 0;
153 for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
154 ResumeInst *RI = Resumes[I];
155 if (ResumeReachable[I]) {
156 Resumes[ResumesLeft++] = RI;
157 } else {
158 BasicBlock *BB = RI->getParent();
159 new UnreachableInst(Ctx, RI);
160 RI->eraseFromParent();
161 simplifyCFG(BB, *TTI, DTU);
164 Resumes.resize(ResumesLeft);
165 return ResumesLeft;
168 bool DwarfEHPrepare::InsertUnwindResumeCalls() {
169 SmallVector<ResumeInst *, 16> Resumes;
170 SmallVector<LandingPadInst *, 16> CleanupLPads;
171 if (F.doesNotThrow())
172 NumNoUnwind++;
173 else
174 NumUnwind++;
175 for (BasicBlock &BB : F) {
176 if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
177 Resumes.push_back(RI);
178 if (auto *LP = BB.getLandingPadInst())
179 if (LP->isCleanup())
180 CleanupLPads.push_back(LP);
183 NumCleanupLandingPadsRemaining += CleanupLPads.size();
185 if (Resumes.empty())
186 return false;
188 // Check the personality, don't do anything if it's scope-based.
189 EHPersonality Pers = classifyEHPersonality(F.getPersonalityFn());
190 if (isScopedEHPersonality(Pers))
191 return false;
193 LLVMContext &Ctx = F.getContext();
195 size_t ResumesLeft = Resumes.size();
196 if (OptLevel != CodeGenOpt::None) {
197 ResumesLeft = pruneUnreachableResumes(Resumes, CleanupLPads);
198 #if LLVM_ENABLE_STATS
199 unsigned NumRemainingLPs = 0;
200 for (BasicBlock &BB : F) {
201 if (auto *LP = BB.getLandingPadInst())
202 if (LP->isCleanup())
203 NumRemainingLPs++;
205 NumCleanupLandingPadsUnreachable += CleanupLPads.size() - NumRemainingLPs;
206 NumCleanupLandingPadsRemaining -= CleanupLPads.size() - NumRemainingLPs;
207 #endif
210 if (ResumesLeft == 0)
211 return true; // We pruned them all.
213 // RewindFunction - _Unwind_Resume or the target equivalent.
214 FunctionCallee RewindFunction;
215 CallingConv::ID RewindFunctionCallingConv;
216 FunctionType *FTy;
217 const char *RewindName;
218 bool DoesRewindFunctionNeedExceptionObject;
220 if ((Pers == EHPersonality::GNU_CXX || Pers == EHPersonality::GNU_CXX_SjLj) &&
221 TargetTriple.isTargetEHABICompatible()) {
222 RewindName = TLI.getLibcallName(RTLIB::CXA_END_CLEANUP);
223 FTy = FunctionType::get(Type::getVoidTy(Ctx), false);
224 RewindFunctionCallingConv =
225 TLI.getLibcallCallingConv(RTLIB::CXA_END_CLEANUP);
226 DoesRewindFunctionNeedExceptionObject = false;
227 } else {
228 RewindName = TLI.getLibcallName(RTLIB::UNWIND_RESUME);
229 FTy =
230 FunctionType::get(Type::getVoidTy(Ctx), Type::getInt8PtrTy(Ctx), false);
231 RewindFunctionCallingConv = TLI.getLibcallCallingConv(RTLIB::UNWIND_RESUME);
232 DoesRewindFunctionNeedExceptionObject = true;
234 RewindFunction = F.getParent()->getOrInsertFunction(RewindName, FTy);
236 // Create the basic block where the _Unwind_Resume call will live.
237 if (ResumesLeft == 1) {
238 // Instead of creating a new BB and PHI node, just append the call to
239 // _Unwind_Resume to the end of the single resume block.
240 ResumeInst *RI = Resumes.front();
241 BasicBlock *UnwindBB = RI->getParent();
242 Value *ExnObj = GetExceptionObject(RI);
243 llvm::SmallVector<Value *, 1> RewindFunctionArgs;
244 if (DoesRewindFunctionNeedExceptionObject)
245 RewindFunctionArgs.push_back(ExnObj);
247 // Call the rewind function.
248 CallInst *CI =
249 CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
250 CI->setCallingConv(RewindFunctionCallingConv);
252 // We never expect _Unwind_Resume to return.
253 CI->setDoesNotReturn();
254 new UnreachableInst(Ctx, UnwindBB);
255 return true;
258 std::vector<DominatorTree::UpdateType> Updates;
259 Updates.reserve(Resumes.size());
261 llvm::SmallVector<Value *, 1> RewindFunctionArgs;
263 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &F);
264 PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft, "exn.obj",
265 UnwindBB);
267 // Extract the exception object from the ResumeInst and add it to the PHI node
268 // that feeds the _Unwind_Resume call.
269 for (ResumeInst *RI : Resumes) {
270 BasicBlock *Parent = RI->getParent();
271 BranchInst::Create(UnwindBB, Parent);
272 Updates.push_back({DominatorTree::Insert, Parent, UnwindBB});
274 Value *ExnObj = GetExceptionObject(RI);
275 PN->addIncoming(ExnObj, Parent);
277 ++NumResumesLowered;
280 if (DoesRewindFunctionNeedExceptionObject)
281 RewindFunctionArgs.push_back(PN);
283 // Call the function.
284 CallInst *CI =
285 CallInst::Create(RewindFunction, RewindFunctionArgs, "", UnwindBB);
286 CI->setCallingConv(RewindFunctionCallingConv);
288 // We never expect _Unwind_Resume to return.
289 CI->setDoesNotReturn();
290 new UnreachableInst(Ctx, UnwindBB);
292 if (DTU)
293 DTU->applyUpdates(Updates);
295 return true;
298 bool DwarfEHPrepare::run() {
299 bool Changed = InsertUnwindResumeCalls();
301 return Changed;
304 static bool prepareDwarfEH(CodeGenOpt::Level OptLevel, Function &F,
305 const TargetLowering &TLI, DominatorTree *DT,
306 const TargetTransformInfo *TTI,
307 const Triple &TargetTriple) {
308 DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
310 return DwarfEHPrepare(OptLevel, F, TLI, DT ? &DTU : nullptr, TTI,
311 TargetTriple)
312 .run();
315 namespace {
317 class DwarfEHPrepareLegacyPass : public FunctionPass {
319 CodeGenOpt::Level OptLevel;
321 public:
322 static char ID; // Pass identification, replacement for typeid.
324 DwarfEHPrepareLegacyPass(CodeGenOpt::Level OptLevel = CodeGenOpt::Default)
325 : FunctionPass(ID), OptLevel(OptLevel) {}
327 bool runOnFunction(Function &F) override {
328 const TargetMachine &TM =
329 getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
330 const TargetLowering &TLI = *TM.getSubtargetImpl(F)->getTargetLowering();
331 DominatorTree *DT = nullptr;
332 const TargetTransformInfo *TTI = nullptr;
333 if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
334 DT = &DTWP->getDomTree();
335 if (OptLevel != CodeGenOpt::None) {
336 if (!DT)
337 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
338 TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
340 return prepareDwarfEH(OptLevel, F, TLI, DT, TTI, TM.getTargetTriple());
343 void getAnalysisUsage(AnalysisUsage &AU) const override {
344 AU.addRequired<TargetPassConfig>();
345 AU.addRequired<TargetTransformInfoWrapperPass>();
346 if (OptLevel != CodeGenOpt::None) {
347 AU.addRequired<DominatorTreeWrapperPass>();
348 AU.addRequired<TargetTransformInfoWrapperPass>();
350 AU.addPreserved<DominatorTreeWrapperPass>();
353 StringRef getPassName() const override {
354 return "Exception handling preparation";
358 } // end anonymous namespace
360 char DwarfEHPrepareLegacyPass::ID = 0;
362 INITIALIZE_PASS_BEGIN(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
363 "Prepare DWARF exceptions", false, false)
364 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
365 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
366 INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
367 INITIALIZE_PASS_END(DwarfEHPrepareLegacyPass, DEBUG_TYPE,
368 "Prepare DWARF exceptions", false, false)
370 FunctionPass *llvm::createDwarfEHPass(CodeGenOpt::Level OptLevel) {
371 return new DwarfEHPrepareLegacyPass(OptLevel);