blob: 6b36a93c62c3d03aa0d58dc9b073c923301d5ece [file] [log] [blame]
Eugene Zelenkof1933322017-09-22 23:46:57 +00001//===- DwarfEHPrepare - Prepare exception handling for code generation ----===//
Duncan Sandsd6fb6502009-05-22 20:36:31 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Duncan Sandsd6fb6502009-05-22 20:36:31 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This pass mulches exception handling code into a form adapted to code
Bill Wendlingd1aa77c2010-03-26 23:41:30 +000010// generation. Required if using dwarf exception handling.
Duncan Sandsd6fb6502009-05-22 20:36:31 +000011//
12//===----------------------------------------------------------------------===//
13
Reid Klecknerbe0a0502015-03-09 22:45:16 +000014#include "llvm/ADT/BitVector.h"
Eugene Zelenkof1933322017-09-22 23:46:57 +000015#include "llvm/ADT/SmallVector.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000016#include "llvm/ADT/Statistic.h"
Reid Klecknerbe0a0502015-03-09 22:45:16 +000017#include "llvm/Analysis/CFG.h"
David Majnemer70497c62015-12-02 23:06:39 +000018#include "llvm/Analysis/EHPersonalities.h"
Reid Klecknerbe0a0502015-03-09 22:45:16 +000019#include "llvm/Analysis/TargetTransformInfo.h"
David Blaikie31b98d22018-06-04 21:23:21 +000020#include "llvm/Transforms/Utils/Local.h"
Eugene Zelenkof1933322017-09-22 23:46:57 +000021#include "llvm/CodeGen/RuntimeLibcalls.h"
David Blaikieb3bde2e2017-11-17 01:07:10 +000022#include "llvm/CodeGen/TargetLowering.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000023#include "llvm/CodeGen/TargetPassConfig.h"
David Blaikieb3bde2e2017-11-17 01:07:10 +000024#include "llvm/CodeGen/TargetSubtargetInfo.h"
Eugene Zelenkof1933322017-09-22 23:46:57 +000025#include "llvm/IR/BasicBlock.h"
26#include "llvm/IR/Constants.h"
27#include "llvm/IR/DerivedTypes.h"
Reid Klecknerbe0a0502015-03-09 22:45:16 +000028#include "llvm/IR/Dominators.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000029#include "llvm/IR/Function.h"
30#include "llvm/IR/Instructions.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000031#include "llvm/IR/Module.h"
Eugene Zelenkof1933322017-09-22 23:46:57 +000032#include "llvm/IR/Type.h"
Duncan Sandsd6fb6502009-05-22 20:36:31 +000033#include "llvm/Pass.h"
Eugene Zelenkof1933322017-09-22 23:46:57 +000034#include "llvm/Support/Casting.h"
Eugene Zelenkof1933322017-09-22 23:46:57 +000035#include "llvm/Target/TargetMachine.h"
Eugene Zelenkof1933322017-09-22 23:46:57 +000036#include <cstddef>
37
Duncan Sandsd6fb6502009-05-22 20:36:31 +000038using namespace llvm;
39
Chandler Carruth1b9dde02014-04-22 02:02:50 +000040#define DEBUG_TYPE "dwarfehprepare"
41
Bill Wendling478f58c2011-11-07 23:36:48 +000042STATISTIC(NumResumesLowered, "Number of resume calls lowered");
Duncan Sandsd6fb6502009-05-22 20:36:31 +000043
44namespace {
Eugene Zelenkof1933322017-09-22 23:46:57 +000045
Nick Lewycky02d5f772009-10-25 06:33:48 +000046 class DwarfEHPrepare : public FunctionPass {
Bill Wendling478f58c2011-11-07 23:36:48 +000047 // RewindFunction - _Unwind_Resume or the target equivalent.
James Y Knight13680222019-02-01 02:28:03 +000048 FunctionCallee RewindFunction = nullptr;
Duncan Sandsd6fb6502009-05-22 20:36:31 +000049
Eugene Zelenkof1933322017-09-22 23:46:57 +000050 DominatorTree *DT = nullptr;
51 const TargetLowering *TLI = nullptr;
Reid Klecknerbe0a0502015-03-09 22:45:16 +000052
Bill Wendling478f58c2011-11-07 23:36:48 +000053 bool InsertUnwindResumeCalls(Function &Fn);
Bill Wendling27489fe2012-05-17 17:59:51 +000054 Value *GetExceptionObject(ResumeInst *RI);
Reid Klecknerbe0a0502015-03-09 22:45:16 +000055 size_t
56 pruneUnreachableResumes(Function &Fn,
57 SmallVectorImpl<ResumeInst *> &Resumes,
58 SmallVectorImpl<LandingPadInst *> &CleanupLPads);
Duncan Sandsd6fb6502009-05-22 20:36:31 +000059
Duncan Sandsd6fb6502009-05-22 20:36:31 +000060 public:
61 static char ID; // Pass identification, replacement for typeid.
Reid Kleckner7bb07382015-02-18 23:17:41 +000062
Eugene Zelenkof1933322017-09-22 23:46:57 +000063 DwarfEHPrepare() : FunctionPass(ID) {}
Duncan Sandsd6fb6502009-05-22 20:36:31 +000064
Craig Topper4584cd52014-03-07 09:26:03 +000065 bool runOnFunction(Function &Fn) override;
Duncan Sandsd6fb6502009-05-22 20:36:31 +000066
Yaron Keren66b0ceb2014-09-14 20:36:28 +000067 bool doFinalization(Module &M) override {
68 RewindFunction = nullptr;
69 return false;
70 }
71
Reid Klecknerbe0a0502015-03-09 22:45:16 +000072 void getAnalysisUsage(AnalysisUsage &AU) const override;
73
Mehdi Amini117296c2016-10-01 02:56:57 +000074 StringRef getPassName() const override {
Duncan Sandsd6fb6502009-05-22 20:36:31 +000075 return "Exception handling preparation";
76 }
Duncan Sandsd6fb6502009-05-22 20:36:31 +000077 };
Eugene Zelenkof1933322017-09-22 23:46:57 +000078
Duncan Sandsd6fb6502009-05-22 20:36:31 +000079} // end anonymous namespace
80
81char DwarfEHPrepare::ID = 0;
Eugene Zelenkof1933322017-09-22 23:46:57 +000082
Matthias Braun1527baa2017-05-25 21:26:32 +000083INITIALIZE_PASS_BEGIN(DwarfEHPrepare, DEBUG_TYPE,
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000084 "Prepare DWARF exceptions", false, false)
Reid Klecknerbe0a0502015-03-09 22:45:16 +000085INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000086INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
Reid Klecknerbe0a0502015-03-09 22:45:16 +000087INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
Matthias Braun1527baa2017-05-25 21:26:32 +000088INITIALIZE_PASS_END(DwarfEHPrepare, DEBUG_TYPE,
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000089 "Prepare DWARF exceptions", false, false)
Duncan Sandsd6fb6502009-05-22 20:36:31 +000090
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000091FunctionPass *llvm::createDwarfEHPass() { return new DwarfEHPrepare(); }
Duncan Sandsd6fb6502009-05-22 20:36:31 +000092
Reid Klecknerbe0a0502015-03-09 22:45:16 +000093void DwarfEHPrepare::getAnalysisUsage(AnalysisUsage &AU) const {
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000094 AU.addRequired<TargetPassConfig>();
Reid Klecknerbe0a0502015-03-09 22:45:16 +000095 AU.addRequired<TargetTransformInfoWrapperPass>();
96 AU.addRequired<DominatorTreeWrapperPass>();
97}
98
Bill Wendling8c090402012-01-28 01:17:56 +000099/// GetExceptionObject - Return the exception object from the value passed into
100/// the 'resume' instruction (typically an aggregate). Clean up any dead
101/// instructions, including the 'resume' instruction.
Bill Wendling27489fe2012-05-17 17:59:51 +0000102Value *DwarfEHPrepare::GetExceptionObject(ResumeInst *RI) {
Bill Wendling8c090402012-01-28 01:17:56 +0000103 Value *V = RI->getOperand(0);
Craig Topperc0196b12014-04-14 00:51:57 +0000104 Value *ExnObj = nullptr;
Bill Wendling8c090402012-01-28 01:17:56 +0000105 InsertValueInst *SelIVI = dyn_cast<InsertValueInst>(V);
Craig Topperc0196b12014-04-14 00:51:57 +0000106 LoadInst *SelLoad = nullptr;
107 InsertValueInst *ExcIVI = nullptr;
Bill Wendling8c090402012-01-28 01:17:56 +0000108 bool EraseIVIs = false;
109
110 if (SelIVI) {
111 if (SelIVI->getNumIndices() == 1 && *SelIVI->idx_begin() == 1) {
112 ExcIVI = dyn_cast<InsertValueInst>(SelIVI->getOperand(0));
113 if (ExcIVI && isa<UndefValue>(ExcIVI->getOperand(0)) &&
114 ExcIVI->getNumIndices() == 1 && *ExcIVI->idx_begin() == 0) {
Bill Wendling27489fe2012-05-17 17:59:51 +0000115 ExnObj = ExcIVI->getOperand(1);
Bill Wendling8c090402012-01-28 01:17:56 +0000116 SelLoad = dyn_cast<LoadInst>(SelIVI->getOperand(1));
117 EraseIVIs = true;
118 }
119 }
120 }
121
122 if (!ExnObj)
123 ExnObj = ExtractValueInst::Create(RI->getOperand(0), 0, "exn.obj", RI);
124
125 RI->eraseFromParent();
126
127 if (EraseIVIs) {
Benjamin Kramereb63e4d2015-01-29 13:26:50 +0000128 if (SelIVI->use_empty())
Bill Wendling8c090402012-01-28 01:17:56 +0000129 SelIVI->eraseFromParent();
Benjamin Kramereb63e4d2015-01-29 13:26:50 +0000130 if (ExcIVI->use_empty())
Bill Wendling8c090402012-01-28 01:17:56 +0000131 ExcIVI->eraseFromParent();
Benjamin Kramereb63e4d2015-01-29 13:26:50 +0000132 if (SelLoad && SelLoad->use_empty())
Bill Wendling8c090402012-01-28 01:17:56 +0000133 SelLoad->eraseFromParent();
134 }
135
136 return ExnObj;
137}
138
Reid Klecknerbe0a0502015-03-09 22:45:16 +0000139/// Replace resumes that are not reachable from a cleanup landing pad with
140/// unreachable and then simplify those blocks.
141size_t DwarfEHPrepare::pruneUnreachableResumes(
142 Function &Fn, SmallVectorImpl<ResumeInst *> &Resumes,
143 SmallVectorImpl<LandingPadInst *> &CleanupLPads) {
144 BitVector ResumeReachable(Resumes.size());
145 size_t ResumeIndex = 0;
146 for (auto *RI : Resumes) {
147 for (auto *LP : CleanupLPads) {
148 if (isPotentiallyReachable(LP, RI, DT)) {
149 ResumeReachable.set(ResumeIndex);
150 break;
151 }
152 }
153 ++ResumeIndex;
154 }
155
156 // If everything is reachable, there is no change.
157 if (ResumeReachable.all())
158 return Resumes.size();
159
160 const TargetTransformInfo &TTI =
161 getAnalysis<TargetTransformInfoWrapperPass>().getTTI(Fn);
162 LLVMContext &Ctx = Fn.getContext();
163
164 // Otherwise, insert unreachable instructions and call simplifycfg.
165 size_t ResumesLeft = 0;
166 for (size_t I = 0, E = Resumes.size(); I < E; ++I) {
167 ResumeInst *RI = Resumes[I];
168 if (ResumeReachable[I]) {
169 Resumes[ResumesLeft++] = RI;
170 } else {
171 BasicBlock *BB = RI->getParent();
172 new UnreachableInst(Ctx, RI);
173 RI->eraseFromParent();
Sanjay Patel4c33d522017-10-04 20:26:25 +0000174 simplifyCFG(BB, TTI);
Reid Klecknerbe0a0502015-03-09 22:45:16 +0000175 }
176 }
177 Resumes.resize(ResumesLeft);
178 return ResumesLeft;
179}
180
Bill Wendling1cdd7fd2011-08-17 19:48:49 +0000181/// InsertUnwindResumeCalls - Convert the ResumeInsts that are still present
182/// into calls to the appropriate _Unwind_Resume function.
Bill Wendling478f58c2011-11-07 23:36:48 +0000183bool DwarfEHPrepare::InsertUnwindResumeCalls(Function &Fn) {
Bill Wendling1cdd7fd2011-08-17 19:48:49 +0000184 SmallVector<ResumeInst*, 16> Resumes;
Reid Klecknerbe0a0502015-03-09 22:45:16 +0000185 SmallVector<LandingPadInst*, 16> CleanupLPads;
Benjamin Kramereb63e4d2015-01-29 13:26:50 +0000186 for (BasicBlock &BB : Fn) {
187 if (auto *RI = dyn_cast<ResumeInst>(BB.getTerminator()))
Bill Wendling8ac20412011-08-25 23:48:11 +0000188 Resumes.push_back(RI);
David Majnemer7fddecc2015-06-17 20:52:32 +0000189 if (auto *LP = BB.getLandingPadInst())
Reid Klecknerbe0a0502015-03-09 22:45:16 +0000190 if (LP->isCleanup())
191 CleanupLPads.push_back(LP);
Bill Wendling8ac20412011-08-25 23:48:11 +0000192 }
Bill Wendling1cdd7fd2011-08-17 19:48:49 +0000193
194 if (Resumes.empty())
Kai Nackee1823b62013-05-31 16:30:36 +0000195 return false;
Bill Wendling1cdd7fd2011-08-17 19:48:49 +0000196
Heejin Ahnb4be38f2018-05-17 20:52:03 +0000197 // Check the personality, don't do anything if it's scope-based.
David Majnemer7fddecc2015-06-17 20:52:32 +0000198 EHPersonality Pers = classifyEHPersonality(Fn.getPersonalityFn());
Heejin Ahnb4be38f2018-05-17 20:52:03 +0000199 if (isScopedEHPersonality(Pers))
David Majnemer7fddecc2015-06-17 20:52:32 +0000200 return false;
201
Chandler Carruth301ed0c2015-02-20 02:15:36 +0000202 LLVMContext &Ctx = Fn.getContext();
Reid Klecknerbe0a0502015-03-09 22:45:16 +0000203
204 size_t ResumesLeft = pruneUnreachableResumes(Fn, Resumes, CleanupLPads);
205 if (ResumesLeft == 0)
206 return true; // We pruned them all.
207
208 // Find the rewind function if we didn't already.
Bill Wendling1cdd7fd2011-08-17 19:48:49 +0000209 if (!RewindFunction) {
Bill Wendling1cdd7fd2011-08-17 19:48:49 +0000210 FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx),
211 Type::getInt8PtrTy(Ctx), false);
212 const char *RewindName = TLI->getLibcallName(RTLIB::UNWIND_RESUME);
Bill Wendling478f58c2011-11-07 23:36:48 +0000213 RewindFunction = Fn.getParent()->getOrInsertFunction(RewindName, FTy);
Bill Wendling1cdd7fd2011-08-17 19:48:49 +0000214 }
215
216 // Create the basic block where the _Unwind_Resume call will live.
Reid Klecknerbe0a0502015-03-09 22:45:16 +0000217 if (ResumesLeft == 1) {
Bill Wendling8c090402012-01-28 01:17:56 +0000218 // Instead of creating a new BB and PHI node, just append the call to
219 // _Unwind_Resume to the end of the single resume block.
220 ResumeInst *RI = Resumes.front();
221 BasicBlock *UnwindBB = RI->getParent();
Bill Wendling27489fe2012-05-17 17:59:51 +0000222 Value *ExnObj = GetExceptionObject(RI);
Bill Wendling8c090402012-01-28 01:17:56 +0000223
224 // Call the _Unwind_Resume function.
225 CallInst *CI = CallInst::Create(RewindFunction, ExnObj, "", UnwindBB);
226 CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME));
227
228 // We never expect _Unwind_Resume to return.
229 new UnreachableInst(Ctx, UnwindBB);
230 return true;
231 }
232
Bill Wendling478f58c2011-11-07 23:36:48 +0000233 BasicBlock *UnwindBB = BasicBlock::Create(Ctx, "unwind_resume", &Fn);
Reid Klecknerbe0a0502015-03-09 22:45:16 +0000234 PHINode *PN = PHINode::Create(Type::getInt8PtrTy(Ctx), ResumesLeft,
Bill Wendling1cdd7fd2011-08-17 19:48:49 +0000235 "exn.obj", UnwindBB);
236
237 // Extract the exception object from the ResumeInst and add it to the PHI node
238 // that feeds the _Unwind_Resume call.
Benjamin Kramereb63e4d2015-01-29 13:26:50 +0000239 for (ResumeInst *RI : Resumes) {
Bill Wendling8c090402012-01-28 01:17:56 +0000240 BasicBlock *Parent = RI->getParent();
241 BranchInst::Create(UnwindBB, Parent);
Bill Wendling92492612012-01-20 00:53:28 +0000242
Bill Wendling27489fe2012-05-17 17:59:51 +0000243 Value *ExnObj = GetExceptionObject(RI);
Bill Wendling8c090402012-01-28 01:17:56 +0000244 PN->addIncoming(ExnObj, Parent);
Bill Wendling92492612012-01-20 00:53:28 +0000245
Bill Wendling478f58c2011-11-07 23:36:48 +0000246 ++NumResumesLowered;
Bill Wendling1cdd7fd2011-08-17 19:48:49 +0000247 }
248
249 // Call the function.
250 CallInst *CI = CallInst::Create(RewindFunction, PN, "", UnwindBB);
251 CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME));
252
253 // We never expect _Unwind_Resume to return.
254 new UnreachableInst(Ctx, UnwindBB);
255 return true;
256}
257
Duncan Sandsd6fb6502009-05-22 20:36:31 +0000258bool DwarfEHPrepare::runOnFunction(Function &Fn) {
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +0000259 const TargetMachine &TM =
260 getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
Reid Klecknerbe0a0502015-03-09 22:45:16 +0000261 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +0000262 TLI = TM.getSubtargetImpl(Fn)->getTargetLowering();
Bill Wendling478f58c2011-11-07 23:36:48 +0000263 bool Changed = InsertUnwindResumeCalls(Fn);
Reid Klecknerbe0a0502015-03-09 22:45:16 +0000264 DT = nullptr;
265 TLI = nullptr;
Duncan Sandsd6fb6502009-05-22 20:36:31 +0000266 return Changed;
267}