LLVM  14.0.0git
WasmEHPrepare.cpp
Go to the documentation of this file.
1 //===-- WasmEHPrepare - Prepare excepton handling for WebAssembly --------===//
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
10 // WebAssembly exception handling scheme. This currently supports C++
11 // exceptions.
12 //
13 // WebAssembly exception handling uses Windows exception IR for the middle level
14 // representation. This pass does the following transformation for every
15 // catchpad block:
16 // (In C-style pseudocode)
17 //
18 // - Before:
19 // catchpad ...
20 // exn = wasm.get.exception();
21 // selector = wasm.get.selector();
22 // ...
23 //
24 // - After:
25 // catchpad ...
26 // exn = wasm.catch(WebAssembly::CPP_EXCEPTION);
27 // // Only add below in case it's not a single catch (...)
28 // wasm.landingpad.index(index);
29 // __wasm_lpad_context.lpad_index = index;
30 // __wasm_lpad_context.lsda = wasm.lsda();
31 // _Unwind_CallPersonality(exn);
32 // selector = __wasm_lpad_context.selector;
33 // ...
34 //
35 //
36 // * Background: Direct personality function call
37 // In WebAssembly EH, the VM is responsible for unwinding the stack once an
38 // exception is thrown. After the stack is unwound, the control flow is
39 // transfered to WebAssembly 'catch' instruction.
40 //
41 // Unwinding the stack is not done by libunwind but the VM, so the personality
42 // function in libcxxabi cannot be called from libunwind during the unwinding
43 // process. So after a catch instruction, we insert a call to a wrapper function
44 // in libunwind that in turn calls the real personality function.
45 //
46 // In Itanium EH, if the personality function decides there is no matching catch
47 // clause in a call frame and no cleanup action to perform, the unwinder doesn't
48 // stop there and continues unwinding. But in Wasm EH, the unwinder stops at
49 // every call frame with a catch intruction, after which the personality
50 // function is called from the compiler-generated user code here.
51 //
52 // In libunwind, we have this struct that serves as a communincation channel
53 // between the compiler-generated user code and the personality function in
54 // libcxxabi.
55 //
56 // struct _Unwind_LandingPadContext {
57 // uintptr_t lpad_index;
58 // uintptr_t lsda;
59 // uintptr_t selector;
60 // };
61 // struct _Unwind_LandingPadContext __wasm_lpad_context = ...;
62 //
63 // And this wrapper in libunwind calls the personality function.
64 //
65 // _Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) {
66 // struct _Unwind_Exception *exception_obj =
67 // (struct _Unwind_Exception *)exception_ptr;
68 // _Unwind_Reason_Code ret = __gxx_personality_v0(
69 // 1, _UA_CLEANUP_PHASE, exception_obj->exception_class, exception_obj,
70 // (struct _Unwind_Context *)__wasm_lpad_context);
71 // return ret;
72 // }
73 //
74 // We pass a landing pad index, and the address of LSDA for the current function
75 // to the wrapper function _Unwind_CallPersonality in libunwind, and we retrieve
76 // the selector after it returns.
77 //
78 //===----------------------------------------------------------------------===//
79 
83 #include "llvm/IR/IRBuilder.h"
84 #include "llvm/IR/IntrinsicsWebAssembly.h"
85 #include "llvm/InitializePasses.h"
87 
88 using namespace llvm;
89 
90 #define DEBUG_TYPE "wasmehprepare"
91 
92 namespace {
93 class WasmEHPrepare : public FunctionPass {
94  Type *LPadContextTy = nullptr; // type of 'struct _Unwind_LandingPadContext'
95  GlobalVariable *LPadContextGV = nullptr; // __wasm_lpad_context
96 
97  // Field addresses of struct _Unwind_LandingPadContext
98  Value *LPadIndexField = nullptr; // lpad_index field
99  Value *LSDAField = nullptr; // lsda field
100  Value *SelectorField = nullptr; // selector
101 
102  Function *ThrowF = nullptr; // wasm.throw() intrinsic
103  Function *LPadIndexF = nullptr; // wasm.landingpad.index() intrinsic
104  Function *LSDAF = nullptr; // wasm.lsda() intrinsic
105  Function *GetExnF = nullptr; // wasm.get.exception() intrinsic
106  Function *CatchF = nullptr; // wasm.catch() intrinsic
107  Function *GetSelectorF = nullptr; // wasm.get.ehselector() intrinsic
108  FunctionCallee CallPersonalityF =
109  nullptr; // _Unwind_CallPersonality() wrapper
110 
111  bool prepareThrows(Function &F);
112  bool prepareEHPads(Function &F);
113  void prepareEHPad(BasicBlock *BB, bool NeedPersonality, unsigned Index = 0);
114 
115 public:
116  static char ID; // Pass identification, replacement for typeid
117 
118  WasmEHPrepare() : FunctionPass(ID) {}
119  bool doInitialization(Module &M) override;
120  bool runOnFunction(Function &F) override;
121 
122  StringRef getPassName() const override {
123  return "WebAssembly Exception handling preparation";
124  }
125 };
126 } // end anonymous namespace
127 
128 char WasmEHPrepare::ID = 0;
129 INITIALIZE_PASS_BEGIN(WasmEHPrepare, DEBUG_TYPE,
130  "Prepare WebAssembly exceptions", false, false)
131 INITIALIZE_PASS_END(WasmEHPrepare, DEBUG_TYPE, "Prepare WebAssembly exceptions",
133 
134 FunctionPass *llvm::createWasmEHPass() { return new WasmEHPrepare(); }
135 
136 bool WasmEHPrepare::doInitialization(Module &M) {
137  IRBuilder<> IRB(M.getContext());
138  LPadContextTy = StructType::get(IRB.getInt32Ty(), // lpad_index
139  IRB.getInt8PtrTy(), // lsda
140  IRB.getInt32Ty() // selector
141  );
142  return false;
143 }
144 
145 // Erase the specified BBs if the BB does not have any remaining predecessors,
146 // and also all its dead children.
147 template <typename Container>
148 static void eraseDeadBBsAndChildren(const Container &BBs) {
149  SmallVector<BasicBlock *, 8> WL(BBs.begin(), BBs.end());
150  while (!WL.empty()) {
151  auto *BB = WL.pop_back_val();
152  if (!pred_empty(BB))
153  continue;
154  WL.append(succ_begin(BB), succ_end(BB));
156  }
157 }
158 
160  bool Changed = false;
161  Changed |= prepareThrows(F);
162  Changed |= prepareEHPads(F);
163  return Changed;
164 }
165 
166 bool WasmEHPrepare::prepareThrows(Function &F) {
167  Module &M = *F.getParent();
168  IRBuilder<> IRB(F.getContext());
169  bool Changed = false;
170 
171  // wasm.throw() intinsic, which will be lowered to wasm 'throw' instruction.
172  ThrowF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_throw);
173  // Insert an unreachable instruction after a call to @llvm.wasm.throw and
174  // delete all following instructions within the BB, and delete all the dead
175  // children of the BB as well.
176  for (User *U : ThrowF->users()) {
177  // A call to @llvm.wasm.throw() is only generated from __cxa_throw()
178  // builtin call within libcxxabi, and cannot be an InvokeInst.
179  auto *ThrowI = cast<CallInst>(U);
180  if (ThrowI->getFunction() != &F)
181  continue;
182  Changed = true;
183  auto *BB = ThrowI->getParent();
185  auto &InstList = BB->getInstList();
186  InstList.erase(std::next(BasicBlock::iterator(ThrowI)), InstList.end());
187  IRB.SetInsertPoint(BB);
188  IRB.CreateUnreachable();
190  }
191 
192  return Changed;
193 }
194 
195 bool WasmEHPrepare::prepareEHPads(Function &F) {
196  Module &M = *F.getParent();
197  IRBuilder<> IRB(F.getContext());
198 
200  SmallVector<BasicBlock *, 16> CleanupPads;
201  for (BasicBlock &BB : F) {
202  if (!BB.isEHPad())
203  continue;
204  auto *Pad = BB.getFirstNonPHI();
205  if (isa<CatchPadInst>(Pad))
206  CatchPads.push_back(&BB);
207  else if (isa<CleanupPadInst>(Pad))
208  CleanupPads.push_back(&BB);
209  }
210  if (CatchPads.empty() && CleanupPads.empty())
211  return false;
212 
213  assert(F.hasPersonalityFn() && "Personality function not found");
214 
215  // __wasm_lpad_context global variable
216  LPadContextGV = cast<GlobalVariable>(
217  M.getOrInsertGlobal("__wasm_lpad_context", LPadContextTy));
218  LPadIndexField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 0,
219  "lpad_index_gep");
220  LSDAField =
221  IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 1, "lsda_gep");
222  SelectorField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 2,
223  "selector_gep");
224 
225  // wasm.landingpad.index() intrinsic, which is to specify landingpad index
226  LPadIndexF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_landingpad_index);
227  // wasm.lsda() intrinsic. Returns the address of LSDA table for the current
228  // function.
229  LSDAF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_lsda);
230  // wasm.get.exception() and wasm.get.ehselector() intrinsics. Calls to these
231  // are generated in clang.
232  GetExnF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_exception);
233  GetSelectorF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_ehselector);
234 
235  // wasm.catch() will be lowered down to wasm 'catch' instruction in
236  // instruction selection.
237  CatchF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_catch);
238 
239  // _Unwind_CallPersonality() wrapper function, which calls the personality
240  CallPersonalityF = M.getOrInsertFunction(
241  "_Unwind_CallPersonality", IRB.getInt32Ty(), IRB.getInt8PtrTy());
242  if (Function *F = dyn_cast<Function>(CallPersonalityF.getCallee()))
243  F->setDoesNotThrow();
244 
245  unsigned Index = 0;
246  for (auto *BB : CatchPads) {
247  auto *CPI = cast<CatchPadInst>(BB->getFirstNonPHI());
248  // In case of a single catch (...), we don't need to emit a personalify
249  // function call
250  if (CPI->getNumArgOperands() == 1 &&
251  cast<Constant>(CPI->getArgOperand(0))->isNullValue())
252  prepareEHPad(BB, false);
253  else
254  prepareEHPad(BB, true, Index++);
255  }
256 
257  // Cleanup pads don't need a personality function call.
258  for (auto *BB : CleanupPads)
259  prepareEHPad(BB, false);
260 
261  return true;
262 }
263 
264 // Prepare an EH pad for Wasm EH handling. If NeedPersonality is false, Index is
265 // ignored.
266 void WasmEHPrepare::prepareEHPad(BasicBlock *BB, bool NeedPersonality,
267  unsigned Index) {
268  assert(BB->isEHPad() && "BB is not an EHPad!");
269  IRBuilder<> IRB(BB->getContext());
270  IRB.SetInsertPoint(&*BB->getFirstInsertionPt());
271 
272  auto *FPI = cast<FuncletPadInst>(BB->getFirstNonPHI());
273  Instruction *GetExnCI = nullptr, *GetSelectorCI = nullptr;
274  for (auto &U : FPI->uses()) {
275  if (auto *CI = dyn_cast<CallInst>(U.getUser())) {
276  if (CI->getCalledOperand() == GetExnF)
277  GetExnCI = CI;
278  if (CI->getCalledOperand() == GetSelectorF)
279  GetSelectorCI = CI;
280  }
281  }
282 
283  // Cleanup pads do not have any of wasm.get.exception() or
284  // wasm.get.ehselector() calls. We need to do nothing.
285  if (!GetExnCI) {
286  assert(!GetSelectorCI &&
287  "wasm.get.ehselector() cannot exist w/o wasm.get.exception()");
288  return;
289  }
290 
291  // Replace wasm.get.exception intrinsic with wasm.catch intrinsic, which will
292  // be lowered to wasm 'catch' instruction. We do this mainly because
293  // instruction selection cannot handle wasm.get.exception intrinsic's token
294  // argument.
295  Instruction *CatchCI =
296  IRB.CreateCall(CatchF, {IRB.getInt32(WebAssembly::CPP_EXCEPTION)}, "exn");
297  GetExnCI->replaceAllUsesWith(CatchCI);
298  GetExnCI->eraseFromParent();
299 
300  // In case it is a catchpad with single catch (...) or a cleanuppad, we don't
301  // need to call personality function because we don't need a selector.
302  if (!NeedPersonality) {
303  if (GetSelectorCI) {
304  assert(GetSelectorCI->use_empty() &&
305  "wasm.get.ehselector() still has uses!");
306  GetSelectorCI->eraseFromParent();
307  }
308  return;
309  }
310  IRB.SetInsertPoint(CatchCI->getNextNode());
311 
312  // This is to create a map of <landingpad EH label, landingpad index> in
313  // SelectionDAGISel, which is to be used in EHStreamer to emit LSDA tables.
314  // Pseudocode: wasm.landingpad.index(Index);
315  IRB.CreateCall(LPadIndexF, {FPI, IRB.getInt32(Index)});
316 
317  // Pseudocode: __wasm_lpad_context.lpad_index = index;
318  IRB.CreateStore(IRB.getInt32(Index), LPadIndexField);
319 
320  auto *CPI = cast<CatchPadInst>(FPI);
321  // TODO Sometimes storing the LSDA address every time is not necessary, in
322  // case it is already set in a dominating EH pad and there is no function call
323  // between from that EH pad to here. Consider optimizing those cases.
324  // Pseudocode: __wasm_lpad_context.lsda = wasm.lsda();
325  IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField);
326 
327  // Pseudocode: _Unwind_CallPersonality(exn);
328  CallInst *PersCI = IRB.CreateCall(CallPersonalityF, CatchCI,
329  OperandBundleDef("funclet", CPI));
330  PersCI->setDoesNotThrow();
331 
332  // Pseudocode: int selector = __wasm_lpad_context.selector;
333  Instruction *Selector =
334  IRB.CreateLoad(IRB.getInt32Ty(), SelectorField, "selector");
335 
336  // Replace the return value from wasm.get.ehselector() with the selector value
337  // loaded from __wasm_lpad_context.selector.
338  assert(GetSelectorCI && "wasm.get.ehselector() call does not exist");
339  GetSelectorCI->replaceAllUsesWith(Selector);
340  GetSelectorCI->eraseFromParent();
341 }
342 
344  // If an exception is not caught by a catchpad (i.e., it is a foreign
345  // exception), it will unwind to its parent catchswitch's unwind destination.
346  // We don't record an unwind destination for cleanuppads because every
347  // exception should be caught by it.
348  for (const auto &BB : *F) {
349  if (!BB.isEHPad())
350  continue;
351  const Instruction *Pad = BB.getFirstNonPHI();
352 
353  if (const auto *CatchPad = dyn_cast<CatchPadInst>(Pad)) {
354  const auto *UnwindBB = CatchPad->getCatchSwitch()->getUnwindDest();
355  if (!UnwindBB)
356  continue;
357  const Instruction *UnwindPad = UnwindBB->getFirstNonPHI();
358  if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(UnwindPad))
359  // Currently there should be only one handler per a catchswitch.
360  EHInfo.setUnwindDest(&BB, *CatchSwitch->handlers().begin());
361  else // cleanuppad
362  EHInfo.setUnwindDest(&BB, UnwindBB);
363  }
364  }
365 }
llvm::WasmEHFuncInfo
Definition: WasmEHFuncInfo.h:32
llvm::WasmEHFuncInfo::setUnwindDest
void setUnwindDest(const BasicBlock *BB, const BasicBlock *Dest)
Definition: WasmEHFuncInfo.h:51
INITIALIZE_PASS_BEGIN
INITIALIZE_PASS_BEGIN(WasmEHPrepare, DEBUG_TYPE, "Prepare WebAssembly exceptions", false, false) INITIALIZE_PASS_END(WasmEHPrepare
llvm
This file implements support for optimizing divisions by a constant.
Definition: AllocatorList.h:23
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::StructType::get
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition: Type.cpp:408
llvm::Intrinsic::getDeclaration
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=None)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
Definition: Function.cpp:1379
llvm::BasicBlock::iterator
InstListType::iterator iterator
Instruction iterators...
Definition: BasicBlock.h:90
llvm::succ_end
Interval::succ_iterator succ_end(Interval *I)
Definition: Interval.h:102
llvm::Function
Definition: Function.h:62
llvm::ilist_node_with_parent::getNextNode
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition: ilist_node.h:288
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1168
llvm::IRBuilder<>
exceptions
Prepare WebAssembly exceptions
Definition: WasmEHPrepare.cpp:131
llvm::GlobalVariable
Definition: GlobalVariable.h:40
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
llvm::SmallVectorImpl::pop_back_val
LLVM_NODISCARD T pop_back_val()
Definition: SmallVector.h:635
llvm::CallBase::setDoesNotThrow
void setDoesNotThrow()
Definition: InstrTypes.h:1850
llvm::successors
succ_range successors(Instruction *I)
Definition: CFG.h:262
llvm::OperandBundleDef
OperandBundleDefT< Value * > OperandBundleDef
Definition: InstrTypes.h:1140
F
#define F(x, y, z)
Definition: MD5.cpp:56
llvm::BasicBlock
LLVM Basic Block Representation.
Definition: BasicBlock.h:58
TargetLowering.h
llvm::SmallVectorImpl::append
void append(in_iter in_start, in_iter in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:648
llvm::User
Definition: User.h:44
false
Definition: StackSlotColoring.cpp:142
llvm::Instruction
Definition: Instruction.h:45
INITIALIZE_PASS_END
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:58
llvm::Instruction::eraseFromParent
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Definition: Instruction.cpp:78
Index
uint32_t Index
Definition: ELFObjHandler.cpp:84
llvm::succ_begin
Interval::succ_iterator succ_begin(Interval *I)
succ_begin/succ_end - define methods so that Intervals may be used just like BasicBlocks can with the...
Definition: Interval.h:99
IRBuilder.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
eraseDeadBBsAndChildren
static void eraseDeadBBsAndChildren(const Container &BBs)
Definition: WasmEHPrepare.cpp:148
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm::Value::replaceAllUsesWith
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:532
TargetSubtargetInfo.h
llvm::pred_empty
bool pred_empty(const BasicBlock *BB)
Definition: CFG.h:119
runOnFunction
static bool runOnFunction(Function &F, bool PostInlining)
Definition: EntryExitInstrumenter.cpp:69
llvm::WebAssembly::CPP_EXCEPTION
@ CPP_EXCEPTION
Definition: WasmEHFuncInfo.h:27
WasmEHFuncInfo.h
llvm::createWasmEHPass
FunctionPass * createWasmEHPass()
createWasmEHPass - This pass adapts exception handling code to use WebAssembly's exception handling s...
Definition: WasmEHPrepare.cpp:134
DEBUG_TYPE
#define DEBUG_TYPE
Definition: WasmEHPrepare.cpp:90
llvm::FunctionCallee
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Definition: DerivedTypes.h:165
llvm::DeleteDeadBlock
void DeleteDeadBlock(BasicBlock *BB, DomTreeUpdater *DTU=nullptr, bool KeepOneInputPHIs=false)
Delete the specified block, which must have no predecessors.
Definition: BasicBlockUtils.cpp:89
llvm::FunctionPass
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:298
llvm::CallInst
This class represents a function call, abstracting a target machine's calling convention.
Definition: Instructions.h:1475
BB
Common register allocation spilling lr str ldr sxth r3 ldr mla r4 can lr mov lr str ldr sxth r3 mla r4 and then merge mul and lr str ldr sxth r3 mla r4 It also increase the likelihood the store may become dead bb27 Successors according to LLVM BB
Definition: README.txt:39
BasicBlockUtils.h
InitializePasses.h
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::Value::users
iterator_range< user_iterator > users()
Definition: Value.h:421
llvm::calculateWasmEHInfo
void calculateWasmEHInfo(const Function *F, WasmEHFuncInfo &EHInfo)
Definition: WasmEHPrepare.cpp:343
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:37