1 | //===- SjLjEHPrepare.cpp - Eliminate Invoke & Unwind instructions ---------===// |
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 transformation is designed for use by code generators which use SjLj |
10 | // based exception handling. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "llvm/CodeGen/SjLjEHPrepare.h" |
15 | #include "llvm/ADT/SetVector.h" |
16 | #include "llvm/ADT/SmallPtrSet.h" |
17 | #include "llvm/ADT/SmallVector.h" |
18 | #include "llvm/ADT/Statistic.h" |
19 | #include "llvm/CodeGen/Passes.h" |
20 | #include "llvm/IR/Constants.h" |
21 | #include "llvm/IR/DataLayout.h" |
22 | #include "llvm/IR/DerivedTypes.h" |
23 | #include "llvm/IR/IRBuilder.h" |
24 | #include "llvm/IR/Instructions.h" |
25 | #include "llvm/IR/Intrinsics.h" |
26 | #include "llvm/IR/Module.h" |
27 | #include "llvm/InitializePasses.h" |
28 | #include "llvm/Pass.h" |
29 | #include "llvm/Support/Debug.h" |
30 | #include "llvm/Support/raw_ostream.h" |
31 | #include "llvm/Target/TargetMachine.h" |
32 | #include "llvm/Transforms/Utils/Local.h" |
33 | using namespace llvm; |
34 | |
35 | #define DEBUG_TYPE "sjlj-eh-prepare" |
36 | |
37 | STATISTIC(NumInvokes, "Number of invokes replaced" ); |
38 | STATISTIC(NumSpilled, "Number of registers live across unwind edges" ); |
39 | |
40 | namespace { |
41 | class SjLjEHPrepareImpl { |
42 | IntegerType *DataTy = nullptr; |
43 | Type *doubleUnderDataTy = nullptr; |
44 | Type *doubleUnderJBufTy = nullptr; |
45 | Type *FunctionContextTy = nullptr; |
46 | FunctionCallee RegisterFn; |
47 | FunctionCallee UnregisterFn; |
48 | Function *BuiltinSetupDispatchFn = nullptr; |
49 | Function *FrameAddrFn = nullptr; |
50 | Function *StackAddrFn = nullptr; |
51 | Function *StackRestoreFn = nullptr; |
52 | Function *LSDAAddrFn = nullptr; |
53 | Function *CallSiteFn = nullptr; |
54 | Function *FuncCtxFn = nullptr; |
55 | AllocaInst *FuncCtx = nullptr; |
56 | const TargetMachine *TM = nullptr; |
57 | |
58 | public: |
59 | explicit SjLjEHPrepareImpl(const TargetMachine *TM = nullptr) : TM(TM) {} |
60 | bool doInitialization(Module &M); |
61 | bool runOnFunction(Function &F); |
62 | |
63 | private: |
64 | bool setupEntryBlockAndCallSites(Function &F); |
65 | void substituteLPadValues(LandingPadInst *LPI, Value *ExnVal, Value *SelVal); |
66 | Value *setupFunctionContext(Function &F, ArrayRef<LandingPadInst *> LPads); |
67 | void lowerIncomingArguments(Function &F); |
68 | void lowerAcrossUnwindEdges(Function &F, ArrayRef<InvokeInst *> Invokes); |
69 | void insertCallSiteStore(Instruction *I, int Number); |
70 | }; |
71 | |
72 | class SjLjEHPrepare : public FunctionPass { |
73 | SjLjEHPrepareImpl Impl; |
74 | |
75 | public: |
76 | static char ID; // Pass identification, replacement for typeid |
77 | explicit SjLjEHPrepare(const TargetMachine *TM = nullptr) |
78 | : FunctionPass(ID), Impl(TM) {} |
79 | bool doInitialization(Module &M) override { return Impl.doInitialization(M); } |
80 | bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }; |
81 | |
82 | StringRef getPassName() const override { |
83 | return "SJLJ Exception Handling preparation" ; |
84 | } |
85 | }; |
86 | |
87 | } // end anonymous namespace |
88 | |
89 | PreservedAnalyses SjLjEHPreparePass::run(Function &F, |
90 | FunctionAnalysisManager &FAM) { |
91 | SjLjEHPrepareImpl Impl(TM); |
92 | Impl.doInitialization(M&: *F.getParent()); |
93 | bool Changed = Impl.runOnFunction(F); |
94 | return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); |
95 | } |
96 | |
97 | char SjLjEHPrepare::ID = 0; |
98 | INITIALIZE_PASS(SjLjEHPrepare, DEBUG_TYPE, "Prepare SjLj exceptions" , |
99 | false, false) |
100 | |
101 | // Public Interface To the SjLjEHPrepare pass. |
102 | FunctionPass *llvm::createSjLjEHPreparePass(const TargetMachine *TM) { |
103 | return new SjLjEHPrepare(TM); |
104 | } |
105 | |
106 | // doInitialization - Set up decalarations and types needed to process |
107 | // exceptions. |
108 | bool SjLjEHPrepareImpl::doInitialization(Module &M) { |
109 | // Build the function context structure. |
110 | // builtin_setjmp uses a five word jbuf |
111 | Type *VoidPtrTy = PointerType::getUnqual(C&: M.getContext()); |
112 | unsigned DataBits = |
113 | TM ? TM->getSjLjDataSize() : TargetMachine::DefaultSjLjDataSize; |
114 | DataTy = Type::getIntNTy(C&: M.getContext(), N: DataBits); |
115 | doubleUnderDataTy = ArrayType::get(ElementType: DataTy, NumElements: 4); |
116 | doubleUnderJBufTy = ArrayType::get(ElementType: VoidPtrTy, NumElements: 5); |
117 | FunctionContextTy = StructType::get(elt1: VoidPtrTy, // __prev |
118 | elts: DataTy, // call_site |
119 | elts: doubleUnderDataTy, // __data |
120 | elts: VoidPtrTy, // __personality |
121 | elts: VoidPtrTy, // __lsda |
122 | elts: doubleUnderJBufTy // __jbuf |
123 | ); |
124 | |
125 | return false; |
126 | } |
127 | |
128 | /// insertCallSiteStore - Insert a store of the call-site value to the |
129 | /// function context |
130 | void SjLjEHPrepareImpl::insertCallSiteStore(Instruction *I, int Number) { |
131 | IRBuilder<> Builder(I); |
132 | |
133 | // Get a reference to the call_site field. |
134 | Type *Int32Ty = Type::getInt32Ty(C&: I->getContext()); |
135 | Value *Zero = ConstantInt::get(Ty: Int32Ty, V: 0); |
136 | Value *One = ConstantInt::get(Ty: Int32Ty, V: 1); |
137 | Value *Idxs[2] = { Zero, One }; |
138 | Value *CallSite = |
139 | Builder.CreateGEP(Ty: FunctionContextTy, Ptr: FuncCtx, IdxList: Idxs, Name: "call_site" ); |
140 | |
141 | // Insert a store of the call-site number |
142 | ConstantInt *CallSiteNoC = ConstantInt::get(Ty: DataTy, V: Number); |
143 | Builder.CreateStore(Val: CallSiteNoC, Ptr: CallSite, isVolatile: true /*volatile*/); |
144 | } |
145 | |
146 | /// MarkBlocksLiveIn - Insert BB and all of its predecessors into LiveBBs until |
147 | /// we reach blocks we've already seen. |
148 | static void MarkBlocksLiveIn(BasicBlock *BB, |
149 | SmallPtrSetImpl<BasicBlock *> &LiveBBs) { |
150 | if (!LiveBBs.insert(Ptr: BB).second) |
151 | return; // already been here. |
152 | |
153 | df_iterator_default_set<BasicBlock*> Visited; |
154 | |
155 | for (BasicBlock *B : inverse_depth_first_ext(G: BB, S&: Visited)) |
156 | LiveBBs.insert(Ptr: B); |
157 | } |
158 | |
159 | /// substituteLPadValues - Substitute the values returned by the landingpad |
160 | /// instruction with those returned by the personality function. |
161 | void SjLjEHPrepareImpl::substituteLPadValues(LandingPadInst *LPI, Value *ExnVal, |
162 | Value *SelVal) { |
163 | SmallVector<Value *, 8> UseWorkList(LPI->users()); |
164 | while (!UseWorkList.empty()) { |
165 | Value *Val = UseWorkList.pop_back_val(); |
166 | auto *EVI = dyn_cast<ExtractValueInst>(Val); |
167 | if (!EVI) |
168 | continue; |
169 | if (EVI->getNumIndices() != 1) |
170 | continue; |
171 | if (*EVI->idx_begin() == 0) |
172 | EVI->replaceAllUsesWith(V: ExnVal); |
173 | else if (*EVI->idx_begin() == 1) |
174 | EVI->replaceAllUsesWith(V: SelVal); |
175 | if (EVI->use_empty()) |
176 | EVI->eraseFromParent(); |
177 | } |
178 | |
179 | if (LPI->use_empty()) |
180 | return; |
181 | |
182 | // There are still some uses of LPI. Construct an aggregate with the exception |
183 | // values and replace the LPI with that aggregate. |
184 | Type *LPadType = LPI->getType(); |
185 | Value *LPadVal = PoisonValue::get(T: LPadType); |
186 | auto *SelI = cast<Instruction>(Val: SelVal); |
187 | IRBuilder<> Builder(SelI->getParent(), std::next(x: SelI->getIterator())); |
188 | LPadVal = Builder.CreateInsertValue(Agg: LPadVal, Val: ExnVal, Idxs: 0, Name: "lpad.val" ); |
189 | LPadVal = Builder.CreateInsertValue(Agg: LPadVal, Val: SelVal, Idxs: 1, Name: "lpad.val" ); |
190 | |
191 | LPI->replaceAllUsesWith(V: LPadVal); |
192 | } |
193 | |
194 | /// setupFunctionContext - Allocate the function context on the stack and fill |
195 | /// it with all of the data that we know at this point. |
196 | Value * |
197 | SjLjEHPrepareImpl::setupFunctionContext(Function &F, |
198 | ArrayRef<LandingPadInst *> LPads) { |
199 | BasicBlock *EntryBB = &F.front(); |
200 | |
201 | // Create an alloca for the incoming jump buffer ptr and the new jump buffer |
202 | // that needs to be restored on all exits from the function. This is an alloca |
203 | // because the value needs to be added to the global context list. |
204 | auto &DL = F.getParent()->getDataLayout(); |
205 | const Align Alignment = DL.getPrefTypeAlign(Ty: FunctionContextTy); |
206 | FuncCtx = new AllocaInst(FunctionContextTy, DL.getAllocaAddrSpace(), nullptr, |
207 | Alignment, "fn_context" , &EntryBB->front()); |
208 | |
209 | // Fill in the function context structure. |
210 | for (LandingPadInst *LPI : LPads) { |
211 | IRBuilder<> Builder(LPI->getParent(), |
212 | LPI->getParent()->getFirstInsertionPt()); |
213 | |
214 | // Reference the __data field. |
215 | Value *FCData = |
216 | Builder.CreateConstGEP2_32(Ty: FunctionContextTy, Ptr: FuncCtx, Idx0: 0, Idx1: 2, Name: "__data" ); |
217 | |
218 | // The exception values come back in context->__data[0]. |
219 | Value *ExceptionAddr = Builder.CreateConstGEP2_32(Ty: doubleUnderDataTy, Ptr: FCData, |
220 | Idx0: 0, Idx1: 0, Name: "exception_gep" ); |
221 | Value *ExnVal = Builder.CreateLoad(Ty: DataTy, Ptr: ExceptionAddr, isVolatile: true, Name: "exn_val" ); |
222 | ExnVal = Builder.CreateIntToPtr(V: ExnVal, DestTy: Builder.getPtrTy()); |
223 | |
224 | Value *SelectorAddr = Builder.CreateConstGEP2_32(Ty: doubleUnderDataTy, Ptr: FCData, |
225 | Idx0: 0, Idx1: 1, Name: "exn_selector_gep" ); |
226 | Value *SelVal = |
227 | Builder.CreateLoad(Ty: DataTy, Ptr: SelectorAddr, isVolatile: true, Name: "exn_selector_val" ); |
228 | |
229 | // SelVal must be Int32Ty, so trunc it |
230 | SelVal = Builder.CreateTrunc(V: SelVal, DestTy: Type::getInt32Ty(C&: F.getContext())); |
231 | |
232 | substituteLPadValues(LPI, ExnVal, SelVal); |
233 | } |
234 | |
235 | // Personality function |
236 | IRBuilder<> Builder(EntryBB->getTerminator()); |
237 | Value *PersonalityFn = F.getPersonalityFn(); |
238 | Value *PersonalityFieldPtr = Builder.CreateConstGEP2_32( |
239 | Ty: FunctionContextTy, Ptr: FuncCtx, Idx0: 0, Idx1: 3, Name: "pers_fn_gep" ); |
240 | Builder.CreateStore(Val: PersonalityFn, Ptr: PersonalityFieldPtr, /*isVolatile=*/true); |
241 | |
242 | // LSDA address |
243 | Value *LSDA = Builder.CreateCall(Callee: LSDAAddrFn, Args: {}, Name: "lsda_addr" ); |
244 | Value *LSDAFieldPtr = |
245 | Builder.CreateConstGEP2_32(Ty: FunctionContextTy, Ptr: FuncCtx, Idx0: 0, Idx1: 4, Name: "lsda_gep" ); |
246 | Builder.CreateStore(Val: LSDA, Ptr: LSDAFieldPtr, /*isVolatile=*/true); |
247 | |
248 | return FuncCtx; |
249 | } |
250 | |
251 | /// lowerIncomingArguments - To avoid having to handle incoming arguments |
252 | /// specially, we lower each arg to a copy instruction in the entry block. This |
253 | /// ensures that the argument value itself cannot be live out of the entry |
254 | /// block. |
255 | void SjLjEHPrepareImpl::lowerIncomingArguments(Function &F) { |
256 | BasicBlock::iterator AfterAllocaInsPt = F.begin()->begin(); |
257 | while (isa<AllocaInst>(Val: AfterAllocaInsPt) && |
258 | cast<AllocaInst>(Val&: AfterAllocaInsPt)->isStaticAlloca()) |
259 | ++AfterAllocaInsPt; |
260 | assert(AfterAllocaInsPt != F.front().end()); |
261 | |
262 | for (auto &AI : F.args()) { |
263 | // Swift error really is a register that we model as memory -- instruction |
264 | // selection will perform mem-to-reg for us and spill/reload appropriately |
265 | // around calls that clobber it. There is no need to spill this |
266 | // value to the stack and doing so would not be allowed. |
267 | if (AI.isSwiftError()) |
268 | continue; |
269 | |
270 | Type *Ty = AI.getType(); |
271 | |
272 | // Use 'select i8 true, %arg, undef' to simulate a 'no-op' instruction. |
273 | Value *TrueValue = ConstantInt::getTrue(Context&: F.getContext()); |
274 | Value *UndefValue = UndefValue::get(T: Ty); |
275 | Instruction *SI = SelectInst::Create( |
276 | C: TrueValue, S1: &AI, S2: UndefValue, NameStr: AI.getName() + ".tmp" , InsertBefore: &*AfterAllocaInsPt); |
277 | AI.replaceAllUsesWith(V: SI); |
278 | |
279 | // Reset the operand, because it was clobbered by the RAUW above. |
280 | SI->setOperand(i: 1, Val: &AI); |
281 | } |
282 | } |
283 | |
284 | /// lowerAcrossUnwindEdges - Find all variables which are alive across an unwind |
285 | /// edge and spill them. |
286 | void SjLjEHPrepareImpl::lowerAcrossUnwindEdges(Function &F, |
287 | ArrayRef<InvokeInst *> Invokes) { |
288 | // Finally, scan the code looking for instructions with bad live ranges. |
289 | for (BasicBlock &BB : F) { |
290 | for (Instruction &Inst : BB) { |
291 | // Ignore obvious cases we don't have to handle. In particular, most |
292 | // instructions either have no uses or only have a single use inside the |
293 | // current block. Ignore them quickly. |
294 | if (Inst.use_empty()) |
295 | continue; |
296 | if (Inst.hasOneUse() && |
297 | cast<Instruction>(Val: Inst.user_back())->getParent() == &BB && |
298 | !isa<PHINode>(Val: Inst.user_back())) |
299 | continue; |
300 | |
301 | // If this is an alloca in the entry block, it's not a real register |
302 | // value. |
303 | if (auto *AI = dyn_cast<AllocaInst>(Val: &Inst)) |
304 | if (AI->isStaticAlloca()) |
305 | continue; |
306 | |
307 | // Avoid iterator invalidation by copying users to a temporary vector. |
308 | SmallVector<Instruction *, 16> Users; |
309 | for (User *U : Inst.users()) { |
310 | Instruction *UI = cast<Instruction>(Val: U); |
311 | if (UI->getParent() != &BB || isa<PHINode>(Val: UI)) |
312 | Users.push_back(Elt: UI); |
313 | } |
314 | |
315 | // Find all of the blocks that this value is live in. |
316 | SmallPtrSet<BasicBlock *, 32> LiveBBs; |
317 | LiveBBs.insert(Ptr: &BB); |
318 | while (!Users.empty()) { |
319 | Instruction *U = Users.pop_back_val(); |
320 | |
321 | if (!isa<PHINode>(Val: U)) { |
322 | MarkBlocksLiveIn(BB: U->getParent(), LiveBBs); |
323 | } else { |
324 | // Uses for a PHI node occur in their predecessor block. |
325 | PHINode *PN = cast<PHINode>(Val: U); |
326 | for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) |
327 | if (PN->getIncomingValue(i) == &Inst) |
328 | MarkBlocksLiveIn(BB: PN->getIncomingBlock(i), LiveBBs); |
329 | } |
330 | } |
331 | |
332 | // Now that we know all of the blocks that this thing is live in, see if |
333 | // it includes any of the unwind locations. |
334 | bool NeedsSpill = false; |
335 | for (InvokeInst *Invoke : Invokes) { |
336 | BasicBlock *UnwindBlock = Invoke->getUnwindDest(); |
337 | if (UnwindBlock != &BB && LiveBBs.count(Ptr: UnwindBlock)) { |
338 | LLVM_DEBUG(dbgs() << "SJLJ Spill: " << Inst << " around " |
339 | << UnwindBlock->getName() << "\n" ); |
340 | NeedsSpill = true; |
341 | break; |
342 | } |
343 | } |
344 | |
345 | // If we decided we need a spill, do it. |
346 | // FIXME: Spilling this way is overkill, as it forces all uses of |
347 | // the value to be reloaded from the stack slot, even those that aren't |
348 | // in the unwind blocks. We should be more selective. |
349 | if (NeedsSpill) { |
350 | DemoteRegToStack(X&: Inst, VolatileLoads: true); |
351 | ++NumSpilled; |
352 | } |
353 | } |
354 | } |
355 | |
356 | // Go through the landing pads and remove any PHIs there. |
357 | for (InvokeInst *Invoke : Invokes) { |
358 | BasicBlock *UnwindBlock = Invoke->getUnwindDest(); |
359 | LandingPadInst *LPI = UnwindBlock->getLandingPadInst(); |
360 | |
361 | // Place PHIs into a set to avoid invalidating the iterator. |
362 | SmallPtrSet<PHINode *, 8> PHIsToDemote; |
363 | for (BasicBlock::iterator PN = UnwindBlock->begin(); isa<PHINode>(Val: PN); ++PN) |
364 | PHIsToDemote.insert(Ptr: cast<PHINode>(Val&: PN)); |
365 | if (PHIsToDemote.empty()) |
366 | continue; |
367 | |
368 | // Demote the PHIs to the stack. |
369 | for (PHINode *PN : PHIsToDemote) |
370 | DemotePHIToStack(P: PN); |
371 | |
372 | // Move the landingpad instruction back to the top of the landing pad block. |
373 | LPI->moveBefore(MovePos: &UnwindBlock->front()); |
374 | } |
375 | } |
376 | |
377 | /// setupEntryBlockAndCallSites - Setup the entry block by creating and filling |
378 | /// the function context and marking the call sites with the appropriate |
379 | /// values. These values are used by the DWARF EH emitter. |
380 | bool SjLjEHPrepareImpl::setupEntryBlockAndCallSites(Function &F) { |
381 | SmallVector<ReturnInst *, 16> Returns; |
382 | SmallVector<InvokeInst *, 16> Invokes; |
383 | SmallSetVector<LandingPadInst *, 16> LPads; |
384 | |
385 | // Look through the terminators of the basic blocks to find invokes. |
386 | for (BasicBlock &BB : F) |
387 | if (auto *II = dyn_cast<InvokeInst>(Val: BB.getTerminator())) { |
388 | if (Function *Callee = II->getCalledFunction()) |
389 | if (Callee->getIntrinsicID() == Intrinsic::donothing) { |
390 | // Remove the NOP invoke. |
391 | BranchInst::Create(IfTrue: II->getNormalDest(), InsertBefore: II); |
392 | II->eraseFromParent(); |
393 | continue; |
394 | } |
395 | |
396 | Invokes.push_back(Elt: II); |
397 | LPads.insert(X: II->getUnwindDest()->getLandingPadInst()); |
398 | } else if (auto *RI = dyn_cast<ReturnInst>(Val: BB.getTerminator())) { |
399 | Returns.push_back(Elt: RI); |
400 | } |
401 | |
402 | if (Invokes.empty()) |
403 | return false; |
404 | |
405 | NumInvokes += Invokes.size(); |
406 | |
407 | lowerIncomingArguments(F); |
408 | lowerAcrossUnwindEdges(F, Invokes); |
409 | |
410 | Value *FuncCtx = |
411 | setupFunctionContext(F, LPads: ArrayRef(LPads.begin(), LPads.end())); |
412 | BasicBlock *EntryBB = &F.front(); |
413 | IRBuilder<> Builder(EntryBB->getTerminator()); |
414 | |
415 | // Get a reference to the jump buffer. |
416 | Value *JBufPtr = |
417 | Builder.CreateConstGEP2_32(Ty: FunctionContextTy, Ptr: FuncCtx, Idx0: 0, Idx1: 5, Name: "jbuf_gep" ); |
418 | |
419 | // Save the frame pointer. |
420 | Value *FramePtr = Builder.CreateConstGEP2_32(Ty: doubleUnderJBufTy, Ptr: JBufPtr, Idx0: 0, Idx1: 0, |
421 | Name: "jbuf_fp_gep" ); |
422 | |
423 | Value *Val = Builder.CreateCall(Callee: FrameAddrFn, Args: Builder.getInt32(C: 0), Name: "fp" ); |
424 | Builder.CreateStore(Val, Ptr: FramePtr, /*isVolatile=*/true); |
425 | |
426 | // Save the stack pointer. |
427 | Value *StackPtr = Builder.CreateConstGEP2_32(Ty: doubleUnderJBufTy, Ptr: JBufPtr, Idx0: 0, Idx1: 2, |
428 | Name: "jbuf_sp_gep" ); |
429 | |
430 | Val = Builder.CreateCall(Callee: StackAddrFn, Args: {}, Name: "sp" ); |
431 | Builder.CreateStore(Val, Ptr: StackPtr, /*isVolatile=*/true); |
432 | |
433 | // Call the setup_dispatch intrinsic. It fills in the rest of the jmpbuf. |
434 | Builder.CreateCall(Callee: BuiltinSetupDispatchFn, Args: {}); |
435 | |
436 | // Store a pointer to the function context so that the back-end will know |
437 | // where to look for it. |
438 | Builder.CreateCall(Callee: FuncCtxFn, Args: FuncCtx); |
439 | |
440 | // At this point, we are all set up, update the invoke instructions to mark |
441 | // their call_site values. |
442 | for (unsigned I = 0, E = Invokes.size(); I != E; ++I) { |
443 | insertCallSiteStore(I: Invokes[I], Number: I + 1); |
444 | |
445 | ConstantInt *CallSiteNum = |
446 | ConstantInt::get(Ty: Type::getInt32Ty(C&: F.getContext()), V: I + 1); |
447 | |
448 | // Record the call site value for the back end so it stays associated with |
449 | // the invoke. |
450 | CallInst::Create(Func: CallSiteFn, Args: CallSiteNum, NameStr: "" , InsertBefore: Invokes[I]); |
451 | } |
452 | |
453 | // Mark call instructions that aren't nounwind as no-action (call_site == |
454 | // -1). Skip the entry block, as prior to then, no function context has been |
455 | // created for this function and any unexpected exceptions thrown will go |
456 | // directly to the caller's context, which is what we want anyway, so no need |
457 | // to do anything here. |
458 | for (BasicBlock &BB : F) { |
459 | if (&BB == &F.front()) |
460 | continue; |
461 | for (Instruction &I : BB) |
462 | if (I.mayThrow()) |
463 | insertCallSiteStore(I: &I, Number: -1); |
464 | } |
465 | |
466 | // Register the function context and make sure it's known to not throw |
467 | CallInst *Register = |
468 | CallInst::Create(Func: RegisterFn, Args: FuncCtx, NameStr: "" , InsertBefore: EntryBB->getTerminator()); |
469 | Register->setDoesNotThrow(); |
470 | |
471 | // Following any allocas not in the entry block, update the saved SP in the |
472 | // jmpbuf to the new value. |
473 | for (BasicBlock &BB : F) { |
474 | if (&BB == &F.front()) |
475 | continue; |
476 | for (Instruction &I : BB) { |
477 | if (auto *CI = dyn_cast<CallInst>(Val: &I)) { |
478 | if (CI->getCalledFunction() != StackRestoreFn) |
479 | continue; |
480 | } else if (!isa<AllocaInst>(Val: &I)) { |
481 | continue; |
482 | } |
483 | Instruction *StackAddr = CallInst::Create(Func: StackAddrFn, NameStr: "sp" ); |
484 | StackAddr->insertAfter(InsertPos: &I); |
485 | new StoreInst(StackAddr, StackPtr, true, StackAddr->getNextNode()); |
486 | } |
487 | } |
488 | |
489 | // Finally, for any returns from this function, if this function contains an |
490 | // invoke, add a call to unregister the function context. |
491 | for (ReturnInst *Return : Returns) { |
492 | Instruction *InsertPoint = Return; |
493 | if (CallInst *CI = Return->getParent()->getTerminatingMustTailCall()) |
494 | InsertPoint = CI; |
495 | CallInst::Create(Func: UnregisterFn, Args: FuncCtx, NameStr: "" , InsertBefore: InsertPoint); |
496 | } |
497 | |
498 | return true; |
499 | } |
500 | |
501 | bool SjLjEHPrepareImpl::runOnFunction(Function &F) { |
502 | Module &M = *F.getParent(); |
503 | RegisterFn = M.getOrInsertFunction( |
504 | Name: "_Unwind_SjLj_Register" , RetTy: Type::getVoidTy(C&: M.getContext()), |
505 | Args: PointerType::getUnqual(ElementType: FunctionContextTy)); |
506 | UnregisterFn = M.getOrInsertFunction( |
507 | Name: "_Unwind_SjLj_Unregister" , RetTy: Type::getVoidTy(C&: M.getContext()), |
508 | Args: PointerType::getUnqual(ElementType: FunctionContextTy)); |
509 | |
510 | PointerType *AllocaPtrTy = M.getDataLayout().getAllocaPtrType(Ctx&: M.getContext()); |
511 | |
512 | FrameAddrFn = |
513 | Intrinsic::getDeclaration(M: &M, Intrinsic::id: frameaddress, Tys: {AllocaPtrTy}); |
514 | StackAddrFn = |
515 | Intrinsic::getDeclaration(M: &M, Intrinsic::id: stacksave, Tys: {AllocaPtrTy}); |
516 | StackRestoreFn = |
517 | Intrinsic::getDeclaration(M: &M, Intrinsic::id: stackrestore, Tys: {AllocaPtrTy}); |
518 | BuiltinSetupDispatchFn = |
519 | Intrinsic::getDeclaration(M: &M, Intrinsic::id: eh_sjlj_setup_dispatch); |
520 | LSDAAddrFn = Intrinsic::getDeclaration(M: &M, Intrinsic::id: eh_sjlj_lsda); |
521 | CallSiteFn = Intrinsic::getDeclaration(M: &M, Intrinsic::id: eh_sjlj_callsite); |
522 | FuncCtxFn = Intrinsic::getDeclaration(M: &M, Intrinsic::id: eh_sjlj_functioncontext); |
523 | |
524 | bool Res = setupEntryBlockAndCallSites(F); |
525 | return Res; |
526 | } |
527 | |