LLVM  7.0.0svn
WebAssemblyLowerEmscriptenEHSjLj.cpp
Go to the documentation of this file.
1 //=== WebAssemblyLowerEmscriptenEHSjLj.cpp - Lower exceptions for Emscripten =//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief This file lowers exception-related instructions and setjmp/longjmp
12 /// function calls in order to use Emscripten's JavaScript try and catch
13 /// mechanism.
14 ///
15 /// To handle exceptions and setjmp/longjmps, this scheme relies on JavaScript's
16 /// try and catch syntax and relevant exception-related libraries implemented
17 /// in JavaScript glue code that will be produced by Emscripten. This is similar
18 /// to the current Emscripten asm.js exception handling in fastcomp. For
19 /// fastcomp's EH / SjLj scheme, see these files in fastcomp LLVM branch:
20 /// (Location: https://github.com/kripken/emscripten-fastcomp)
21 /// lib/Target/JSBackend/NaCl/LowerEmExceptionsPass.cpp
22 /// lib/Target/JSBackend/NaCl/LowerEmSetjmp.cpp
23 /// lib/Target/JSBackend/JSBackend.cpp
24 /// lib/Target/JSBackend/CallHandlers.h
25 ///
26 /// * Exception handling
27 /// This pass lowers invokes and landingpads into library functions in JS glue
28 /// code. Invokes are lowered into function wrappers called invoke wrappers that
29 /// exist in JS side, which wraps the original function call with JS try-catch.
30 /// If an exception occurred, cxa_throw() function in JS side sets some
31 /// variables (see below) so we can check whether an exception occurred from
32 /// wasm code and handle it appropriately.
33 ///
34 /// * Setjmp-longjmp handling
35 /// This pass lowers setjmp to a reasonably-performant approach for emscripten.
36 /// The idea is that each block with a setjmp is broken up into two parts: the
37 /// part containing setjmp and the part right after the setjmp. The latter part
38 /// is either reached from the setjmp, or later from a longjmp. To handle the
39 /// longjmp, all calls that might longjmp are also called using invoke wrappers
40 /// and thus JS / try-catch. JS longjmp() function also sets some variables so
41 /// we can check / whether a longjmp occurred from wasm code. Each block with a
42 /// function call that might longjmp is also split up after the longjmp call.
43 /// After the longjmp call, we check whether a longjmp occurred, and if it did,
44 /// which setjmp it corresponds to, and jump to the right post-setjmp block.
45 /// We assume setjmp-longjmp handling always run after EH handling, which means
46 /// we don't expect any exception-related instructions when SjLj runs.
47 /// FIXME Currently this scheme does not support indirect call of setjmp,
48 /// because of the limitation of the scheme itself. fastcomp does not support it
49 /// either.
50 ///
51 /// In detail, this pass does following things:
52 ///
53 /// 1) Create three global variables: __THREW__, __threwValue, and __tempRet0.
54 /// __tempRet0 will be set within __cxa_find_matching_catch() function in
55 /// JS library, and __THREW__ and __threwValue will be set in invoke wrappers
56 /// in JS glue code. For what invoke wrappers are, refer to 3). These
57 /// variables are used for both exceptions and setjmp/longjmps.
58 /// __THREW__ indicates whether an exception or a longjmp occurred or not. 0
59 /// means nothing occurred, 1 means an exception occurred, and other numbers
60 /// mean a longjmp occurred. In the case of longjmp, __threwValue variable
61 /// indicates the corresponding setjmp buffer the longjmp corresponds to.
62 /// In exception handling, __tempRet0 indicates the type of an exception
63 /// caught, and in setjmp/longjmp, it means the second argument to longjmp
64 /// function.
65 ///
66 /// * Exception handling
67 ///
68 /// 2) Create setThrew and setTempRet0 functions.
69 /// The global variables created in 1) will exist in wasm address space,
70 /// but their values should be set in JS code, so we provide these functions
71 /// as interfaces to JS glue code. These functions are equivalent to the
72 /// following JS functions, which actually exist in asm.js version of JS
73 /// library.
74 ///
75 /// function setThrew(threw, value) {
76 /// if (__THREW__ == 0) {
77 /// __THREW__ = threw;
78 /// __threwValue = value;
79 /// }
80 /// }
81 ///
82 /// function setTempRet0(value) {
83 /// __tempRet0 = value;
84 /// }
85 ///
86 /// 3) Lower
87 /// invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad
88 /// into
89 /// __THREW__ = 0;
90 /// call @__invoke_SIG(func, arg1, arg2)
91 /// %__THREW__.val = __THREW__;
92 /// __THREW__ = 0;
93 /// if (%__THREW__.val == 1)
94 /// goto %lpad
95 /// else
96 /// goto %invoke.cont
97 /// SIG is a mangled string generated based on the LLVM IR-level function
98 /// signature. After LLVM IR types are lowered to the target wasm types,
99 /// the names for these wrappers will change based on wasm types as well,
100 /// as in invoke_vi (function takes an int and returns void). The bodies of
101 /// these wrappers will be generated in JS glue code, and inside those
102 /// wrappers we use JS try-catch to generate actual exception effects. It
103 /// also calls the original callee function. An example wrapper in JS code
104 /// would look like this:
105 /// function invoke_vi(index,a1) {
106 /// try {
107 /// Module["dynCall_vi"](index,a1); // This calls original callee
108 /// } catch(e) {
109 /// if (typeof e !== 'number' && e !== 'longjmp') throw e;
110 /// asm["setThrew"](1, 0); // setThrew is called here
111 /// }
112 /// }
113 /// If an exception is thrown, __THREW__ will be set to true in a wrapper,
114 /// so we can jump to the right BB based on this value.
115 ///
116 /// 4) Lower
117 /// %val = landingpad catch c1 catch c2 catch c3 ...
118 /// ... use %val ...
119 /// into
120 /// %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
121 /// %val = {%fmc, __tempRet0}
122 /// ... use %val ...
123 /// Here N is a number calculated based on the number of clauses.
124 /// Global variable __tempRet0 is set within __cxa_find_matching_catch() in
125 /// JS glue code.
126 ///
127 /// 5) Lower
128 /// resume {%a, %b}
129 /// into
130 /// call @__resumeException(%a)
131 /// where __resumeException() is a function in JS glue code.
132 ///
133 /// 6) Lower
134 /// call @llvm.eh.typeid.for(type) (intrinsic)
135 /// into
136 /// call @llvm_eh_typeid_for(type)
137 /// llvm_eh_typeid_for function will be generated in JS glue code.
138 ///
139 /// * Setjmp / Longjmp handling
140 ///
141 /// 7) In the function entry that calls setjmp, initialize setjmpTable and
142 /// sejmpTableSize as follows:
143 /// setjmpTableSize = 4;
144 /// setjmpTable = (int *) malloc(40);
145 /// setjmpTable[0] = 0;
146 /// setjmpTable and setjmpTableSize are used in saveSetjmp() function in JS
147 /// code.
148 ///
149 /// 8) Lower
150 /// setjmp(buf)
151 /// into
152 /// setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
153 /// setjmpTableSize = __tempRet0;
154 /// For each dynamic setjmp call, setjmpTable stores its ID (a number which
155 /// is incrementally assigned from 0) and its label (a unique number that
156 /// represents each callsite of setjmp). When we need more entries in
157 /// setjmpTable, it is reallocated in saveSetjmp() in JS code and it will
158 /// return the new table address, and assign the new table size in
159 /// __tempRet0. saveSetjmp also stores the setjmp's ID into the buffer buf.
160 /// A BB with setjmp is split into two after setjmp call in order to make the
161 /// post-setjmp BB the possible destination of longjmp BB.
162 ///
163 /// 9) Lower
164 /// longjmp(buf, value)
165 /// into
166 /// emscripten_longjmp_jmpbuf(buf, value)
167 /// emscripten_longjmp_jmpbuf will be lowered to emscripten_longjmp later.
168 ///
169 /// 10) Lower every call that might longjmp into
170 /// __THREW__ = 0;
171 /// call @__invoke_SIG(func, arg1, arg2)
172 /// %__THREW__.val = __THREW__;
173 /// __THREW__ = 0;
174 /// if (%__THREW__.val != 0 & __threwValue != 0) {
175 /// %label = testSetjmp(mem[%__THREW__.val], setjmpTable,
176 /// setjmpTableSize);
177 /// if (%label == 0)
178 /// emscripten_longjmp(%__THREW__.val, __threwValue);
179 /// __tempRet0 = __threwValue;
180 /// } else {
181 /// %label = -1;
182 /// }
183 /// longjmp_result = __tempRet0;
184 /// switch label {
185 /// label 1: goto post-setjmp BB 1
186 /// label 2: goto post-setjmp BB 2
187 /// ...
188 /// default: goto splitted next BB
189 /// }
190 /// testSetjmp examines setjmpTable to see if there is a matching setjmp
191 /// call. After calling an invoke wrapper, if a longjmp occurred, __THREW__
192 /// will be the address of matching jmp_buf buffer and __threwValue be the
193 /// second argument to longjmp. mem[__THREW__.val] is a setjmp ID that is
194 /// stored in saveSetjmp. testSetjmp returns a setjmp label, a unique ID to
195 /// each setjmp callsite. Label 0 means this longjmp buffer does not
196 /// correspond to one of the setjmp callsites in this function, so in this
197 /// case we just chain the longjmp to the caller. (Here we call
198 /// emscripten_longjmp, which is different from emscripten_longjmp_jmpbuf.
199 /// emscripten_longjmp_jmpbuf takes jmp_buf as its first argument, while
200 /// emscripten_longjmp takes an int. Both of them will eventually be lowered
201 /// to emscripten_longjmp in s2wasm, but here we need two signatures - we
202 /// can't translate an int value to a jmp_buf.)
203 /// Label -1 means no longjmp occurred. Otherwise we jump to the right
204 /// post-setjmp BB based on the label.
205 ///
206 ///===----------------------------------------------------------------------===//
207 
208 #include "WebAssembly.h"
209 #include "llvm/IR/CallSite.h"
210 #include "llvm/IR/Dominators.h"
211 #include "llvm/IR/IRBuilder.h"
214 
215 using namespace llvm;
216 
217 #define DEBUG_TYPE "wasm-lower-em-ehsjlj"
218 
220  EHWhitelist("emscripten-cxx-exceptions-whitelist",
221  cl::desc("The list of function names in which Emscripten-style "
222  "exception handling is enabled (see emscripten "
223  "EMSCRIPTEN_CATCHING_WHITELIST options)"),
225 
226 namespace {
227 class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
228  static const char *ThrewGVName;
229  static const char *ThrewValueGVName;
230  static const char *TempRet0GVName;
231  static const char *ResumeFName;
232  static const char *EHTypeIDFName;
233  static const char *SetThrewFName;
234  static const char *SetTempRet0FName;
235  static const char *EmLongjmpFName;
236  static const char *EmLongjmpJmpbufFName;
237  static const char *SaveSetjmpFName;
238  static const char *TestSetjmpFName;
239  static const char *FindMatchingCatchPrefix;
240  static const char *InvokePrefix;
241 
242  bool EnableEH; // Enable exception handling
243  bool EnableSjLj; // Enable setjmp/longjmp handling
244 
245  GlobalVariable *ThrewGV;
246  GlobalVariable *ThrewValueGV;
247  GlobalVariable *TempRet0GV;
248  Function *ResumeF;
249  Function *EHTypeIDF;
250  Function *EmLongjmpF;
251  Function *EmLongjmpJmpbufF;
252  Function *SaveSetjmpF;
253  Function *TestSetjmpF;
254 
255  // __cxa_find_matching_catch_N functions.
256  // Indexed by the number of clauses in an original landingpad instruction.
257  DenseMap<int, Function *> FindMatchingCatches;
258  // Map of <function signature string, invoke_ wrappers>
259  StringMap<Function *> InvokeWrappers;
260  // Set of whitelisted function names for exception handling
261  std::set<std::string> EHWhitelistSet;
262 
263  StringRef getPassName() const override {
264  return "WebAssembly Lower Emscripten Exceptions";
265  }
266 
267  bool runEHOnFunction(Function &F);
268  bool runSjLjOnFunction(Function &F);
269  Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
270 
271  template <typename CallOrInvoke> Value *wrapInvoke(CallOrInvoke *CI);
272  void wrapTestSetjmp(BasicBlock *BB, Instruction *InsertPt, Value *Threw,
273  Value *SetjmpTable, Value *SetjmpTableSize, Value *&Label,
274  Value *&LongjmpResult, BasicBlock *&EndBB);
275  template <typename CallOrInvoke> Function *getInvokeWrapper(CallOrInvoke *CI);
276 
277  bool areAllExceptionsAllowed() const { return EHWhitelistSet.empty(); }
278  bool canLongjmp(Module &M, const Value *Callee) const;
279 
280  void createSetThrewFunction(Module &M);
281  void createSetTempRet0Function(Module &M);
282 
283  void rebuildSSA(Function &F);
284 
285 public:
286  static char ID;
287 
288  WebAssemblyLowerEmscriptenEHSjLj(bool EnableEH = true, bool EnableSjLj = true)
289  : ModulePass(ID), EnableEH(EnableEH), EnableSjLj(EnableSjLj),
290  ThrewGV(nullptr), ThrewValueGV(nullptr), TempRet0GV(nullptr),
291  ResumeF(nullptr), EHTypeIDF(nullptr), EmLongjmpF(nullptr),
292  EmLongjmpJmpbufF(nullptr), SaveSetjmpF(nullptr), TestSetjmpF(nullptr) {
293  EHWhitelistSet.insert(EHWhitelist.begin(), EHWhitelist.end());
294  }
295  bool runOnModule(Module &M) override;
296 
297  void getAnalysisUsage(AnalysisUsage &AU) const override {
299  }
300 };
301 } // End anonymous namespace
302 
303 const char *WebAssemblyLowerEmscriptenEHSjLj::ThrewGVName = "__THREW__";
304 const char *WebAssemblyLowerEmscriptenEHSjLj::ThrewValueGVName = "__threwValue";
305 const char *WebAssemblyLowerEmscriptenEHSjLj::TempRet0GVName = "__tempRet0";
306 const char *WebAssemblyLowerEmscriptenEHSjLj::ResumeFName = "__resumeException";
307 const char *WebAssemblyLowerEmscriptenEHSjLj::EHTypeIDFName =
308  "llvm_eh_typeid_for";
309 const char *WebAssemblyLowerEmscriptenEHSjLj::SetThrewFName = "setThrew";
310 const char *WebAssemblyLowerEmscriptenEHSjLj::SetTempRet0FName = "setTempRet0";
311 const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpFName =
312  "emscripten_longjmp";
313 const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpJmpbufFName =
314  "emscripten_longjmp_jmpbuf";
315 const char *WebAssemblyLowerEmscriptenEHSjLj::SaveSetjmpFName = "saveSetjmp";
316 const char *WebAssemblyLowerEmscriptenEHSjLj::TestSetjmpFName = "testSetjmp";
317 const char *WebAssemblyLowerEmscriptenEHSjLj::FindMatchingCatchPrefix =
318  "__cxa_find_matching_catch_";
319 const char *WebAssemblyLowerEmscriptenEHSjLj::InvokePrefix = "__invoke_";
320 
322 INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE,
323  "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
324  false, false)
325 
327  bool EnableSjLj) {
328  return new WebAssemblyLowerEmscriptenEHSjLj(EnableEH, EnableSjLj);
329 }
330 
331 static bool canThrow(const Value *V) {
332  if (const auto *F = dyn_cast<const Function>(V)) {
333  // Intrinsics cannot throw
334  if (F->isIntrinsic())
335  return false;
336  StringRef Name = F->getName();
337  // leave setjmp and longjmp (mostly) alone, we process them properly later
338  if (Name == "setjmp" || Name == "longjmp")
339  return false;
340  return !F->doesNotThrow();
341  }
342  // not a function, so an indirect call - can throw, we can't tell
343  return true;
344 }
345 
346 // Returns an available name for a global value.
347 // If the proposed name already exists in the module, adds '_' at the end of
348 // the name until the name is available.
349 static inline std::string createGlobalValueName(const Module &M,
350  const std::string &Propose) {
351  std::string Name = Propose;
352  while (M.getNamedGlobal(Name))
353  Name += "_";
354  return Name;
355 }
356 
357 // Simple function name mangler.
358 // This function simply takes LLVM's string representation of parameter types
359 // and concatenate them with '_'. There are non-alphanumeric characters but llc
360 // is ok with it, and we need to postprocess these names after the lowering
361 // phase anyway.
362 static std::string getSignature(FunctionType *FTy) {
363  std::string Sig;
364  raw_string_ostream OS(Sig);
365  OS << *FTy->getReturnType();
366  for (Type *ParamTy : FTy->params())
367  OS << "_" << *ParamTy;
368  if (FTy->isVarArg())
369  OS << "_...";
370  Sig = OS.str();
371  Sig.erase(remove_if(Sig, isspace), Sig.end());
372  // When s2wasm parses .s file, a comma means the end of an argument. So a
373  // mangled function name can contain any character but a comma.
374  std::replace(Sig.begin(), Sig.end(), ',', '.');
375  return Sig;
376 }
377 
378 // Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
379 // This is because a landingpad instruction contains two more arguments, a
380 // personality function and a cleanup bit, and __cxa_find_matching_catch_N
381 // functions are named after the number of arguments in the original landingpad
382 // instruction.
383 Function *
384 WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
385  unsigned NumClauses) {
386  if (FindMatchingCatches.count(NumClauses))
387  return FindMatchingCatches[NumClauses];
388  PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
389  SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy);
390  FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
391  Function *F =
393  FindMatchingCatchPrefix + Twine(NumClauses + 2), &M);
394  FindMatchingCatches[NumClauses] = F;
395  return F;
396 }
397 
398 // Generate invoke wrapper seqence with preamble and postamble
399 // Preamble:
400 // __THREW__ = 0;
401 // Postamble:
402 // %__THREW__.val = __THREW__; __THREW__ = 0;
403 // Returns %__THREW__.val, which indicates whether an exception is thrown (or
404 // whether longjmp occurred), for future use.
405 template <typename CallOrInvoke>
406 Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallOrInvoke *CI) {
407  LLVMContext &C = CI->getModule()->getContext();
408 
409  // If we are calling a function that is noreturn, we must remove that
410  // attribute. The code we insert here does expect it to return, after we
411  // catch the exception.
412  if (CI->doesNotReturn()) {
413  if (auto *F = dyn_cast<Function>(CI->getCalledValue()))
414  F->removeFnAttr(Attribute::NoReturn);
415  CI->removeAttribute(AttributeList::FunctionIndex, Attribute::NoReturn);
416  }
417 
418  IRBuilder<> IRB(C);
419  IRB.SetInsertPoint(CI);
420 
421  // Pre-invoke
422  // __THREW__ = 0;
423  IRB.CreateStore(IRB.getInt32(0), ThrewGV);
424 
425  // Invoke function wrapper in JavaScript
427  // Put the pointer to the callee as first argument, so it can be called
428  // within the invoke wrapper later
429  Args.push_back(CI->getCalledValue());
430  Args.append(CI->arg_begin(), CI->arg_end());
431  CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
432  NewCall->takeName(CI);
433  NewCall->setCallingConv(CI->getCallingConv());
434  NewCall->setDebugLoc(CI->getDebugLoc());
435 
436  // Because we added the pointer to the callee as first argument, all
437  // argument attribute indices have to be incremented by one.
438  SmallVector<AttributeSet, 8> ArgAttributes;
439  const AttributeList &InvokeAL = CI->getAttributes();
440 
441  // No attributes for the callee pointer.
442  ArgAttributes.push_back(AttributeSet());
443  // Copy the argument attributes from the original
444  for (unsigned i = 0, e = CI->getNumArgOperands(); i < e; ++i)
445  ArgAttributes.push_back(InvokeAL.getParamAttributes(i));
446 
447  // Reconstruct the AttributesList based on the vector we constructed.
448  AttributeList NewCallAL =
449  AttributeList::get(C, InvokeAL.getFnAttributes(),
450  InvokeAL.getRetAttributes(), ArgAttributes);
451  NewCall->setAttributes(NewCallAL);
452 
453  CI->replaceAllUsesWith(NewCall);
454 
455  // Post-invoke
456  // %__THREW__.val = __THREW__; __THREW__ = 0;
457  Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
458  IRB.CreateStore(IRB.getInt32(0), ThrewGV);
459  return Threw;
460 }
461 
462 // Get matching invoke wrapper based on callee signature
463 template <typename CallOrInvoke>
464 Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallOrInvoke *CI) {
465  Module *M = CI->getModule();
467  Value *Callee = CI->getCalledValue();
468  FunctionType *CalleeFTy;
469  if (auto *F = dyn_cast<Function>(Callee))
470  CalleeFTy = F->getFunctionType();
471  else {
472  auto *CalleeTy = cast<PointerType>(Callee->getType())->getElementType();
473  CalleeFTy = dyn_cast<FunctionType>(CalleeTy);
474  }
475 
476  std::string Sig = getSignature(CalleeFTy);
477  if (InvokeWrappers.find(Sig) != InvokeWrappers.end())
478  return InvokeWrappers[Sig];
479 
480  // Put the pointer to the callee as first argument
481  ArgTys.push_back(PointerType::getUnqual(CalleeFTy));
482  // Add argument types
483  ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end());
484 
485  FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
486  CalleeFTy->isVarArg());
488  InvokePrefix + Sig, M);
489  InvokeWrappers[Sig] = F;
490  return F;
491 }
492 
493 bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(Module &M,
494  const Value *Callee) const {
495  if (auto *CalleeF = dyn_cast<Function>(Callee))
496  if (CalleeF->isIntrinsic())
497  return false;
498 
499  // The reason we include malloc/free here is to exclude the malloc/free
500  // calls generated in setjmp prep / cleanup routines.
501  Function *SetjmpF = M.getFunction("setjmp");
502  Function *MallocF = M.getFunction("malloc");
503  Function *FreeF = M.getFunction("free");
504  if (Callee == SetjmpF || Callee == MallocF || Callee == FreeF)
505  return false;
506 
507  // There are functions in JS glue code
508  if (Callee == ResumeF || Callee == EHTypeIDF || Callee == SaveSetjmpF ||
509  Callee == TestSetjmpF)
510  return false;
511 
512  // __cxa_find_matching_catch_N functions cannot longjmp
513  if (Callee->getName().startswith(FindMatchingCatchPrefix))
514  return false;
515 
516  // Exception-catching related functions
517  Function *BeginCatchF = M.getFunction("__cxa_begin_catch");
518  Function *EndCatchF = M.getFunction("__cxa_end_catch");
519  Function *AllocExceptionF = M.getFunction("__cxa_allocate_exception");
520  Function *ThrowF = M.getFunction("__cxa_throw");
521  Function *TerminateF = M.getFunction("__clang_call_terminate");
522  if (Callee == BeginCatchF || Callee == EndCatchF ||
523  Callee == AllocExceptionF || Callee == ThrowF || Callee == TerminateF)
524  return false;
525 
526  // Otherwise we don't know
527  return true;
528 }
529 
530 // Generate testSetjmp function call seqence with preamble and postamble.
531 // The code this generates is equivalent to the following JavaScript code:
532 // if (%__THREW__.val != 0 & threwValue != 0) {
533 // %label = _testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
534 // if (%label == 0)
535 // emscripten_longjmp(%__THREW__.val, threwValue);
536 // __tempRet0 = threwValue;
537 // } else {
538 // %label = -1;
539 // }
540 // %longjmp_result = __tempRet0;
541 //
542 // As output parameters. returns %label, %longjmp_result, and the BB the last
543 // instruction (%longjmp_result = ...) is in.
544 void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
545  BasicBlock *BB, Instruction *InsertPt, Value *Threw, Value *SetjmpTable,
546  Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult,
547  BasicBlock *&EndBB) {
548  Function *F = BB->getParent();
549  LLVMContext &C = BB->getModule()->getContext();
550  IRBuilder<> IRB(C);
551  IRB.SetInsertPoint(InsertPt);
552 
553  // if (%__THREW__.val != 0 & threwValue != 0)
554  IRB.SetInsertPoint(BB);
555  BasicBlock *ThenBB1 = BasicBlock::Create(C, "if.then1", F);
556  BasicBlock *ElseBB1 = BasicBlock::Create(C, "if.else1", F);
557  BasicBlock *EndBB1 = BasicBlock::Create(C, "if.end", F);
558  Value *ThrewCmp = IRB.CreateICmpNE(Threw, IRB.getInt32(0));
559  Value *ThrewValue =
560  IRB.CreateLoad(ThrewValueGV, ThrewValueGV->getName() + ".val");
561  Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
562  Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp, "cmp1");
563  IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
564 
565  // %label = _testSetjmp(mem[%__THREW__.val], _setjmpTable, _setjmpTableSize);
566  // if (%label == 0)
567  IRB.SetInsertPoint(ThenBB1);
568  BasicBlock *ThenBB2 = BasicBlock::Create(C, "if.then2", F);
569  BasicBlock *EndBB2 = BasicBlock::Create(C, "if.end2", F);
570  Value *ThrewInt = IRB.CreateIntToPtr(Threw, Type::getInt32PtrTy(C),
571  Threw->getName() + ".i32p");
572  Value *LoadedThrew =
573  IRB.CreateLoad(ThrewInt, ThrewInt->getName() + ".loaded");
574  Value *ThenLabel = IRB.CreateCall(
575  TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, "label");
576  Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
577  IRB.CreateCondBr(Cmp2, ThenBB2, EndBB2);
578 
579  // emscripten_longjmp(%__THREW__.val, threwValue);
580  IRB.SetInsertPoint(ThenBB2);
581  IRB.CreateCall(EmLongjmpF, {Threw, ThrewValue});
582  IRB.CreateUnreachable();
583 
584  // __tempRet0 = threwValue;
585  IRB.SetInsertPoint(EndBB2);
586  IRB.CreateStore(ThrewValue, TempRet0GV);
587  IRB.CreateBr(EndBB1);
588 
589  IRB.SetInsertPoint(ElseBB1);
590  IRB.CreateBr(EndBB1);
591 
592  // longjmp_result = __tempRet0;
593  IRB.SetInsertPoint(EndBB1);
594  PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label");
595  LabelPHI->addIncoming(ThenLabel, EndBB2);
596 
597  LabelPHI->addIncoming(IRB.getInt32(-1), ElseBB1);
598 
599  // Output parameter assignment
600  Label = LabelPHI;
601  EndBB = EndBB1;
602  LongjmpResult = IRB.CreateLoad(TempRet0GV, "longjmp_result");
603 }
604 
605 // Create setThrew function
606 // function setThrew(threw, value) {
607 // if (__THREW__ == 0) {
608 // __THREW__ = threw;
609 // __threwValue = value;
610 // }
611 // }
612 void WebAssemblyLowerEmscriptenEHSjLj::createSetThrewFunction(Module &M) {
613  LLVMContext &C = M.getContext();
614  IRBuilder<> IRB(C);
615 
616  assert(!M.getNamedGlobal(SetThrewFName) && "setThrew already exists");
617  Type *Params[] = {IRB.getInt32Ty(), IRB.getInt32Ty()};
618  FunctionType *FTy = FunctionType::get(IRB.getVoidTy(), Params, false);
619  Function *F =
620  Function::Create(FTy, GlobalValue::ExternalLinkage, SetThrewFName, &M);
621  Argument *Arg1 = &*(F->arg_begin());
622  Argument *Arg2 = &*std::next(F->arg_begin());
623  Arg1->setName("threw");
624  Arg2->setName("value");
625  BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
626  BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", F);
627  BasicBlock *EndBB = BasicBlock::Create(C, "if.end", F);
628 
629  IRB.SetInsertPoint(EntryBB);
630  Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
631  Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getInt32(0), "cmp");
632  IRB.CreateCondBr(Cmp, ThenBB, EndBB);
633 
634  IRB.SetInsertPoint(ThenBB);
635  IRB.CreateStore(Arg1, ThrewGV);
636  IRB.CreateStore(Arg2, ThrewValueGV);
637  IRB.CreateBr(EndBB);
638 
639  IRB.SetInsertPoint(EndBB);
640  IRB.CreateRetVoid();
641 }
642 
643 // Create setTempRet0 function
644 // function setTempRet0(value) {
645 // __tempRet0 = value;
646 // }
647 void WebAssemblyLowerEmscriptenEHSjLj::createSetTempRet0Function(Module &M) {
648  LLVMContext &C = M.getContext();
649  IRBuilder<> IRB(C);
650 
651  assert(!M.getNamedGlobal(SetTempRet0FName) && "setTempRet0 already exists");
652  Type *Params[] = {IRB.getInt32Ty()};
653  FunctionType *FTy = FunctionType::get(IRB.getVoidTy(), Params, false);
654  Function *F =
655  Function::Create(FTy, GlobalValue::ExternalLinkage, SetTempRet0FName, &M);
656  F->arg_begin()->setName("value");
657  BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
658  IRB.SetInsertPoint(EntryBB);
659  IRB.CreateStore(&*F->arg_begin(), TempRet0GV);
660  IRB.CreateRetVoid();
661 }
662 
663 void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
664  DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
665  DT.recalculate(F); // CFG has been changed
666  SSAUpdater SSA;
667  for (BasicBlock &BB : F) {
668  for (Instruction &I : BB) {
669  for (auto UI = I.use_begin(), UE = I.use_end(); UI != UE;) {
670  Use &U = *UI;
671  ++UI;
672  SSA.Initialize(I.getType(), I.getName());
673  SSA.AddAvailableValue(&BB, &I);
674  Instruction *User = cast<Instruction>(U.getUser());
675  if (User->getParent() == &BB)
676  continue;
677 
678  if (PHINode *UserPN = dyn_cast<PHINode>(User))
679  if (UserPN->getIncomingBlock(U) == &BB)
680  continue;
681 
682  if (DT.dominates(&I, User))
683  continue;
685  }
686  }
687  }
688 }
689 
690 bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
691  LLVMContext &C = M.getContext();
692  IRBuilder<> IRB(C);
693 
694  Function *SetjmpF = M.getFunction("setjmp");
695  Function *LongjmpF = M.getFunction("longjmp");
696  bool SetjmpUsed = SetjmpF && !SetjmpF->use_empty();
697  bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
698  bool DoSjLj = EnableSjLj && (SetjmpUsed || LongjmpUsed);
699 
700  // Create global variables __THREW__, threwValue, and __tempRet0, which are
701  // used in common for both exception handling and setjmp/longjmp handling
702  ThrewGV = new GlobalVariable(M, IRB.getInt32Ty(), false,
704  createGlobalValueName(M, ThrewGVName));
705  ThrewValueGV = new GlobalVariable(
706  M, IRB.getInt32Ty(), false, GlobalValue::ExternalLinkage, IRB.getInt32(0),
707  createGlobalValueName(M, ThrewValueGVName));
708  TempRet0GV = new GlobalVariable(M, IRB.getInt32Ty(), false,
710  createGlobalValueName(M, TempRet0GVName));
711 
712  bool Changed = false;
713 
714  // Exception handling
715  if (EnableEH) {
716  // Register __resumeException function
717  FunctionType *ResumeFTy =
718  FunctionType::get(IRB.getVoidTy(), IRB.getInt8PtrTy(), false);
719  ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage,
720  ResumeFName, &M);
721 
722  // Register llvm_eh_typeid_for function
723  FunctionType *EHTypeIDTy =
724  FunctionType::get(IRB.getInt32Ty(), IRB.getInt8PtrTy(), false);
725  EHTypeIDF = Function::Create(EHTypeIDTy, GlobalValue::ExternalLinkage,
726  EHTypeIDFName, &M);
727 
728  for (Function &F : M) {
729  if (F.isDeclaration())
730  continue;
731  Changed |= runEHOnFunction(F);
732  }
733  }
734 
735  // Setjmp/longjmp handling
736  if (DoSjLj) {
737  Changed = true; // We have setjmp or longjmp somewhere
738 
739  Function *MallocF = M.getFunction("malloc");
740  Function *FreeF = M.getFunction("free");
741  if (!MallocF || !FreeF)
743  "malloc and free must be linked into the module if setjmp is used");
744 
745  // Register saveSetjmp function
746  FunctionType *SetjmpFTy = SetjmpF->getFunctionType();
747  SmallVector<Type *, 4> Params = {SetjmpFTy->getParamType(0),
749  IRB.getInt32Ty()};
750  FunctionType *FTy =
751  FunctionType::get(Type::getInt32PtrTy(C), Params, false);
753  SaveSetjmpFName, &M);
754 
755  // Register testSetjmp function
756  Params = {IRB.getInt32Ty(), Type::getInt32PtrTy(C), IRB.getInt32Ty()};
757  FTy = FunctionType::get(IRB.getInt32Ty(), Params, false);
759  TestSetjmpFName, &M);
760 
761  if (LongjmpF) {
762  // Replace all uses of longjmp with emscripten_longjmp_jmpbuf, which is
763  // defined in JS code
764  EmLongjmpJmpbufF = Function::Create(LongjmpF->getFunctionType(),
766  EmLongjmpJmpbufFName, &M);
767 
768  LongjmpF->replaceAllUsesWith(EmLongjmpJmpbufF);
769  }
770  FTy = FunctionType::get(IRB.getVoidTy(),
771  {IRB.getInt32Ty(), IRB.getInt32Ty()}, false);
772  EmLongjmpF =
773  Function::Create(FTy, GlobalValue::ExternalLinkage, EmLongjmpFName, &M);
774 
775  // Only traverse functions that uses setjmp in order not to insert
776  // unnecessary prep / cleanup code in every function
777  SmallPtrSet<Function *, 8> SetjmpUsers;
778  for (User *U : SetjmpF->users()) {
779  auto *UI = cast<Instruction>(U);
780  SetjmpUsers.insert(UI->getFunction());
781  }
782  for (Function *F : SetjmpUsers)
783  runSjLjOnFunction(*F);
784  }
785 
786  if (!Changed) {
787  // Delete unused global variables and functions
788  ThrewGV->eraseFromParent();
789  ThrewValueGV->eraseFromParent();
790  TempRet0GV->eraseFromParent();
791  if (ResumeF)
792  ResumeF->eraseFromParent();
793  if (EHTypeIDF)
794  EHTypeIDF->eraseFromParent();
795  if (EmLongjmpF)
796  EmLongjmpF->eraseFromParent();
797  if (SaveSetjmpF)
798  SaveSetjmpF->eraseFromParent();
799  if (TestSetjmpF)
800  TestSetjmpF->eraseFromParent();
801  return false;
802  }
803 
804  // If we have made any changes while doing exception handling or
805  // setjmp/longjmp handling, we have to create these functions for JavaScript
806  // to call.
807  createSetThrewFunction(M);
808  createSetTempRet0Function(M);
809 
810  return true;
811 }
812 
813 bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
814  Module &M = *F.getParent();
815  LLVMContext &C = F.getContext();
816  IRBuilder<> IRB(C);
817  bool Changed = false;
820  bool AllowExceptions =
821  areAllExceptionsAllowed() || EHWhitelistSet.count(F.getName());
822 
823  for (BasicBlock &BB : F) {
824  auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
825  if (!II)
826  continue;
827  Changed = true;
828  LandingPads.insert(II->getLandingPadInst());
829  IRB.SetInsertPoint(II);
830 
831  bool NeedInvoke = AllowExceptions && canThrow(II->getCalledValue());
832  if (NeedInvoke) {
833  // Wrap invoke with invoke wrapper and generate preamble/postamble
834  Value *Threw = wrapInvoke(II);
835  ToErase.push_back(II);
836 
837  // Insert a branch based on __THREW__ variable
838  Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getInt32(1), "cmp");
839  IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
840 
841  } else {
842  // This can't throw, and we don't need this invoke, just replace it with a
843  // call+branch
844  SmallVector<Value *, 16> Args(II->arg_begin(), II->arg_end());
845  CallInst *NewCall = IRB.CreateCall(II->getCalledValue(), Args);
846  NewCall->takeName(II);
847  NewCall->setCallingConv(II->getCallingConv());
848  NewCall->setDebugLoc(II->getDebugLoc());
849  NewCall->setAttributes(II->getAttributes());
850  II->replaceAllUsesWith(NewCall);
851  ToErase.push_back(II);
852 
853  IRB.CreateBr(II->getNormalDest());
854 
855  // Remove any PHI node entries from the exception destination
856  II->getUnwindDest()->removePredecessor(&BB);
857  }
858  }
859 
860  // Process resume instructions
861  for (BasicBlock &BB : F) {
862  // Scan the body of the basic block for resumes
863  for (Instruction &I : BB) {
864  auto *RI = dyn_cast<ResumeInst>(&I);
865  if (!RI)
866  continue;
867 
868  // Split the input into legal values
869  Value *Input = RI->getValue();
870  IRB.SetInsertPoint(RI);
871  Value *Low = IRB.CreateExtractValue(Input, 0, "low");
872  // Create a call to __resumeException function
873  IRB.CreateCall(ResumeF, {Low});
874  // Add a terminator to the block
875  IRB.CreateUnreachable();
876  ToErase.push_back(RI);
877  }
878  }
879 
880  // Process llvm.eh.typeid.for intrinsics
881  for (BasicBlock &BB : F) {
882  for (Instruction &I : BB) {
883  auto *CI = dyn_cast<CallInst>(&I);
884  if (!CI)
885  continue;
886  const Function *Callee = CI->getCalledFunction();
887  if (!Callee)
888  continue;
889  if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
890  continue;
891 
892  IRB.SetInsertPoint(CI);
893  CallInst *NewCI =
894  IRB.CreateCall(EHTypeIDF, CI->getArgOperand(0), "typeid");
895  CI->replaceAllUsesWith(NewCI);
896  ToErase.push_back(CI);
897  }
898  }
899 
900  // Look for orphan landingpads, can occur in blocks with no predecessors
901  for (BasicBlock &BB : F) {
902  Instruction *I = BB.getFirstNonPHI();
903  if (auto *LPI = dyn_cast<LandingPadInst>(I))
904  LandingPads.insert(LPI);
905  }
906 
907  // Handle all the landingpad for this function together, as multiple invokes
908  // may share a single lp
909  for (LandingPadInst *LPI : LandingPads) {
910  IRB.SetInsertPoint(LPI);
911  SmallVector<Value *, 16> FMCArgs;
912  for (unsigned i = 0, e = LPI->getNumClauses(); i < e; ++i) {
913  Constant *Clause = LPI->getClause(i);
914  // As a temporary workaround for the lack of aggregate varargs support
915  // in the interface between JS and wasm, break out filter operands into
916  // their component elements.
917  if (LPI->isFilter(i)) {
918  auto *ATy = cast<ArrayType>(Clause->getType());
919  for (unsigned j = 0, e = ATy->getNumElements(); j < e; ++j) {
920  Value *EV = IRB.CreateExtractValue(Clause, makeArrayRef(j), "filter");
921  FMCArgs.push_back(EV);
922  }
923  } else
924  FMCArgs.push_back(Clause);
925  }
926 
927  // Create a call to __cxa_find_matching_catch_N function
928  Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
929  CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc");
930  Value *Undef = UndefValue::get(LPI->getType());
931  Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0");
932  Value *TempRet0 =
933  IRB.CreateLoad(TempRet0GV, TempRet0GV->getName() + ".val");
934  Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
935 
936  LPI->replaceAllUsesWith(Pair1);
937  ToErase.push_back(LPI);
938  }
939 
940  // Erase everything we no longer need in this function
941  for (Instruction *I : ToErase)
942  I->eraseFromParent();
943 
944  return Changed;
945 }
946 
947 bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
948  Module &M = *F.getParent();
949  LLVMContext &C = F.getContext();
950  IRBuilder<> IRB(C);
952  // Vector of %setjmpTable values
953  std::vector<Instruction *> SetjmpTableInsts;
954  // Vector of %setjmpTableSize values
955  std::vector<Instruction *> SetjmpTableSizeInsts;
956 
957  // Setjmp preparation
958 
959  // This instruction effectively means %setjmpTableSize = 4.
960  // We create this as an instruction intentionally, and we don't want to fold
961  // this instruction to a constant 4, because this value will be used in
962  // SSAUpdater.AddAvailableValue(...) later.
963  BasicBlock &EntryBB = F.getEntryBlock();
964  BinaryOperator *SetjmpTableSize = BinaryOperator::Create(
965  Instruction::Add, IRB.getInt32(4), IRB.getInt32(0), "setjmpTableSize",
966  &*EntryBB.getFirstInsertionPt());
967  // setjmpTable = (int *) malloc(40);
968  Instruction *SetjmpTable = CallInst::CreateMalloc(
969  SetjmpTableSize, IRB.getInt32Ty(), IRB.getInt32Ty(), IRB.getInt32(40),
970  nullptr, nullptr, "setjmpTable");
971  // setjmpTable[0] = 0;
972  IRB.SetInsertPoint(SetjmpTableSize);
973  IRB.CreateStore(IRB.getInt32(0), SetjmpTable);
974  SetjmpTableInsts.push_back(SetjmpTable);
975  SetjmpTableSizeInsts.push_back(SetjmpTableSize);
976 
977  // Setjmp transformation
978  std::vector<PHINode *> SetjmpRetPHIs;
979  Function *SetjmpF = M.getFunction("setjmp");
980  for (User *U : SetjmpF->users()) {
981  auto *CI = dyn_cast<CallInst>(U);
982  if (!CI)
983  report_fatal_error("Does not support indirect calls to setjmp");
984 
985  BasicBlock *BB = CI->getParent();
986  if (BB->getParent() != &F) // in other function
987  continue;
988 
989  // The tail is everything right after the call, and will be reached once
990  // when setjmp is called, and later when longjmp returns to the setjmp
991  BasicBlock *Tail = SplitBlock(BB, CI->getNextNode());
992  // Add a phi to the tail, which will be the output of setjmp, which
993  // indicates if this is the first call or a longjmp back. The phi directly
994  // uses the right value based on where we arrive from
995  IRB.SetInsertPoint(Tail->getFirstNonPHI());
996  PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2, "setjmp.ret");
997 
998  // setjmp initial call returns 0
999  SetjmpRet->addIncoming(IRB.getInt32(0), BB);
1000  // The proper output is now this, not the setjmp call itself
1001  CI->replaceAllUsesWith(SetjmpRet);
1002  // longjmp returns to the setjmp will add themselves to this phi
1003  SetjmpRetPHIs.push_back(SetjmpRet);
1004 
1005  // Fix call target
1006  // Our index in the function is our place in the array + 1 to avoid index
1007  // 0, because index 0 means the longjmp is not ours to handle.
1008  IRB.SetInsertPoint(CI);
1009  Value *Args[] = {CI->getArgOperand(0), IRB.getInt32(SetjmpRetPHIs.size()),
1010  SetjmpTable, SetjmpTableSize};
1011  Instruction *NewSetjmpTable =
1012  IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable");
1013  Instruction *NewSetjmpTableSize =
1014  IRB.CreateLoad(TempRet0GV, "setjmpTableSize");
1015  SetjmpTableInsts.push_back(NewSetjmpTable);
1016  SetjmpTableSizeInsts.push_back(NewSetjmpTableSize);
1017  ToErase.push_back(CI);
1018  }
1019 
1020  // Update each call that can longjmp so it can return to a setjmp where
1021  // relevant.
1022 
1023  // Because we are creating new BBs while processing and don't want to make
1024  // all these newly created BBs candidates again for longjmp processing, we
1025  // first make the vector of candidate BBs.
1026  std::vector<BasicBlock *> BBs;
1027  for (BasicBlock &BB : F)
1028  BBs.push_back(&BB);
1029 
1030  // BBs.size() will change within the loop, so we query it every time
1031  for (unsigned i = 0; i < BBs.size(); i++) {
1032  BasicBlock *BB = BBs[i];
1033  for (Instruction &I : *BB) {
1034  assert(!isa<InvokeInst>(&I));
1035  auto *CI = dyn_cast<CallInst>(&I);
1036  if (!CI)
1037  continue;
1038 
1039  const Value *Callee = CI->getCalledValue();
1040  if (!canLongjmp(M, Callee))
1041  continue;
1042 
1043  Value *Threw = nullptr;
1044  BasicBlock *Tail;
1045  if (Callee->getName().startswith(InvokePrefix)) {
1046  // If invoke wrapper has already been generated for this call in
1047  // previous EH phase, search for the load instruction
1048  // %__THREW__.val = __THREW__;
1049  // in postamble after the invoke wrapper call
1050  LoadInst *ThrewLI = nullptr;
1051  StoreInst *ThrewResetSI = nullptr;
1052  for (auto I = std::next(BasicBlock::iterator(CI)), IE = BB->end();
1053  I != IE; ++I) {
1054  if (auto *LI = dyn_cast<LoadInst>(I))
1055  if (auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
1056  if (GV == ThrewGV) {
1057  Threw = ThrewLI = LI;
1058  break;
1059  }
1060  }
1061  // Search for the store instruction after the load above
1062  // __THREW__ = 0;
1063  for (auto I = std::next(BasicBlock::iterator(ThrewLI)), IE = BB->end();
1064  I != IE; ++I) {
1065  if (auto *SI = dyn_cast<StoreInst>(I))
1066  if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand()))
1067  if (GV == ThrewGV && SI->getValueOperand() == IRB.getInt32(0)) {
1068  ThrewResetSI = SI;
1069  break;
1070  }
1071  }
1072  assert(Threw && ThrewLI && "Cannot find __THREW__ load after invoke");
1073  assert(ThrewResetSI && "Cannot find __THREW__ store after invoke");
1074  Tail = SplitBlock(BB, ThrewResetSI->getNextNode());
1075 
1076  } else {
1077  // Wrap call with invoke wrapper and generate preamble/postamble
1078  Threw = wrapInvoke(CI);
1079  ToErase.push_back(CI);
1080  Tail = SplitBlock(BB, CI->getNextNode());
1081  }
1082 
1083  // We need to replace the terminator in Tail - SplitBlock makes BB go
1084  // straight to Tail, we need to check if a longjmp occurred, and go to the
1085  // right setjmp-tail if so
1086  ToErase.push_back(BB->getTerminator());
1087 
1088  // Generate a function call to testSetjmp function and preamble/postamble
1089  // code to figure out (1) whether longjmp occurred (2) if longjmp
1090  // occurred, which setjmp it corresponds to
1091  Value *Label = nullptr;
1092  Value *LongjmpResult = nullptr;
1093  BasicBlock *EndBB = nullptr;
1094  wrapTestSetjmp(BB, CI, Threw, SetjmpTable, SetjmpTableSize, Label,
1095  LongjmpResult, EndBB);
1096  assert(Label && LongjmpResult && EndBB);
1097 
1098  // Create switch instruction
1099  IRB.SetInsertPoint(EndBB);
1100  SwitchInst *SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.size());
1101  // -1 means no longjmp happened, continue normally (will hit the default
1102  // switch case). 0 means a longjmp that is not ours to handle, needs a
1103  // rethrow. Otherwise the index is the same as the index in P+1 (to avoid
1104  // 0).
1105  for (unsigned i = 0; i < SetjmpRetPHIs.size(); i++) {
1106  SI->addCase(IRB.getInt32(i + 1), SetjmpRetPHIs[i]->getParent());
1107  SetjmpRetPHIs[i]->addIncoming(LongjmpResult, EndBB);
1108  }
1109 
1110  // We are splitting the block here, and must continue to find other calls
1111  // in the block - which is now split. so continue to traverse in the Tail
1112  BBs.push_back(Tail);
1113  }
1114  }
1115 
1116  // Erase everything we no longer need in this function
1117  for (Instruction *I : ToErase)
1118  I->eraseFromParent();
1119 
1120  // Free setjmpTable buffer before each return instruction
1121  for (BasicBlock &BB : F) {
1122  TerminatorInst *TI = BB.getTerminator();
1123  if (isa<ReturnInst>(TI))
1124  CallInst::CreateFree(SetjmpTable, TI);
1125  }
1126 
1127  // Every call to saveSetjmp can change setjmpTable and setjmpTableSize
1128  // (when buffer reallocation occurs)
1129  // entry:
1130  // setjmpTableSize = 4;
1131  // setjmpTable = (int *) malloc(40);
1132  // setjmpTable[0] = 0;
1133  // ...
1134  // somebb:
1135  // setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
1136  // setjmpTableSize = __tempRet0;
1137  // So we need to make sure the SSA for these variables is valid so that every
1138  // saveSetjmp and testSetjmp calls have the correct arguments.
1139  SSAUpdater SetjmpTableSSA;
1140  SSAUpdater SetjmpTableSizeSSA;
1141  SetjmpTableSSA.Initialize(Type::getInt32PtrTy(C), "setjmpTable");
1142  SetjmpTableSizeSSA.Initialize(Type::getInt32Ty(C), "setjmpTableSize");
1143  for (Instruction *I : SetjmpTableInsts)
1144  SetjmpTableSSA.AddAvailableValue(I->getParent(), I);
1145  for (Instruction *I : SetjmpTableSizeInsts)
1146  SetjmpTableSizeSSA.AddAvailableValue(I->getParent(), I);
1147 
1148  for (auto UI = SetjmpTable->use_begin(), UE = SetjmpTable->use_end();
1149  UI != UE;) {
1150  // Grab the use before incrementing the iterator.
1151  Use &U = *UI;
1152  // Increment the iterator before removing the use from the list.
1153  ++UI;
1154  if (Instruction *I = dyn_cast<Instruction>(U.getUser()))
1155  if (I->getParent() != &EntryBB)
1156  SetjmpTableSSA.RewriteUse(U);
1157  }
1158  for (auto UI = SetjmpTableSize->use_begin(), UE = SetjmpTableSize->use_end();
1159  UI != UE;) {
1160  Use &U = *UI;
1161  ++UI;
1162  if (Instruction *I = dyn_cast<Instruction>(U.getUser()))
1163  if (I->getParent() != &EntryBB)
1164  SetjmpTableSizeSSA.RewriteUse(U);
1165  }
1166 
1167  // Finally, our modifications to the cfg can break dominance of SSA variables.
1168  // For example, in this code,
1169  // if (x()) { .. setjmp() .. }
1170  // if (y()) { .. longjmp() .. }
1171  // We must split the longjmp block, and it can jump into the block splitted
1172  // from setjmp one. But that means that when we split the setjmp block, it's
1173  // first part no longer dominates its second part - there is a theoretically
1174  // possible control flow path where x() is false, then y() is true and we
1175  // reach the second part of the setjmp block, without ever reaching the first
1176  // part. So, we rebuild SSA form here.
1177  rebuildSSA(F);
1178  return true;
1179 }
uint64_t CallInst * C
use_iterator use_end()
Definition: Value.h:352
BranchInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a conditional &#39;br Cond, TrueDest, FalseDest&#39; instruction.
Definition: IRBuilder.h:825
Helper class for SSA formation on a set of values defined in multiple blocks.
Definition: SSAUpdater.h:39
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
ModulePass * createWebAssemblyLowerEmscriptenEHSjLj(bool DoEH, bool DoSjLj)
This class represents an incoming formal argument to a Function.
Definition: Argument.h:30
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:1631
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition: ilist_node.h:289
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:115
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
BasicBlock * SplitBlock(BasicBlock *Old, Instruction *SplitPt, DominatorTree *DT=nullptr, LoopInfo *LI=nullptr)
Split the specified block at the specified instruction - everything before SplitPt stays in Old and e...
Type * getParamType(unsigned i) const
Parameter type accessors.
Definition: DerivedTypes.h:135
void Initialize(Type *Ty, StringRef Name)
Reset this object to get ready for a new set of SSA updates with type &#39;Ty&#39;.
Definition: SSAUpdater.cpp:54
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:63
LLVM_ATTRIBUTE_ALWAYS_INLINE size_type size() const
Definition: SmallVector.h:136
void AddAvailableValue(BasicBlock *BB, Value *V)
Indicate that a rewritten value is available in the specified block with the specified value...
Definition: SSAUpdater.cpp:67
void addCase(ConstantInt *OnVal, BasicBlock *Dest)
Add an entry to the switch instruction.
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
This class represents a function call, abstracting a target machine&#39;s calling convention.
static PointerType * getInt32PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:228
const GlobalVariable * getNamedGlobal(StringRef Name) const
Return the global variable in the module with the specified name, of arbitrary type.
Definition: Module.h:383
iterator find(StringRef Key)
Definition: StringMap.h:335
Externally visible function.
Definition: GlobalValue.h:49
F(f)
param_iterator param_end() const
Definition: DerivedTypes.h:129
An instruction for reading from memory.
Definition: Instructions.h:164
static Instruction * CreateFree(Value *Source, Instruction *InsertBefore)
Generate the IR for a call to the builtin free function.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
static bool canThrow(const Value *V)
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Definition: IRBuilder.h:348
AnalysisUsage & addRequired()
const Module * getModule() const
Return the module owning the function this basic block belongs to, or nullptr it the function does no...
Definition: BasicBlock.cpp:116
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:451
LLVMContext & getContext() const
Get the global data context.
Definition: Module.h:237
A Use represents the edge between a Value definition and its users.
Definition: Use.h:56
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:714
AttributeSet getRetAttributes() const
The attributes for the ret value are returned.
void setName(const Twine &Name)
Change the name of the value.
Definition: Value.cpp:295
Type * getVoidTy()
Fetch the type representing void.
Definition: IRBuilder.h:381
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Definition: IRBuilder.h:1258
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
Definition: IRBuilder.h:1522
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:267
User * getUser() const LLVM_READONLY
Returns the User that contains this Use.
Definition: Use.cpp:41
Class to represent function types.
Definition: DerivedTypes.h:103
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:245
AttributeSet getParamAttributes(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
void setAttributes(AttributeList A)
Set the parameter attributes for this call.
bool isVarArg() const
Definition: DerivedTypes.h:123
Memory SSA
Definition: MemorySSA.cpp:65
An instruction for storing to memory.
Definition: Instructions.h:306
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:439
void takeName(Value *V)
Transfer the name from V to this value.
Definition: Value.cpp:301
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree...
Definition: Dominators.h:142
amdgpu Simplify well known AMD library false Value * Callee
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block...
Definition: IRBuilder.h:128
Class to represent pointers.
Definition: DerivedTypes.h:467
AttributeSet getAttributes(unsigned Index) const
The attributes for the specified index are returned.
const BasicBlock & getEntryBlock() const
Definition: Function.h:618
LoadInst * CreateLoad(Value *Ptr, const char *Name)
Definition: IRBuilder.h:1246
The landingpad instruction holds all of the information necessary to generate correct exception handl...
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
Definition: BasicBlock.cpp:171
Subclasses of this class are all able to terminate a basic block.
Definition: InstrTypes.h:55
const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
Definition: BasicBlock.cpp:200
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
Definition: Instruction.h:282
LLVM Basic Block Representation.
Definition: BasicBlock.h:59
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:46
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:69
void RewriteUseAfterInsertions(Use &U)
Rewrite a use like RewriteUse but handling in-block definitions.
Definition: SSAUpdater.cpp:202
UnreachableInst * CreateUnreachable()
Definition: IRBuilder.h:909
This is an important base class in LLVM.
Definition: Constant.h:42
Resume the propagation of an exception.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:371
size_t size() const
Definition: BasicBlock.h:262
void eraseFromParent()
eraseFromParent - This method unlinks &#39;this&#39; from the containing module and deletes it...
Definition: Globals.cpp:336
ArrayRef< Type * > params() const
Definition: DerivedTypes.h:130
param_iterator param_begin() const
Definition: DerivedTypes.h:128
Represent the analysis usage information of a pass.
static FunctionType * get(Type *Result, ArrayRef< Type *> Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Definition: Type.cpp:297
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:101
Value * CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:1628
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
Definition: SmallPtrSet.h:382
auto remove_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range))
Provide wrappers to std::remove_if which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:854
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function. ...
Definition: Function.cpp:194
static UndefValue * get(Type *T)
Static factory methods - Return an &#39;undef&#39; object of the specified type.
Definition: Constants.cpp:1369
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
Definition: IRBuilder.h:1832
PointerType * getInt8PtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer to an 8-bit integer value.
Definition: IRBuilder.h:386
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:220
std::string & str()
Flushes the stream contents to the target string and returns the string&#39;s reference.
Definition: raw_ostream.h:478
void setCallingConv(CallingConv::ID CC)
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Definition: IRBuilder.h:1735
Iterator for intrusive lists based on ilist_node.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
Definition: SmallPtrSet.h:418
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the generic address space (address sp...
Definition: DerivedTypes.h:482
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:862
bool dominates(const Instruction *Def, const Use &U) const
Return true if Def dominates a use in User.
Definition: Dominators.cpp:243
Type * getReturnType() const
Definition: DerivedTypes.h:124
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Definition: IRBuilder.h:308
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
Definition: Function.h:175
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
Definition: Module.cpp:172
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition: Function.h:145
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Definition: StringMap.h:222
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
Definition: Instruction.cpp:55
static BinaryOperator * Create(BinaryOps Op, Value *S1, Value *S2, const Twine &Name=Twine(), Instruction *InsertBefore=nullptr)
Construct a binary instruction, given the opcode and the two operands.
iterator_range< user_iterator > users()
Definition: Value.h:405
void append(in_iter in_start, in_iter in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:396
static Instruction * CreateMalloc(Instruction *InsertBefore, Type *IntPtrTy, Type *AllocTy, Value *AllocSize, Value *ArraySize=nullptr, Function *MallocF=nullptr, const Twine &Name="")
Generate the IR for a call to malloc:
SwitchInst * CreateSwitch(Value *V, BasicBlock *Dest, unsigned NumCases=10, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a switch instruction with the specified value, default dest, and with a hint for the number of...
Definition: IRBuilder.h:848
use_iterator use_begin()
Definition: Value.h:344
ReturnInst * CreateRetVoid()
Create a &#39;ret void&#39; instruction.
Definition: IRBuilder.h:795
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:176
StringRef getName() const
Return a constant reference to the value&#39;s name.
Definition: Value.cpp:224
const Function * getParent() const
Return the enclosing method, or null if none.
Definition: BasicBlock.h:108
#define I(x, y, z)
Definition: MD5.cpp:58
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:225
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.h:323
void eraseFromParent()
eraseFromParent - This method unlinks &#39;this&#39; from the containing module and deletes it...
Definition: Function.cpp:202
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition: DenseMap.h:141
static std::string createGlobalValueName(const Module &M, const std::string &Propose)
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:1074
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition: Globals.cpp:201
Multiway switch.
INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE, "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp", false, false) ModulePass *llvm
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:462
Module * getParent()
Get the module that this global value is contained inside of...
Definition: GlobalValue.h:565
LLVM Value Representation.
Definition: Value.h:73
static cl::list< std::string > EHWhitelist("emscripten-cxx-exceptions-whitelist", cl::desc("The list of function names in which Emscripten-style " "exception handling is enabled (see emscripten " "EMSCRIPTEN_CATCHING_WHITELIST options)"), cl::CommaSeparated)
BranchInst * CreateBr(BasicBlock *Dest)
Create an unconditional &#39;br label X&#39; instruction.
Definition: IRBuilder.h:819
AttributeSet getFnAttributes() const
The function attributes are returned.
Invoke instruction.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
static Expected< std::string > replace(StringRef S, StringRef From, StringRef To)
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, const Twine &N="", Module *M=nullptr)
Definition: Function.h:136
Legacy analysis pass which computes a DominatorTree.
Definition: Dominators.h:260
const TerminatorInst * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Definition: BasicBlock.cpp:120
Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")
Definition: IRBuilder.h:1840
void RewriteUse(Use &U)
Rewrite a use of the symbolic value.
Definition: SSAUpdater.cpp:185
static std::string getSignature(FunctionType *FTy)
bool use_empty() const
Definition: Value.h:328
iterator end()
Definition: StringMap.h:320
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute >> Attrs)
Create an AttributeList with the specified parameters in it.
Definition: Attributes.cpp:865
const BasicBlock * getParent() const
Definition: Instruction.h:67
CallInst * CreateCall(Value *Callee, ArrayRef< Value *> Args=None, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition: IRBuilder.h:1740