LLVM  15.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 
81 #include "llvm/CodeGen/Passes.h"
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  // This variable should be thread local. If the target does not support TLS,
217  // we depend on CoalesceFeaturesAndStripAtomics to downgrade it to
218  // non-thread-local ones, in which case we don't allow this object to be
219  // linked with other objects using shared memory.
220  LPadContextGV = cast<GlobalVariable>(
221  M.getOrInsertGlobal("__wasm_lpad_context", LPadContextTy));
222  LPadContextGV->setThreadLocalMode(GlobalValue::GeneralDynamicTLSModel);
223 
224  LPadIndexField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 0,
225  "lpad_index_gep");
226  LSDAField =
227  IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 1, "lsda_gep");
228  SelectorField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 2,
229  "selector_gep");
230 
231  // wasm.landingpad.index() intrinsic, which is to specify landingpad index
232  LPadIndexF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_landingpad_index);
233  // wasm.lsda() intrinsic. Returns the address of LSDA table for the current
234  // function.
235  LSDAF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_lsda);
236  // wasm.get.exception() and wasm.get.ehselector() intrinsics. Calls to these
237  // are generated in clang.
238  GetExnF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_exception);
239  GetSelectorF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_ehselector);
240 
241  // wasm.catch() will be lowered down to wasm 'catch' instruction in
242  // instruction selection.
243  CatchF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_catch);
244 
245  // _Unwind_CallPersonality() wrapper function, which calls the personality
246  CallPersonalityF = M.getOrInsertFunction(
247  "_Unwind_CallPersonality", IRB.getInt32Ty(), IRB.getInt8PtrTy());
248  if (Function *F = dyn_cast<Function>(CallPersonalityF.getCallee()))
249  F->setDoesNotThrow();
250 
251  unsigned Index = 0;
252  for (auto *BB : CatchPads) {
253  auto *CPI = cast<CatchPadInst>(BB->getFirstNonPHI());
254  // In case of a single catch (...), we don't need to emit a personalify
255  // function call
256  if (CPI->getNumArgOperands() == 1 &&
257  cast<Constant>(CPI->getArgOperand(0))->isNullValue())
258  prepareEHPad(BB, false);
259  else
260  prepareEHPad(BB, true, Index++);
261  }
262 
263  // Cleanup pads don't need a personality function call.
264  for (auto *BB : CleanupPads)
265  prepareEHPad(BB, false);
266 
267  return true;
268 }
269 
270 // Prepare an EH pad for Wasm EH handling. If NeedPersonality is false, Index is
271 // ignored.
272 void WasmEHPrepare::prepareEHPad(BasicBlock *BB, bool NeedPersonality,
273  unsigned Index) {
274  assert(BB->isEHPad() && "BB is not an EHPad!");
275  IRBuilder<> IRB(BB->getContext());
276  IRB.SetInsertPoint(&*BB->getFirstInsertionPt());
277 
278  auto *FPI = cast<FuncletPadInst>(BB->getFirstNonPHI());
279  Instruction *GetExnCI = nullptr, *GetSelectorCI = nullptr;
280  for (auto &U : FPI->uses()) {
281  if (auto *CI = dyn_cast<CallInst>(U.getUser())) {
282  if (CI->getCalledOperand() == GetExnF)
283  GetExnCI = CI;
284  if (CI->getCalledOperand() == GetSelectorF)
285  GetSelectorCI = CI;
286  }
287  }
288 
289  // Cleanup pads do not have any of wasm.get.exception() or
290  // wasm.get.ehselector() calls. We need to do nothing.
291  if (!GetExnCI) {
292  assert(!GetSelectorCI &&
293  "wasm.get.ehselector() cannot exist w/o wasm.get.exception()");
294  return;
295  }
296 
297  // Replace wasm.get.exception intrinsic with wasm.catch intrinsic, which will
298  // be lowered to wasm 'catch' instruction. We do this mainly because
299  // instruction selection cannot handle wasm.get.exception intrinsic's token
300  // argument.
301  Instruction *CatchCI =
302  IRB.CreateCall(CatchF, {IRB.getInt32(WebAssembly::CPP_EXCEPTION)}, "exn");
303  GetExnCI->replaceAllUsesWith(CatchCI);
304  GetExnCI->eraseFromParent();
305 
306  // In case it is a catchpad with single catch (...) or a cleanuppad, we don't
307  // need to call personality function because we don't need a selector.
308  if (!NeedPersonality) {
309  if (GetSelectorCI) {
310  assert(GetSelectorCI->use_empty() &&
311  "wasm.get.ehselector() still has uses!");
312  GetSelectorCI->eraseFromParent();
313  }
314  return;
315  }
316  IRB.SetInsertPoint(CatchCI->getNextNode());
317 
318  // This is to create a map of <landingpad EH label, landingpad index> in
319  // SelectionDAGISel, which is to be used in EHStreamer to emit LSDA tables.
320  // Pseudocode: wasm.landingpad.index(Index);
321  IRB.CreateCall(LPadIndexF, {FPI, IRB.getInt32(Index)});
322 
323  // Pseudocode: __wasm_lpad_context.lpad_index = index;
324  IRB.CreateStore(IRB.getInt32(Index), LPadIndexField);
325 
326  auto *CPI = cast<CatchPadInst>(FPI);
327  // TODO Sometimes storing the LSDA address every time is not necessary, in
328  // case it is already set in a dominating EH pad and there is no function call
329  // between from that EH pad to here. Consider optimizing those cases.
330  // Pseudocode: __wasm_lpad_context.lsda = wasm.lsda();
331  IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField);
332 
333  // Pseudocode: _Unwind_CallPersonality(exn);
334  CallInst *PersCI = IRB.CreateCall(CallPersonalityF, CatchCI,
335  OperandBundleDef("funclet", CPI));
336  PersCI->setDoesNotThrow();
337 
338  // Pseudocode: int selector = __wasm_lpad_context.selector;
339  Instruction *Selector =
340  IRB.CreateLoad(IRB.getInt32Ty(), SelectorField, "selector");
341 
342  // Replace the return value from wasm.get.ehselector() with the selector value
343  // loaded from __wasm_lpad_context.selector.
344  assert(GetSelectorCI && "wasm.get.ehselector() call does not exist");
345  GetSelectorCI->replaceAllUsesWith(Selector);
346  GetSelectorCI->eraseFromParent();
347 }
348 
350  // If an exception is not caught by a catchpad (i.e., it is a foreign
351  // exception), it will unwind to its parent catchswitch's unwind destination.
352  // We don't record an unwind destination for cleanuppads because every
353  // exception should be caught by it.
354  for (const auto &BB : *F) {
355  if (!BB.isEHPad())
356  continue;
357  const Instruction *Pad = BB.getFirstNonPHI();
358 
359  if (const auto *CatchPad = dyn_cast<CatchPadInst>(Pad)) {
360  const auto *UnwindBB = CatchPad->getCatchSwitch()->getUnwindDest();
361  if (!UnwindBB)
362  continue;
363  const Instruction *UnwindPad = UnwindBB->getFirstNonPHI();
364  if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(UnwindPad))
365  // Currently there should be only one handler per a catchswitch.
366  EHInfo.setUnwindDest(&BB, *CatchSwitch->handlers().begin());
367  else // cleanuppad
368  EHInfo.setUnwindDest(&BB, UnwindBB);
369  }
370  }
371 }
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 is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
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:406
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:1410
llvm::BasicBlock::iterator
InstListType::iterator iterator
Instruction iterators...
Definition: BasicBlock.h:87
llvm::succ_end
Interval::succ_iterator succ_end(Interval *I)
Definition: Interval.h:102
llvm::Function
Definition: Function.h:60
llvm::ilist_node_with_parent::getNextNode
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition: ilist_node.h:289
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1185
llvm::IRBuilder<>
exceptions
Prepare WebAssembly exceptions
Definition: WasmEHPrepare.cpp:131
llvm::GlobalVariable
Definition: GlobalVariable.h:39
MachineBasicBlock.h
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
llvm::successors
auto successors(MachineBasicBlock *BB)
Definition: MachineSSAContext.h:29
llvm::SmallVectorImpl::pop_back_val
LLVM_NODISCARD T pop_back_val()
Definition: SmallVector.h:654
llvm::CallBase::setDoesNotThrow
void setDoesNotThrow()
Definition: InstrTypes.h:1900
F
#define F(x, y, z)
Definition: MD5.cpp:55
llvm::BasicBlock
LLVM Basic Block Representation.
Definition: BasicBlock.h:55
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:667
llvm::User
Definition: User.h:44
false
Definition: StackSlotColoring.cpp:141
llvm::dwarf::Index
Index
Definition: Dwarf.h:472
llvm::Instruction
Definition: Instruction.h:42
llvm::OperandBundleDef
OperandBundleDefT< Value * > OperandBundleDef
Definition: AutoUpgrade.h:33
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
INITIALIZE_PASS_END
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:58
Passes.h
llvm::Instruction::eraseFromParent
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Definition: Instruction.cpp:77
llvm::GlobalValue::GeneralDynamicTLSModel
@ GeneralDynamicTLSModel
Definition: GlobalValue.h:179
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:65
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:529
llvm::pred_empty
bool pred_empty(const BasicBlock *BB)
Definition: CFG.h:118
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:94
llvm::FunctionPass
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:308
llvm::CallInst
This class represents a function call, abstracting a target machine's calling convention.
Definition: Instructions.h:1474
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:349
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:37