LLVM: lib/CodeGen/WasmEHPrepare.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
86#include "llvm/IR/IntrinsicsWebAssembly.h"
90
91using namespace llvm;
92
93#define DEBUG_TYPE "wasm-eh-prepare"
94
95namespace {
96class WasmEHPrepareImpl {
97 friend class WasmEHPrepare;
98
99 Type *LPadContextTy = nullptr;
100 GlobalVariable *LPadContextGV = nullptr;
101
102
103 Value *LPadIndexField = nullptr;
104 Value *LSDAField = nullptr;
105 Value *SelectorField = nullptr;
106
107 Function *ThrowF = nullptr;
108 Function *LPadIndexF = nullptr;
109 Function *LSDAF = nullptr;
110 Function *GetExnF = nullptr;
111 Function *CatchF = nullptr;
112 Function *GetSelectorF = nullptr;
114 nullptr;
115
118 void prepareEHPad(BasicBlock *BB, bool NeedPersonality, unsigned Index = 0);
119
120public:
121 WasmEHPrepareImpl() = default;
122 WasmEHPrepareImpl(Type *LPadContextTy_) : LPadContextTy(LPadContextTy_) {}
124};
125
127 WasmEHPrepareImpl P;
128
129public:
130 static char ID;
131
135
137 return "WebAssembly Exception handling preparation";
138 }
139};
140
141}
142
145 auto &Context = F.getContext();
148 auto *LPadContextTy =
149 StructType::get(I32Ty , PtrTy , I32Ty );
150 WasmEHPrepareImpl P(LPadContextTy);
151 bool Changed = P.runOnFunction(F);
153}
154
155char WasmEHPrepare::ID = 0;
157 "Prepare WebAssembly exceptions", false, false)
160
162
163bool WasmEHPrepare::doInitialization(Module &M) {
165 P.LPadContextTy = StructType::get(IRB.getInt32Ty(),
166 IRB.getPtrTy(),
167 IRB.getInt32Ty()
168 );
169 return false;
170}
171
172
173
174template
177 while (!WL.empty()) {
180 continue;
183 }
184}
185
186bool WasmEHPrepareImpl::runOnFunction(Function &F) {
187 bool Changed = false;
188 Changed |= prepareThrows(F);
189 Changed |= prepareEHPads(F);
190 return Changed;
191}
192
193bool WasmEHPrepareImpl::prepareThrows(Function &F) {
196 bool Changed = false;
197
198
200
201
202
203 for (User *U : ThrowF->users()) {
204
205
206 auto *ThrowI = cast(U);
207 if (ThrowI->getFunction() != &F)
208 continue;
209 Changed = true;
210 auto *BB = ThrowI->getParent();
213 IRB.SetInsertPoint(BB);
214 IRB.CreateUnreachable();
216 }
217
218 return Changed;
219}
220
221bool WasmEHPrepareImpl::prepareEHPads(Function &F) {
224
228 if (!BB.isEHPad())
229 continue;
230 auto *Pad = BB.getFirstNonPHI();
231 if (isa(Pad))
233 else if (isa(Pad))
235 }
236 if (CatchPads.empty() && CleanupPads.empty())
237 return false;
238
239 if (.hasPersonalityFn() ||
242 "' does not have a correct Wasm personality function "
243 "'__gxx_wasm_personality_v0'");
244 }
245 assert(F.hasPersonalityFn() && "Personality function not found");
246
247
248
249
250
251
252 LPadContextGV = cast(
253 M.getOrInsertGlobal("__wasm_lpad_context", LPadContextTy));
255
256 LPadIndexField = LPadContextGV;
257 LSDAField = IRB.CreateConstInBoundsGEP2_32(LPadContextTy, LPadContextGV, 0, 1,
258 "lsda_gep");
259 SelectorField = IRB.CreateConstInBoundsGEP2_32(LPadContextTy, LPadContextGV,
260 0, 2, "selector_gep");
261
262
263 LPadIndexF =
265
266
268
269
270 GetExnF =
272 GetSelectorF =
274
275
276
278
279
280 CallPersonalityF = M.getOrInsertFunction("_Unwind_CallPersonality",
281 IRB.getInt32Ty(), IRB.getPtrTy());
282 if (Function *F = dyn_cast(CallPersonalityF.getCallee()))
283 F->setDoesNotThrow();
284
285 unsigned Index = 0;
286 for (auto *BB : CatchPads) {
287 auto *CPI = cast(BB->getFirstNonPHI());
288
289
290 if (CPI->arg_size() == 1 &&
291 cast(CPI->getArgOperand(0))->isNullValue())
292 prepareEHPad(BB, false);
293 else
294 prepareEHPad(BB, true, Index++);
295 }
296
297
298 for (auto *BB : CleanupPads)
299 prepareEHPad(BB, false);
300
301 return true;
302}
303
304
305
306void WasmEHPrepareImpl::prepareEHPad(BasicBlock *BB, bool NeedPersonality,
307 unsigned Index) {
311
312 auto *FPI = cast(BB->getFirstNonPHI());
313 Instruction *GetExnCI = nullptr, *GetSelectorCI = nullptr;
314 for (auto &U : FPI->uses()) {
315 if (auto *CI = dyn_cast(U.getUser())) {
316 if (CI->getCalledOperand() == GetExnF)
317 GetExnCI = CI;
318 if (CI->getCalledOperand() == GetSelectorF)
319 GetSelectorCI = CI;
320 }
321 }
322
323
324
325 if (!GetExnCI) {
326 assert(!GetSelectorCI &&
327 "wasm.get.ehselector() cannot exist w/o wasm.get.exception()");
328 return;
329 }
330
331
332
333
334
339
340
341
342 if (!NeedPersonality) {
343 if (GetSelectorCI) {
344 assert(GetSelectorCI->use_empty() &&
345 "wasm.get.ehselector() still has uses!");
346 GetSelectorCI->eraseFromParent();
347 }
348 return;
349 }
350 IRB.SetInsertPoint(CatchCI->getNextNode());
351
352
353
354
355 IRB.CreateCall(LPadIndexF, {FPI, IRB.getInt32(Index)});
356
357
358 IRB.CreateStore(IRB.getInt32(Index), LPadIndexField);
359
360 auto *CPI = cast(FPI);
361
362
363
364
365 IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField);
366
367
368 CallInst *PersCI = IRB.CreateCall(CallPersonalityF, CatchCI,
371
372
374 IRB.CreateLoad(IRB.getInt32Ty(), SelectorField, "selector");
375
376
377
378 assert(GetSelectorCI && "wasm.get.ehselector() call does not exist");
379 GetSelectorCI->replaceAllUsesWith(Selector);
380 GetSelectorCI->eraseFromParent();
381}
382
384
385
386
387
388 for (const auto &BB : *F) {
390 continue;
392
393 if (const auto *CatchPad = dyn_cast(Pad)) {
394 const auto *UnwindBB = CatchPad->getCatchSwitch()->getUnwindDest();
395 if (!UnwindBB)
396 continue;
397 const Instruction *UnwindPad = UnwindBB->getFirstNonPHI();
398 if (const auto *CatchSwitch = dyn_cast(UnwindPad))
399
401 else
403 }
404 }
405}
static bool runOnFunction(Function &F, bool PostInlining)
Module.h This file contains the declarations for the Module class.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static void eraseDeadBBsAndChildren(const Container &BBs)
A container for analyses that lazily runs them and caches their results.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
InstListType::iterator iterator
Instruction iterators...
LLVMContext & getContext() const
Get the context in which this basic block lives.
bool isEHPad() const
Return true if this basic block is an exception handling block.
This class represents a function call, abstracting a target machine's calling convention.
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
FunctionPass class - This class is used to implement most global optimizations.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
A Module instance is used to store all the information related to an LLVM module.
virtual bool doInitialization(Module &)
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
static PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getInt32Ty(LLVMContext &C)
LLVM Value Representation.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
This is an optimization pass for GlobalISel generic memory operations.
auto successors(const MachineBasicBlock *BB)
FunctionPass * createWasmEHPass()
createWasmEHPass - This pass adapts exception handling code to use WebAssembly's exception handling s...
void DeleteDeadBlock(BasicBlock *BB, DomTreeUpdater *DTU=nullptr, bool KeepOneInputPHIs=false)
Delete the specified block, which must have no predecessors.
bool isScopedEHPersonality(EHPersonality Pers)
Returns true if this personality uses scope-style EH IR instructions: catchswitch,...
OperandBundleDefT< Value * > OperandBundleDef
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
RNSuccIterator< NodeRef, BlockT, RegionT > succ_begin(NodeRef Node)
RNSuccIterator< NodeRef, BlockT, RegionT > succ_end(NodeRef Node)
void calculateWasmEHInfo(const Function *F, WasmEHFuncInfo &EHInfo)
bool pred_empty(const BasicBlock *BB)
void setUnwindDest(const BasicBlock *BB, const BasicBlock *Dest)