LLVM  15.0.0git
WebAssemblyLowerEmscriptenEHSjLj.cpp
Go to the documentation of this file.
1 //=== WebAssemblyLowerEmscriptenEHSjLj.cpp - Lower exceptions for Emscripten =//
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 /// \file
10 /// This file lowers exception-related instructions and setjmp/longjmp function
11 /// calls to use Emscripten's library functions. The pass uses JavaScript's try
12 /// and catch mechanism in case of Emscripten EH/SjLj and Wasm EH intrinsics in
13 /// case of Emscripten SjLJ.
14 ///
15 /// * Emscripten exception handling
16 /// This pass lowers invokes and landingpads into library functions in JS glue
17 /// code. Invokes are lowered into function wrappers called invoke wrappers that
18 /// exist in JS side, which wraps the original function call with JS try-catch.
19 /// If an exception occurred, cxa_throw() function in JS side sets some
20 /// variables (see below) so we can check whether an exception occurred from
21 /// wasm code and handle it appropriately.
22 ///
23 /// * Emscripten setjmp-longjmp handling
24 /// This pass lowers setjmp to a reasonably-performant approach for emscripten.
25 /// The idea is that each block with a setjmp is broken up into two parts: the
26 /// part containing setjmp and the part right after the setjmp. The latter part
27 /// is either reached from the setjmp, or later from a longjmp. To handle the
28 /// longjmp, all calls that might longjmp are also called using invoke wrappers
29 /// and thus JS / try-catch. JS longjmp() function also sets some variables so
30 /// we can check / whether a longjmp occurred from wasm code. Each block with a
31 /// function call that might longjmp is also split up after the longjmp call.
32 /// After the longjmp call, we check whether a longjmp occurred, and if it did,
33 /// which setjmp it corresponds to, and jump to the right post-setjmp block.
34 /// We assume setjmp-longjmp handling always run after EH handling, which means
35 /// we don't expect any exception-related instructions when SjLj runs.
36 /// FIXME Currently this scheme does not support indirect call of setjmp,
37 /// because of the limitation of the scheme itself. fastcomp does not support it
38 /// either.
39 ///
40 /// In detail, this pass does following things:
41 ///
42 /// 1) Assumes the existence of global variables: __THREW__, __threwValue
43 /// __THREW__ and __threwValue are defined in compiler-rt in Emscripten.
44 /// These variables are used for both exceptions and setjmp/longjmps.
45 /// __THREW__ indicates whether an exception or a longjmp occurred or not. 0
46 /// means nothing occurred, 1 means an exception occurred, and other numbers
47 /// mean a longjmp occurred. In the case of longjmp, __THREW__ variable
48 /// indicates the corresponding setjmp buffer the longjmp corresponds to.
49 /// __threwValue is 0 for exceptions, and the argument to longjmp in case of
50 /// longjmp.
51 ///
52 /// * Emscripten exception handling
53 ///
54 /// 2) We assume the existence of setThrew and setTempRet0/getTempRet0 functions
55 /// at link time. setThrew exists in Emscripten's compiler-rt:
56 ///
57 /// void setThrew(uintptr_t threw, int value) {
58 /// if (__THREW__ == 0) {
59 /// __THREW__ = threw;
60 /// __threwValue = value;
61 /// }
62 /// }
63 //
64 /// setTempRet0 is called from __cxa_find_matching_catch() in JS glue code.
65 /// In exception handling, getTempRet0 indicates the type of an exception
66 /// caught, and in setjmp/longjmp, it means the second argument to longjmp
67 /// function.
68 ///
69 /// 3) Lower
70 /// invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad
71 /// into
72 /// __THREW__ = 0;
73 /// call @__invoke_SIG(func, arg1, arg2)
74 /// %__THREW__.val = __THREW__;
75 /// __THREW__ = 0;
76 /// if (%__THREW__.val == 1)
77 /// goto %lpad
78 /// else
79 /// goto %invoke.cont
80 /// SIG is a mangled string generated based on the LLVM IR-level function
81 /// signature. After LLVM IR types are lowered to the target wasm types,
82 /// the names for these wrappers will change based on wasm types as well,
83 /// as in invoke_vi (function takes an int and returns void). The bodies of
84 /// these wrappers will be generated in JS glue code, and inside those
85 /// wrappers we use JS try-catch to generate actual exception effects. It
86 /// also calls the original callee function. An example wrapper in JS code
87 /// would look like this:
88 /// function invoke_vi(index,a1) {
89 /// try {
90 /// Module["dynCall_vi"](index,a1); // This calls original callee
91 /// } catch(e) {
92 /// if (typeof e !== 'number' && e !== 'longjmp') throw e;
93 /// _setThrew(1, 0); // setThrew is called here
94 /// }
95 /// }
96 /// If an exception is thrown, __THREW__ will be set to true in a wrapper,
97 /// so we can jump to the right BB based on this value.
98 ///
99 /// 4) Lower
100 /// %val = landingpad catch c1 catch c2 catch c3 ...
101 /// ... use %val ...
102 /// into
103 /// %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
104 /// %val = {%fmc, getTempRet0()}
105 /// ... use %val ...
106 /// Here N is a number calculated based on the number of clauses.
107 /// setTempRet0 is called from __cxa_find_matching_catch() in JS glue code.
108 ///
109 /// 5) Lower
110 /// resume {%a, %b}
111 /// into
112 /// call @__resumeException(%a)
113 /// where __resumeException() is a function in JS glue code.
114 ///
115 /// 6) Lower
116 /// call @llvm.eh.typeid.for(type) (intrinsic)
117 /// into
118 /// call @llvm_eh_typeid_for(type)
119 /// llvm_eh_typeid_for function will be generated in JS glue code.
120 ///
121 /// * Emscripten setjmp / longjmp handling
122 ///
123 /// If there are calls to longjmp()
124 ///
125 /// 1) Lower
126 /// longjmp(env, val)
127 /// into
128 /// emscripten_longjmp(env, val)
129 ///
130 /// If there are calls to setjmp()
131 ///
132 /// 2) In the function entry that calls setjmp, initialize setjmpTable and
133 /// sejmpTableSize as follows:
134 /// setjmpTableSize = 4;
135 /// setjmpTable = (int *) malloc(40);
136 /// setjmpTable[0] = 0;
137 /// setjmpTable and setjmpTableSize are used to call saveSetjmp() function in
138 /// Emscripten compiler-rt.
139 ///
140 /// 3) Lower
141 /// setjmp(env)
142 /// into
143 /// setjmpTable = saveSetjmp(env, label, setjmpTable, setjmpTableSize);
144 /// setjmpTableSize = getTempRet0();
145 /// For each dynamic setjmp call, setjmpTable stores its ID (a number which
146 /// is incrementally assigned from 0) and its label (a unique number that
147 /// represents each callsite of setjmp). When we need more entries in
148 /// setjmpTable, it is reallocated in saveSetjmp() in Emscripten's
149 /// compiler-rt and it will return the new table address, and assign the new
150 /// table size in setTempRet0(). saveSetjmp also stores the setjmp's ID into
151 /// the buffer 'env'. A BB with setjmp is split into two after setjmp call in
152 /// order to make the post-setjmp BB the possible destination of longjmp BB.
153 ///
154 /// 4) Lower every call that might longjmp into
155 /// __THREW__ = 0;
156 /// call @__invoke_SIG(func, arg1, arg2)
157 /// %__THREW__.val = __THREW__;
158 /// __THREW__ = 0;
159 /// %__threwValue.val = __threwValue;
160 /// if (%__THREW__.val != 0 & %__threwValue.val != 0) {
161 /// %label = testSetjmp(mem[%__THREW__.val], setjmpTable,
162 /// setjmpTableSize);
163 /// if (%label == 0)
164 /// emscripten_longjmp(%__THREW__.val, %__threwValue.val);
165 /// setTempRet0(%__threwValue.val);
166 /// } else {
167 /// %label = -1;
168 /// }
169 /// longjmp_result = getTempRet0();
170 /// switch %label {
171 /// label 1: goto post-setjmp BB 1
172 /// label 2: goto post-setjmp BB 2
173 /// ...
174 /// default: goto splitted next BB
175 /// }
176 /// testSetjmp examines setjmpTable to see if there is a matching setjmp
177 /// call. After calling an invoke wrapper, if a longjmp occurred, __THREW__
178 /// will be the address of matching jmp_buf buffer and __threwValue be the
179 /// second argument to longjmp. mem[%__THREW__.val] is a setjmp ID that is
180 /// stored in saveSetjmp. testSetjmp returns a setjmp label, a unique ID to
181 /// each setjmp callsite. Label 0 means this longjmp buffer does not
182 /// correspond to one of the setjmp callsites in this function, so in this
183 /// case we just chain the longjmp to the caller. Label -1 means no longjmp
184 /// occurred. Otherwise we jump to the right post-setjmp BB based on the
185 /// label.
186 ///
187 /// * Wasm setjmp / longjmp handling
188 /// This mode still uses some Emscripten library functions but not JavaScript's
189 /// try-catch mechanism. It instead uses Wasm exception handling intrinsics,
190 /// which will be lowered to exception handling instructions.
191 ///
192 /// If there are calls to longjmp()
193 ///
194 /// 1) Lower
195 /// longjmp(env, val)
196 /// into
197 /// __wasm_longjmp(env, val)
198 ///
199 /// If there are calls to setjmp()
200 ///
201 /// 2) and 3): The same as 2) and 3) in Emscripten SjLj.
202 /// (setjmpTable/setjmpTableSize initialization + setjmp callsite
203 /// transformation)
204 ///
205 /// 4) Create a catchpad with a wasm.catch() intrinsic, which returns the value
206 /// thrown by __wasm_longjmp function. In Emscripten library, we have this
207 /// struct:
208 ///
209 /// struct __WasmLongjmpArgs {
210 /// void *env;
211 /// int val;
212 /// };
213 /// struct __WasmLongjmpArgs __wasm_longjmp_args;
214 ///
215 /// The thrown value here is a pointer to __wasm_longjmp_args struct object. We
216 /// use this struct to transfer two values by throwing a single value. Wasm
217 /// throw and catch instructions are capable of throwing and catching multiple
218 /// values, but it also requires multivalue support that is currently not very
219 /// reliable.
220 /// TODO Switch to throwing and catching two values without using the struct
221 ///
222 /// All longjmpable function calls will be converted to an invoke that will
223 /// unwind to this catchpad in case a longjmp occurs. Within the catchpad, we
224 /// test the thrown values using testSetjmp function as we do for Emscripten
225 /// SjLj. The main difference is, in Emscripten SjLj, we need to transform every
226 /// longjmpable callsite into a sequence of code including testSetjmp() call; in
227 /// Wasm SjLj we do the testing in only one place, in this catchpad.
228 ///
229 /// After testing calling testSetjmp(), if the longjmp does not correspond to
230 /// one of the setjmps within the current function, it rethrows the longjmp
231 /// by calling __wasm_longjmp(). If it corresponds to one of setjmps in the
232 /// function, we jump to the beginning of the function, which contains a switch
233 /// to each post-setjmp BB. Again, in Emscripten SjLj, this switch is added for
234 /// every longjmpable callsite; in Wasm SjLj we do this only once at the top of
235 /// the function. (after setjmpTable/setjmpTableSize initialization)
236 ///
237 /// The below is the pseudocode for what we have described
238 ///
239 /// entry:
240 /// Initialize setjmpTable and setjmpTableSize
241 ///
242 /// setjmp.dispatch:
243 /// switch %label {
244 /// label 1: goto post-setjmp BB 1
245 /// label 2: goto post-setjmp BB 2
246 /// ...
247 /// default: goto splitted next BB
248 /// }
249 /// ...
250 ///
251 /// bb:
252 /// invoke void @foo() ;; foo is a longjmpable function
253 /// to label %next unwind label %catch.dispatch.longjmp
254 /// ...
255 ///
256 /// catch.dispatch.longjmp:
257 /// %0 = catchswitch within none [label %catch.longjmp] unwind to caller
258 ///
259 /// catch.longjmp:
260 /// %longjmp.args = wasm.catch() ;; struct __WasmLongjmpArgs
261 /// %env = load 'env' field from __WasmLongjmpArgs
262 /// %val = load 'val' field from __WasmLongjmpArgs
263 /// %label = testSetjmp(mem[%env], setjmpTable, setjmpTableSize);
264 /// if (%label == 0)
265 /// __wasm_longjmp(%env, %val)
266 /// catchret to %setjmp.dispatch
267 ///
268 ///===----------------------------------------------------------------------===//
269 
271 #include "WebAssembly.h"
273 #include "llvm/ADT/StringExtras.h"
277 #include "llvm/IR/Dominators.h"
278 #include "llvm/IR/IRBuilder.h"
279 #include "llvm/IR/IntrinsicsWebAssembly.h"
285 
286 using namespace llvm;
287 
288 #define DEBUG_TYPE "wasm-lower-em-ehsjlj"
289 
291  EHAllowlist("emscripten-cxx-exceptions-allowed",
292  cl::desc("The list of function names in which Emscripten-style "
293  "exception handling is enabled (see emscripten "
294  "EMSCRIPTEN_CATCHING_ALLOWED options)"),
296 
297 namespace {
298 class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
299  bool EnableEmEH; // Enable Emscripten exception handling
300  bool EnableEmSjLj; // Enable Emscripten setjmp/longjmp handling
301  bool EnableWasmSjLj; // Enable Wasm setjmp/longjmp handling
302  bool DoSjLj; // Whether we actually perform setjmp/longjmp handling
303 
304  GlobalVariable *ThrewGV = nullptr; // __THREW__ (Emscripten)
305  GlobalVariable *ThrewValueGV = nullptr; // __threwValue (Emscripten)
306  Function *GetTempRet0F = nullptr; // getTempRet0() (Emscripten)
307  Function *SetTempRet0F = nullptr; // setTempRet0() (Emscripten)
308  Function *ResumeF = nullptr; // __resumeException() (Emscripten)
309  Function *EHTypeIDF = nullptr; // llvm.eh.typeid.for() (intrinsic)
310  Function *EmLongjmpF = nullptr; // emscripten_longjmp() (Emscripten)
311  Function *SaveSetjmpF = nullptr; // saveSetjmp() (Emscripten)
312  Function *TestSetjmpF = nullptr; // testSetjmp() (Emscripten)
313  Function *WasmLongjmpF = nullptr; // __wasm_longjmp() (Emscripten)
314  Function *CatchF = nullptr; // wasm.catch() (intrinsic)
315 
316  // type of 'struct __WasmLongjmpArgs' defined in emscripten
317  Type *LongjmpArgsTy = nullptr;
318 
319  // __cxa_find_matching_catch_N functions.
320  // Indexed by the number of clauses in an original landingpad instruction.
321  DenseMap<int, Function *> FindMatchingCatches;
322  // Map of <function signature string, invoke_ wrappers>
323  StringMap<Function *> InvokeWrappers;
324  // Set of allowed function names for exception handling
325  std::set<std::string> EHAllowlistSet;
326  // Functions that contains calls to setjmp
327  SmallPtrSet<Function *, 8> SetjmpUsers;
328 
329  StringRef getPassName() const override {
330  return "WebAssembly Lower Emscripten Exceptions";
331  }
332 
333  using InstVector = SmallVectorImpl<Instruction *>;
334  bool runEHOnFunction(Function &F);
335  bool runSjLjOnFunction(Function &F);
336  void handleLongjmpableCallsForEmscriptenSjLj(
337  Function &F, InstVector &SetjmpTableInsts,
338  InstVector &SetjmpTableSizeInsts,
339  SmallVectorImpl<PHINode *> &SetjmpRetPHIs);
340  void
341  handleLongjmpableCallsForWasmSjLj(Function &F, InstVector &SetjmpTableInsts,
342  InstVector &SetjmpTableSizeInsts,
343  SmallVectorImpl<PHINode *> &SetjmpRetPHIs);
344  Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
345 
346  Value *wrapInvoke(CallBase *CI);
347  void wrapTestSetjmp(BasicBlock *BB, DebugLoc DL, Value *Threw,
348  Value *SetjmpTable, Value *SetjmpTableSize, Value *&Label,
349  Value *&LongjmpResult, BasicBlock *&CallEmLongjmpBB,
350  PHINode *&CallEmLongjmpBBThrewPHI,
351  PHINode *&CallEmLongjmpBBThrewValuePHI,
352  BasicBlock *&EndBB);
353  Function *getInvokeWrapper(CallBase *CI);
354 
355  bool areAllExceptionsAllowed() const { return EHAllowlistSet.empty(); }
356  bool supportsException(const Function *F) const {
357  return EnableEmEH && (areAllExceptionsAllowed() ||
358  EHAllowlistSet.count(std::string(F->getName())));
359  }
360  void replaceLongjmpWith(Function *LongjmpF, Function *NewF);
361 
362  void rebuildSSA(Function &F);
363 
364 public:
365  static char ID;
366 
367  WebAssemblyLowerEmscriptenEHSjLj()
368  : ModulePass(ID), EnableEmEH(WebAssembly::WasmEnableEmEH),
369  EnableEmSjLj(WebAssembly::WasmEnableEmSjLj),
370  EnableWasmSjLj(WebAssembly::WasmEnableSjLj) {
371  assert(!(EnableEmSjLj && EnableWasmSjLj) &&
372  "Two SjLj modes cannot be turned on at the same time");
373  assert(!(EnableEmEH && EnableWasmSjLj) &&
374  "Wasm SjLj should be only used with Wasm EH");
375  EHAllowlistSet.insert(EHAllowlist.begin(), EHAllowlist.end());
376  }
377  bool runOnModule(Module &M) override;
378 
379  void getAnalysisUsage(AnalysisUsage &AU) const override {
381  }
382 };
383 } // End anonymous namespace
384 
386 INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE,
387  "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
388  false, false)
389 
391  return new WebAssemblyLowerEmscriptenEHSjLj();
392 }
393 
394 static bool canThrow(const Value *V) {
395  if (const auto *F = dyn_cast<const Function>(V)) {
396  // Intrinsics cannot throw
397  if (F->isIntrinsic())
398  return false;
399  StringRef Name = F->getName();
400  // leave setjmp and longjmp (mostly) alone, we process them properly later
401  if (Name == "setjmp" || Name == "longjmp" || Name == "emscripten_longjmp")
402  return false;
403  return !F->doesNotThrow();
404  }
405  // not a function, so an indirect call - can throw, we can't tell
406  return true;
407 }
408 
409 // Get a thread-local global variable with the given name. If it doesn't exist
410 // declare it, which will generate an import and assume that it will exist at
411 // link time.
414  const char *Name) {
415  auto *GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal(Name, Ty));
416  if (!GV)
417  report_fatal_error(Twine("unable to create global: ") + Name);
418 
419  // Variables created by this function are thread local. If the target does not
420  // support TLS, we depend on CoalesceFeaturesAndStripAtomics to downgrade it
421  // to non-thread-local ones, in which case we don't allow this object to be
422  // linked with other objects using shared memory.
423  GV->setThreadLocalMode(GlobalValue::GeneralDynamicTLSModel);
424  return GV;
425 }
426 
427 // Simple function name mangler.
428 // This function simply takes LLVM's string representation of parameter types
429 // and concatenate them with '_'. There are non-alphanumeric characters but llc
430 // is ok with it, and we need to postprocess these names after the lowering
431 // phase anyway.
432 static std::string getSignature(FunctionType *FTy) {
433  std::string Sig;
434  raw_string_ostream OS(Sig);
435  OS << *FTy->getReturnType();
436  for (Type *ParamTy : FTy->params())
437  OS << "_" << *ParamTy;
438  if (FTy->isVarArg())
439  OS << "_...";
440  Sig = OS.str();
441  erase_if(Sig, isSpace);
442  // When s2wasm parses .s file, a comma means the end of an argument. So a
443  // mangled function name can contain any character but a comma.
444  std::replace(Sig.begin(), Sig.end(), ',', '.');
445  return Sig;
446 }
447 
449  Module *M) {
451  // Tell the linker that this function is expected to be imported from the
452  // 'env' module.
453  if (!F->hasFnAttribute("wasm-import-module")) {
454  llvm::AttrBuilder B(M->getContext());
455  B.addAttribute("wasm-import-module", "env");
456  F->addFnAttrs(B);
457  }
458  if (!F->hasFnAttribute("wasm-import-name")) {
459  llvm::AttrBuilder B(M->getContext());
460  B.addAttribute("wasm-import-name", F->getName());
461  F->addFnAttrs(B);
462  }
463  return F;
464 }
465 
466 // Returns an integer type for the target architecture's address space.
467 // i32 for wasm32 and i64 for wasm64.
469  IRBuilder<> IRB(M->getContext());
470  return IRB.getIntNTy(M->getDataLayout().getPointerSizeInBits());
471 }
472 
473 // Returns an integer pointer type for the target architecture's address space.
474 // i32* for wasm32 and i64* for wasm64.
476  return Type::getIntNPtrTy(M->getContext(),
477  M->getDataLayout().getPointerSizeInBits());
478 }
479 
480 // Returns an integer whose type is the integer type for the target's address
481 // space. Returns (i32 C) for wasm32 and (i64 C) for wasm64, when C is the
482 // integer.
484  IRBuilder<> IRB(M->getContext());
485  return IRB.getIntN(M->getDataLayout().getPointerSizeInBits(), C);
486 }
487 
488 // Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
489 // This is because a landingpad instruction contains two more arguments, a
490 // personality function and a cleanup bit, and __cxa_find_matching_catch_N
491 // functions are named after the number of arguments in the original landingpad
492 // instruction.
493 Function *
494 WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
495  unsigned NumClauses) {
496  if (FindMatchingCatches.count(NumClauses))
497  return FindMatchingCatches[NumClauses];
498  PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
499  SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy);
500  FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
502  FTy, "__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
503  FindMatchingCatches[NumClauses] = F;
504  return F;
505 }
506 
507 // Generate invoke wrapper seqence with preamble and postamble
508 // Preamble:
509 // __THREW__ = 0;
510 // Postamble:
511 // %__THREW__.val = __THREW__; __THREW__ = 0;
512 // Returns %__THREW__.val, which indicates whether an exception is thrown (or
513 // whether longjmp occurred), for future use.
514 Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
515  Module *M = CI->getModule();
516  LLVMContext &C = M->getContext();
517 
518  IRBuilder<> IRB(C);
519  IRB.SetInsertPoint(CI);
520 
521  // Pre-invoke
522  // __THREW__ = 0;
523  IRB.CreateStore(getAddrSizeInt(M, 0), ThrewGV);
524 
525  // Invoke function wrapper in JavaScript
527  // Put the pointer to the callee as first argument, so it can be called
528  // within the invoke wrapper later
529  Args.push_back(CI->getCalledOperand());
530  Args.append(CI->arg_begin(), CI->arg_end());
531  CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
532  NewCall->takeName(CI);
534  NewCall->setDebugLoc(CI->getDebugLoc());
535 
536  // Because we added the pointer to the callee as first argument, all
537  // argument attribute indices have to be incremented by one.
538  SmallVector<AttributeSet, 8> ArgAttributes;
539  const AttributeList &InvokeAL = CI->getAttributes();
540 
541  // No attributes for the callee pointer.
542  ArgAttributes.push_back(AttributeSet());
543  // Copy the argument attributes from the original
544  for (unsigned I = 0, E = CI->arg_size(); I < E; ++I)
545  ArgAttributes.push_back(InvokeAL.getParamAttrs(I));
546 
547  AttrBuilder FnAttrs(CI->getContext(), InvokeAL.getFnAttrs());
548  if (FnAttrs.contains(Attribute::AllocSize)) {
549  // The allocsize attribute (if any) referes to parameters by index and needs
550  // to be adjusted.
551  unsigned SizeArg;
552  Optional<unsigned> NEltArg;
553  std::tie(SizeArg, NEltArg) = FnAttrs.getAllocSizeArgs();
554  SizeArg += 1;
555  if (NEltArg)
556  NEltArg = NEltArg.getValue() + 1;
557  FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
558  }
559  // In case the callee has 'noreturn' attribute, We need to remove it, because
560  // we expect invoke wrappers to return.
561  FnAttrs.removeAttribute(Attribute::NoReturn);
562 
563  // Reconstruct the AttributesList based on the vector we constructed.
564  AttributeList NewCallAL = AttributeList::get(
565  C, AttributeSet::get(C, FnAttrs), InvokeAL.getRetAttrs(), ArgAttributes);
566  NewCall->setAttributes(NewCallAL);
567 
568  CI->replaceAllUsesWith(NewCall);
569 
570  // Post-invoke
571  // %__THREW__.val = __THREW__; __THREW__ = 0;
572  Value *Threw =
573  IRB.CreateLoad(getAddrIntType(M), ThrewGV, ThrewGV->getName() + ".val");
574  IRB.CreateStore(getAddrSizeInt(M, 0), ThrewGV);
575  return Threw;
576 }
577 
578 // Get matching invoke wrapper based on callee signature
579 Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallBase *CI) {
580  Module *M = CI->getModule();
582  FunctionType *CalleeFTy = CI->getFunctionType();
583 
584  std::string Sig = getSignature(CalleeFTy);
585  if (InvokeWrappers.find(Sig) != InvokeWrappers.end())
586  return InvokeWrappers[Sig];
587 
588  // Put the pointer to the callee as first argument
589  ArgTys.push_back(PointerType::getUnqual(CalleeFTy));
590  // Add argument types
591  ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end());
592 
593  FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
594  CalleeFTy->isVarArg());
595  Function *F = getEmscriptenFunction(FTy, "__invoke_" + Sig, M);
596  InvokeWrappers[Sig] = F;
597  return F;
598 }
599 
600 static bool canLongjmp(const Value *Callee) {
601  if (auto *CalleeF = dyn_cast<Function>(Callee))
602  if (CalleeF->isIntrinsic())
603  return false;
604 
605  // Attempting to transform inline assembly will result in something like:
606  // call void @__invoke_void(void ()* asm ...)
607  // which is invalid because inline assembly blocks do not have addresses
608  // and can't be passed by pointer. The result is a crash with illegal IR.
609  if (isa<InlineAsm>(Callee))
610  return false;
611  StringRef CalleeName = Callee->getName();
612 
613  // TODO Include more functions or consider checking with mangled prefixes
614 
615  // The reason we include malloc/free here is to exclude the malloc/free
616  // calls generated in setjmp prep / cleanup routines.
617  if (CalleeName == "setjmp" || CalleeName == "malloc" || CalleeName == "free")
618  return false;
619 
620  // There are functions in Emscripten's JS glue code or compiler-rt
621  if (CalleeName == "__resumeException" || CalleeName == "llvm_eh_typeid_for" ||
622  CalleeName == "saveSetjmp" || CalleeName == "testSetjmp" ||
623  CalleeName == "getTempRet0" || CalleeName == "setTempRet0")
624  return false;
625 
626  // __cxa_find_matching_catch_N functions cannot longjmp
627  if (Callee->getName().startswith("__cxa_find_matching_catch_"))
628  return false;
629 
630  // Exception-catching related functions
631  //
632  // We intentionally treat __cxa_end_catch longjmpable in Wasm SjLj even though
633  // it surely cannot longjmp, in order to maintain the unwind relationship from
634  // all existing catchpads (and calls within them) to catch.dispatch.longjmp.
635  //
636  // In Wasm EH + Wasm SjLj, we
637  // 1. Make all catchswitch and cleanuppad that unwind to caller unwind to
638  // catch.dispatch.longjmp instead
639  // 2. Convert all longjmpable calls to invokes that unwind to
640  // catch.dispatch.longjmp
641  // But catchswitch BBs are removed in isel, so if an EH catchswitch (generated
642  // from an exception)'s catchpad does not contain any calls that are converted
643  // into invokes unwinding to catch.dispatch.longjmp, this unwind relationship
644  // (EH catchswitch BB -> catch.dispatch.longjmp BB) is lost and
645  // catch.dispatch.longjmp BB can be placed before the EH catchswitch BB in
646  // CFGSort.
647  // int ret = setjmp(buf);
648  // try {
649  // foo(); // longjmps
650  // } catch (...) {
651  // }
652  // Then in this code, if 'foo' longjmps, it first unwinds to 'catch (...)'
653  // catchswitch, and is not caught by that catchswitch because it is a longjmp,
654  // then it should next unwind to catch.dispatch.longjmp BB. But if this 'catch
655  // (...)' catchswitch -> catch.dispatch.longjmp unwind relationship is lost,
656  // it will not unwind to catch.dispatch.longjmp, producing an incorrect
657  // result.
658  //
659  // Every catchpad generated by Wasm C++ contains __cxa_end_catch, so we
660  // intentionally treat it as longjmpable to work around this problem. This is
661  // a hacky fix but an easy one.
662  //
663  // The comment block in findWasmUnwindDestinations() in
664  // SelectionDAGBuilder.cpp is addressing a similar problem.
665  if (CalleeName == "__cxa_end_catch")
667  if (CalleeName == "__cxa_begin_catch" ||
668  CalleeName == "__cxa_allocate_exception" || CalleeName == "__cxa_throw" ||
669  CalleeName == "__clang_call_terminate")
670  return false;
671 
672  // std::terminate, which is generated when another exception occurs while
673  // handling an exception, cannot longjmp.
674  if (CalleeName == "_ZSt9terminatev")
675  return false;
676 
677  // Otherwise we don't know
678  return true;
679 }
680 
681 static bool isEmAsmCall(const Value *Callee) {
682  StringRef CalleeName = Callee->getName();
683  // This is an exhaustive list from Emscripten's <emscripten/em_asm.h>.
684  return CalleeName == "emscripten_asm_const_int" ||
685  CalleeName == "emscripten_asm_const_double" ||
686  CalleeName == "emscripten_asm_const_int_sync_on_main_thread" ||
687  CalleeName == "emscripten_asm_const_double_sync_on_main_thread" ||
688  CalleeName == "emscripten_asm_const_async_on_main_thread";
689 }
690 
691 // Generate testSetjmp function call seqence with preamble and postamble.
692 // The code this generates is equivalent to the following JavaScript code:
693 // %__threwValue.val = __threwValue;
694 // if (%__THREW__.val != 0 & %__threwValue.val != 0) {
695 // %label = testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
696 // if (%label == 0)
697 // emscripten_longjmp(%__THREW__.val, %__threwValue.val);
698 // setTempRet0(%__threwValue.val);
699 // } else {
700 // %label = -1;
701 // }
702 // %longjmp_result = getTempRet0();
703 //
704 // As output parameters. returns %label, %longjmp_result, and the BB the last
705 // instruction (%longjmp_result = ...) is in.
706 void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
707  BasicBlock *BB, DebugLoc DL, Value *Threw, Value *SetjmpTable,
708  Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult,
709  BasicBlock *&CallEmLongjmpBB, PHINode *&CallEmLongjmpBBThrewPHI,
710  PHINode *&CallEmLongjmpBBThrewValuePHI, BasicBlock *&EndBB) {
711  Function *F = BB->getParent();
712  Module *M = F->getParent();
713  LLVMContext &C = M->getContext();
714  IRBuilder<> IRB(C);
715  IRB.SetCurrentDebugLocation(DL);
716 
717  // if (%__THREW__.val != 0 & %__threwValue.val != 0)
718  IRB.SetInsertPoint(BB);
719  BasicBlock *ThenBB1 = BasicBlock::Create(C, "if.then1", F);
720  BasicBlock *ElseBB1 = BasicBlock::Create(C, "if.else1", F);
721  BasicBlock *EndBB1 = BasicBlock::Create(C, "if.end", F);
722  Value *ThrewCmp = IRB.CreateICmpNE(Threw, getAddrSizeInt(M, 0));
723  Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
724  ThrewValueGV->getName() + ".val");
725  Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
726  Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp, "cmp1");
727  IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
728 
729  // Generate call.em.longjmp BB once and share it within the function
730  if (!CallEmLongjmpBB) {
731  // emscripten_longjmp(%__THREW__.val, %__threwValue.val);
732  CallEmLongjmpBB = BasicBlock::Create(C, "call.em.longjmp", F);
733  IRB.SetInsertPoint(CallEmLongjmpBB);
734  CallEmLongjmpBBThrewPHI = IRB.CreatePHI(getAddrIntType(M), 4, "threw.phi");
735  CallEmLongjmpBBThrewValuePHI =
736  IRB.CreatePHI(IRB.getInt32Ty(), 4, "threwvalue.phi");
737  CallEmLongjmpBBThrewPHI->addIncoming(Threw, ThenBB1);
738  CallEmLongjmpBBThrewValuePHI->addIncoming(ThrewValue, ThenBB1);
739  IRB.CreateCall(EmLongjmpF,
740  {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
741  IRB.CreateUnreachable();
742  } else {
743  CallEmLongjmpBBThrewPHI->addIncoming(Threw, ThenBB1);
744  CallEmLongjmpBBThrewValuePHI->addIncoming(ThrewValue, ThenBB1);
745  }
746 
747  // %label = testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
748  // if (%label == 0)
749  IRB.SetInsertPoint(ThenBB1);
750  BasicBlock *EndBB2 = BasicBlock::Create(C, "if.end2", F);
751  Value *ThrewPtr =
752  IRB.CreateIntToPtr(Threw, getAddrPtrType(M), Threw->getName() + ".p");
753  Value *LoadedThrew = IRB.CreateLoad(getAddrIntType(M), ThrewPtr,
754  ThrewPtr->getName() + ".loaded");
755  Value *ThenLabel = IRB.CreateCall(
756  TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, "label");
757  Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
758  IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
759 
760  // setTempRet0(%__threwValue.val);
761  IRB.SetInsertPoint(EndBB2);
762  IRB.CreateCall(SetTempRet0F, ThrewValue);
763  IRB.CreateBr(EndBB1);
764 
765  IRB.SetInsertPoint(ElseBB1);
766  IRB.CreateBr(EndBB1);
767 
768  // longjmp_result = getTempRet0();
769  IRB.SetInsertPoint(EndBB1);
770  PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label");
771  LabelPHI->addIncoming(ThenLabel, EndBB2);
772 
773  LabelPHI->addIncoming(IRB.getInt32(-1), ElseBB1);
774 
775  // Output parameter assignment
776  Label = LabelPHI;
777  EndBB = EndBB1;
778  LongjmpResult = IRB.CreateCall(GetTempRet0F, None, "longjmp_result");
779 }
780 
781 void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
782  DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
783  DT.recalculate(F); // CFG has been changed
784 
786  for (BasicBlock &BB : F) {
787  for (Instruction &I : BB) {
788  unsigned VarID = SSA.AddVariable(I.getName(), I.getType());
789  // If a value is defined by an invoke instruction, it is only available in
790  // its normal destination and not in its unwind destination.
791  if (auto *II = dyn_cast<InvokeInst>(&I))
792  SSA.AddAvailableValue(VarID, II->getNormalDest(), II);
793  else
794  SSA.AddAvailableValue(VarID, &BB, &I);
795  for (auto &U : I.uses()) {
796  auto *User = cast<Instruction>(U.getUser());
797  if (auto *UserPN = dyn_cast<PHINode>(User))
798  if (UserPN->getIncomingBlock(U) == &BB)
799  continue;
800  if (DT.dominates(&I, User))
801  continue;
802  SSA.AddUse(VarID, &U);
803  }
804  }
805  }
806  SSA.RewriteAllUses(&DT);
807 }
808 
809 // Replace uses of longjmp with a new longjmp function in Emscripten library.
810 // In Emscripten SjLj, the new function is
811 // void emscripten_longjmp(uintptr_t, i32)
812 // In Wasm SjLj, the new function is
813 // void __wasm_longjmp(i8*, i32)
814 // Because the original libc longjmp function takes (jmp_buf*, i32), we need a
815 // ptrtoint/bitcast instruction here to make the type match. jmp_buf* will
816 // eventually be lowered to i32/i64 in the wasm backend.
817 void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(Function *LongjmpF,
818  Function *NewF) {
819  assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
820  Module *M = LongjmpF->getParent();
822  LLVMContext &C = LongjmpF->getParent()->getContext();
823  IRBuilder<> IRB(C);
824 
825  // For calls to longjmp, replace it with emscripten_longjmp/__wasm_longjmp and
826  // cast its first argument (jmp_buf*) appropriately
827  for (User *U : LongjmpF->users()) {
828  auto *CI = dyn_cast<CallInst>(U);
829  if (CI && CI->getCalledFunction() == LongjmpF) {
830  IRB.SetInsertPoint(CI);
831  Value *Env = nullptr;
832  if (NewF == EmLongjmpF)
833  Env =
834  IRB.CreatePtrToInt(CI->getArgOperand(0), getAddrIntType(M), "env");
835  else // WasmLongjmpF
836  Env =
837  IRB.CreateBitCast(CI->getArgOperand(0), IRB.getInt8PtrTy(), "env");
838  IRB.CreateCall(NewF, {Env, CI->getArgOperand(1)});
839  ToErase.push_back(CI);
840  }
841  }
842  for (auto *I : ToErase)
843  I->eraseFromParent();
844 
845  // If we have any remaining uses of longjmp's function pointer, replace it
846  // with (void(*)(jmp_buf*, int))emscripten_longjmp / __wasm_longjmp.
847  if (!LongjmpF->uses().empty()) {
848  Value *NewLongjmp =
849  IRB.CreateBitCast(NewF, LongjmpF->getType(), "longjmp.cast");
850  LongjmpF->replaceAllUsesWith(NewLongjmp);
851  }
852 }
853 
854 static bool containsLongjmpableCalls(const Function *F) {
855  for (const auto &BB : *F)
856  for (const auto &I : BB)
857  if (const auto *CB = dyn_cast<CallBase>(&I))
858  if (canLongjmp(CB->getCalledOperand()))
859  return true;
860  return false;
861 }
862 
863 // When a function contains a setjmp call but not other calls that can longjmp,
864 // we don't do setjmp transformation for that setjmp. But we need to convert the
865 // setjmp calls into "i32 0" so they don't cause link time errors. setjmp always
866 // returns 0 when called directly.
867 static void nullifySetjmp(Function *F) {
868  Module &M = *F->getParent();
869  IRBuilder<> IRB(M.getContext());
870  Function *SetjmpF = M.getFunction("setjmp");
872 
873  for (User *U : make_early_inc_range(SetjmpF->users())) {
874  auto *CB = cast<CallBase>(U);
875  BasicBlock *BB = CB->getParent();
876  if (BB->getParent() != F) // in other function
877  continue;
878  CallInst *CI = nullptr;
879  // setjmp cannot throw. So if it is an invoke, lower it to a call
880  if (auto *II = dyn_cast<InvokeInst>(CB))
881  CI = llvm::changeToCall(II);
882  else
883  CI = cast<CallInst>(CB);
884  ToErase.push_back(CI);
885  CI->replaceAllUsesWith(IRB.getInt32(0));
886  }
887  for (auto *I : ToErase)
888  I->eraseFromParent();
889 }
890 
891 bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
892  LLVM_DEBUG(dbgs() << "********** Lower Emscripten EH & SjLj **********\n");
893 
894  LLVMContext &C = M.getContext();
895  IRBuilder<> IRB(C);
896 
897  Function *SetjmpF = M.getFunction("setjmp");
898  Function *LongjmpF = M.getFunction("longjmp");
899 
900  // In some platforms _setjmp and _longjmp are used instead. Change these to
901  // use setjmp/longjmp instead, because we later detect these functions by
902  // their names.
903  Function *SetjmpF2 = M.getFunction("_setjmp");
904  Function *LongjmpF2 = M.getFunction("_longjmp");
905  if (SetjmpF2) {
906  if (SetjmpF) {
907  if (SetjmpF->getFunctionType() != SetjmpF2->getFunctionType())
908  report_fatal_error("setjmp and _setjmp have different function types");
909  } else {
910  SetjmpF = Function::Create(SetjmpF2->getFunctionType(),
911  GlobalValue::ExternalLinkage, "setjmp", M);
912  }
913  SetjmpF2->replaceAllUsesWith(SetjmpF);
914  }
915  if (LongjmpF2) {
916  if (LongjmpF) {
917  if (LongjmpF->getFunctionType() != LongjmpF2->getFunctionType())
919  "longjmp and _longjmp have different function types");
920  } else {
921  LongjmpF = Function::Create(LongjmpF2->getFunctionType(),
922  GlobalValue::ExternalLinkage, "setjmp", M);
923  }
924  LongjmpF2->replaceAllUsesWith(LongjmpF);
925  }
926 
927  auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
928  assert(TPC && "Expected a TargetPassConfig");
929  auto &TM = TPC->getTM<WebAssemblyTargetMachine>();
930 
931  // Declare (or get) global variables __THREW__, __threwValue, and
932  // getTempRet0/setTempRet0 function which are used in common for both
933  // exception handling and setjmp/longjmp handling
934  ThrewGV = getGlobalVariable(M, getAddrIntType(&M), TM, "__THREW__");
935  ThrewValueGV = getGlobalVariable(M, IRB.getInt32Ty(), TM, "__threwValue");
936  GetTempRet0F = getEmscriptenFunction(
937  FunctionType::get(IRB.getInt32Ty(), false), "getTempRet0", &M);
938  SetTempRet0F = getEmscriptenFunction(
939  FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(), false),
940  "setTempRet0", &M);
941  GetTempRet0F->setDoesNotThrow();
942  SetTempRet0F->setDoesNotThrow();
943 
944  bool Changed = false;
945 
946  // Function registration for exception handling
947  if (EnableEmEH) {
948  // Register __resumeException function
949  FunctionType *ResumeFTy =
950  FunctionType::get(IRB.getVoidTy(), IRB.getInt8PtrTy(), false);
951  ResumeF = getEmscriptenFunction(ResumeFTy, "__resumeException", &M);
952  ResumeF->addFnAttr(Attribute::NoReturn);
953 
954  // Register llvm_eh_typeid_for function
955  FunctionType *EHTypeIDTy =
956  FunctionType::get(IRB.getInt32Ty(), IRB.getInt8PtrTy(), false);
957  EHTypeIDF = getEmscriptenFunction(EHTypeIDTy, "llvm_eh_typeid_for", &M);
958  }
959 
960  // Functions that contains calls to setjmp but don't have other longjmpable
961  // calls within them.
962  SmallPtrSet<Function *, 4> SetjmpUsersToNullify;
963 
964  if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
965  // Precompute setjmp users
966  for (User *U : SetjmpF->users()) {
967  if (auto *CB = dyn_cast<CallBase>(U)) {
968  auto *UserF = CB->getFunction();
969  // If a function that calls setjmp does not contain any other calls that
970  // can longjmp, we don't need to do any transformation on that function,
971  // so can ignore it
972  if (containsLongjmpableCalls(UserF))
973  SetjmpUsers.insert(UserF);
974  else
975  SetjmpUsersToNullify.insert(UserF);
976  } else {
977  std::string S;
979  SS << *U;
980  report_fatal_error(Twine("Indirect use of setjmp is not supported: ") +
981  SS.str());
982  }
983  }
984  }
985 
986  bool SetjmpUsed = SetjmpF && !SetjmpUsers.empty();
987  bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
988  DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
989 
990  // Function registration and data pre-gathering for setjmp/longjmp handling
991  if (DoSjLj) {
992  assert(EnableEmSjLj || EnableWasmSjLj);
993  if (EnableEmSjLj) {
994  // Register emscripten_longjmp function
996  IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()}, false);
997  EmLongjmpF = getEmscriptenFunction(FTy, "emscripten_longjmp", &M);
998  EmLongjmpF->addFnAttr(Attribute::NoReturn);
999  } else { // EnableWasmSjLj
1000  // Register __wasm_longjmp function, which calls __builtin_wasm_longjmp.
1002  IRB.getVoidTy(), {IRB.getInt8PtrTy(), IRB.getInt32Ty()}, false);
1003  WasmLongjmpF = getEmscriptenFunction(FTy, "__wasm_longjmp", &M);
1004  WasmLongjmpF->addFnAttr(Attribute::NoReturn);
1005  }
1006 
1007  if (SetjmpF) {
1008  // Register saveSetjmp function
1009  FunctionType *SetjmpFTy = SetjmpF->getFunctionType();
1010  FunctionType *FTy =
1012  {SetjmpFTy->getParamType(0), IRB.getInt32Ty(),
1013  Type::getInt32PtrTy(C), IRB.getInt32Ty()},
1014  false);
1015  SaveSetjmpF = getEmscriptenFunction(FTy, "saveSetjmp", &M);
1016 
1017  // Register testSetjmp function
1018  FTy = FunctionType::get(
1019  IRB.getInt32Ty(),
1020  {getAddrIntType(&M), Type::getInt32PtrTy(C), IRB.getInt32Ty()},
1021  false);
1022  TestSetjmpF = getEmscriptenFunction(FTy, "testSetjmp", &M);
1023 
1024  // wasm.catch() will be lowered down to wasm 'catch' instruction in
1025  // instruction selection.
1026  CatchF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_catch);
1027  // Type for struct __WasmLongjmpArgs
1028  LongjmpArgsTy = StructType::get(IRB.getInt8PtrTy(), // env
1029  IRB.getInt32Ty() // val
1030  );
1031  }
1032  }
1033 
1034  // Exception handling transformation
1035  if (EnableEmEH) {
1036  for (Function &F : M) {
1037  if (F.isDeclaration())
1038  continue;
1039  Changed |= runEHOnFunction(F);
1040  }
1041  }
1042 
1043  // Setjmp/longjmp handling transformation
1044  if (DoSjLj) {
1045  Changed = true; // We have setjmp or longjmp somewhere
1046  if (LongjmpF)
1047  replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1048  // Only traverse functions that uses setjmp in order not to insert
1049  // unnecessary prep / cleanup code in every function
1050  if (SetjmpF)
1051  for (Function *F : SetjmpUsers)
1052  runSjLjOnFunction(*F);
1053  }
1054 
1055  // Replace unnecessary setjmp calls with 0
1056  if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.empty()) {
1057  Changed = true;
1058  assert(SetjmpF);
1059  for (Function *F : SetjmpUsersToNullify)
1060  nullifySetjmp(F);
1061  }
1062 
1063  // Delete unused global variables and functions
1064  for (auto *V : {ThrewGV, ThrewValueGV})
1065  if (V && V->use_empty())
1066  V->eraseFromParent();
1067  for (auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF,
1068  SaveSetjmpF, TestSetjmpF, WasmLongjmpF, CatchF})
1069  if (V && V->use_empty())
1070  V->eraseFromParent();
1071 
1072  return Changed;
1073 }
1074 
1075 bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
1076  Module &M = *F.getParent();
1077  LLVMContext &C = F.getContext();
1078  IRBuilder<> IRB(C);
1079  bool Changed = false;
1082 
1083  // rethrow.longjmp BB that will be shared within the function.
1084  BasicBlock *RethrowLongjmpBB = nullptr;
1085  // PHI node for the loaded value of __THREW__ global variable in
1086  // rethrow.longjmp BB
1087  PHINode *RethrowLongjmpBBThrewPHI = nullptr;
1088 
1089  for (BasicBlock &BB : F) {
1090  auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
1091  if (!II)
1092  continue;
1093  Changed = true;
1094  LandingPads.insert(II->getLandingPadInst());
1095  IRB.SetInsertPoint(II);
1096 
1097  const Value *Callee = II->getCalledOperand();
1098  bool NeedInvoke = supportsException(&F) && canThrow(Callee);
1099  if (NeedInvoke) {
1100  // Wrap invoke with invoke wrapper and generate preamble/postamble
1101  Value *Threw = wrapInvoke(II);
1102  ToErase.push_back(II);
1103 
1104  // If setjmp/longjmp handling is enabled, the thrown value can be not an
1105  // exception but a longjmp. If the current function contains calls to
1106  // setjmp, it will be appropriately handled in runSjLjOnFunction. But even
1107  // if the function does not contain setjmp calls, we shouldn't silently
1108  // ignore longjmps; we should rethrow them so they can be correctly
1109  // handled in somewhere up the call chain where setjmp is. __THREW__'s
1110  // value is 0 when nothing happened, 1 when an exception is thrown, and
1111  // other values when longjmp is thrown.
1112  //
1113  // if (%__THREW__.val == 0 || %__THREW__.val == 1)
1114  // goto %tail
1115  // else
1116  // goto %longjmp.rethrow
1117  //
1118  // rethrow.longjmp: ;; This is longjmp. Rethrow it
1119  // %__threwValue.val = __threwValue
1120  // emscripten_longjmp(%__THREW__.val, %__threwValue.val);
1121  //
1122  // tail: ;; Nothing happened or an exception is thrown
1123  // ... Continue exception handling ...
1124  if (DoSjLj && EnableEmSjLj && !SetjmpUsers.count(&F) &&
1125  canLongjmp(Callee)) {
1126  // Create longjmp.rethrow BB once and share it within the function
1127  if (!RethrowLongjmpBB) {
1128  RethrowLongjmpBB = BasicBlock::Create(C, "rethrow.longjmp", &F);
1129  IRB.SetInsertPoint(RethrowLongjmpBB);
1130  RethrowLongjmpBBThrewPHI =
1131  IRB.CreatePHI(getAddrIntType(&M), 4, "threw.phi");
1132  RethrowLongjmpBBThrewPHI->addIncoming(Threw, &BB);
1133  Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1134  ThrewValueGV->getName() + ".val");
1135  IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1136  IRB.CreateUnreachable();
1137  } else {
1138  RethrowLongjmpBBThrewPHI->addIncoming(Threw, &BB);
1139  }
1140 
1141  IRB.SetInsertPoint(II); // Restore the insert point back
1142  BasicBlock *Tail = BasicBlock::Create(C, "tail", &F);
1143  Value *CmpEqOne =
1144  IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp.eq.one");
1145  Value *CmpEqZero =
1146  IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 0), "cmp.eq.zero");
1147  Value *Or = IRB.CreateOr(CmpEqZero, CmpEqOne, "or");
1148  IRB.CreateCondBr(Or, Tail, RethrowLongjmpBB);
1149  IRB.SetInsertPoint(Tail);
1150  BB.replaceSuccessorsPhiUsesWith(&BB, Tail);
1151  }
1152 
1153  // Insert a branch based on __THREW__ variable
1154  Value *Cmp = IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp");
1155  IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
1156 
1157  } else {
1158  // This can't throw, and we don't need this invoke, just replace it with a
1159  // call+branch
1160  changeToCall(II);
1161  }
1162  }
1163 
1164  // Process resume instructions
1165  for (BasicBlock &BB : F) {
1166  // Scan the body of the basic block for resumes
1167  for (Instruction &I : BB) {
1168  auto *RI = dyn_cast<ResumeInst>(&I);
1169  if (!RI)
1170  continue;
1171  Changed = true;
1172 
1173  // Split the input into legal values
1174  Value *Input = RI->getValue();
1175  IRB.SetInsertPoint(RI);
1176  Value *Low = IRB.CreateExtractValue(Input, 0, "low");
1177  // Create a call to __resumeException function
1178  IRB.CreateCall(ResumeF, {Low});
1179  // Add a terminator to the block
1180  IRB.CreateUnreachable();
1181  ToErase.push_back(RI);
1182  }
1183  }
1184 
1185  // Process llvm.eh.typeid.for intrinsics
1186  for (BasicBlock &BB : F) {
1187  for (Instruction &I : BB) {
1188  auto *CI = dyn_cast<CallInst>(&I);
1189  if (!CI)
1190  continue;
1191  const Function *Callee = CI->getCalledFunction();
1192  if (!Callee)
1193  continue;
1194  if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1195  continue;
1196  Changed = true;
1197 
1198  IRB.SetInsertPoint(CI);
1199  CallInst *NewCI =
1200  IRB.CreateCall(EHTypeIDF, CI->getArgOperand(0), "typeid");
1201  CI->replaceAllUsesWith(NewCI);
1202  ToErase.push_back(CI);
1203  }
1204  }
1205 
1206  // Look for orphan landingpads, can occur in blocks with no predecessors
1207  for (BasicBlock &BB : F) {
1208  Instruction *I = BB.getFirstNonPHI();
1209  if (auto *LPI = dyn_cast<LandingPadInst>(I))
1210  LandingPads.insert(LPI);
1211  }
1212  Changed |= !LandingPads.empty();
1213 
1214  // Handle all the landingpad for this function together, as multiple invokes
1215  // may share a single lp
1216  for (LandingPadInst *LPI : LandingPads) {
1217  IRB.SetInsertPoint(LPI);
1218  SmallVector<Value *, 16> FMCArgs;
1219  for (unsigned I = 0, E = LPI->getNumClauses(); I < E; ++I) {
1220  Constant *Clause = LPI->getClause(I);
1221  // TODO Handle filters (= exception specifications).
1222  // https://bugs.llvm.org/show_bug.cgi?id=50396
1223  if (LPI->isCatch(I))
1224  FMCArgs.push_back(Clause);
1225  }
1226 
1227  // Create a call to __cxa_find_matching_catch_N function
1228  Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
1229  CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc");
1230  Value *Undef = UndefValue::get(LPI->getType());
1231  Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0");
1232  Value *TempRet0 = IRB.CreateCall(GetTempRet0F, None, "tempret0");
1233  Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
1234 
1235  LPI->replaceAllUsesWith(Pair1);
1236  ToErase.push_back(LPI);
1237  }
1238 
1239  // Erase everything we no longer need in this function
1240  for (Instruction *I : ToErase)
1241  I->eraseFromParent();
1242 
1243  return Changed;
1244 }
1245 
1246 // This tries to get debug info from the instruction before which a new
1247 // instruction will be inserted, and if there's no debug info in that
1248 // instruction, tries to get the info instead from the previous instruction (if
1249 // any). If none of these has debug info and a DISubprogram is provided, it
1250 // creates a dummy debug info with the first line of the function, because IR
1251 // verifier requires all inlinable callsites should have debug info when both a
1252 // caller and callee have DISubprogram. If none of these conditions are met,
1253 // returns empty info.
1254 static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore,
1255  DISubprogram *SP) {
1256  assert(InsertBefore);
1257  if (InsertBefore->getDebugLoc())
1258  return InsertBefore->getDebugLoc();
1259  const Instruction *Prev = InsertBefore->getPrevNode();
1260  if (Prev && Prev->getDebugLoc())
1261  return Prev->getDebugLoc();
1262  if (SP)
1263  return DILocation::get(SP->getContext(), SP->getLine(), 1, SP);
1264  return DebugLoc();
1265 }
1266 
1267 bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
1268  assert(EnableEmSjLj || EnableWasmSjLj);
1269  Module &M = *F.getParent();
1270  LLVMContext &C = F.getContext();
1271  IRBuilder<> IRB(C);
1273  // Vector of %setjmpTable values
1274  SmallVector<Instruction *, 4> SetjmpTableInsts;
1275  // Vector of %setjmpTableSize values
1276  SmallVector<Instruction *, 4> SetjmpTableSizeInsts;
1277 
1278  // Setjmp preparation
1279 
1280  // This instruction effectively means %setjmpTableSize = 4.
1281  // We create this as an instruction intentionally, and we don't want to fold
1282  // this instruction to a constant 4, because this value will be used in
1283  // SSAUpdater.AddAvailableValue(...) later.
1284  BasicBlock *Entry = &F.getEntryBlock();
1285  DebugLoc FirstDL = getOrCreateDebugLoc(&*Entry->begin(), F.getSubprogram());
1286  SplitBlock(Entry, &*Entry->getFirstInsertionPt());
1287 
1288  BinaryOperator *SetjmpTableSize =
1289  BinaryOperator::Create(Instruction::Add, IRB.getInt32(4), IRB.getInt32(0),
1290  "setjmpTableSize", Entry->getTerminator());
1291  SetjmpTableSize->setDebugLoc(FirstDL);
1292  // setjmpTable = (int *) malloc(40);
1293  Instruction *SetjmpTable = CallInst::CreateMalloc(
1294  SetjmpTableSize, IRB.getInt32Ty(), IRB.getInt32Ty(), IRB.getInt32(40),
1295  nullptr, nullptr, "setjmpTable");
1296  SetjmpTable->setDebugLoc(FirstDL);
1297  // CallInst::CreateMalloc may return a bitcast instruction if the result types
1298  // mismatch. We need to set the debug loc for the original call too.
1299  auto *MallocCall = SetjmpTable->stripPointerCasts();
1300  if (auto *MallocCallI = dyn_cast<Instruction>(MallocCall)) {
1301  MallocCallI->setDebugLoc(FirstDL);
1302  }
1303  // setjmpTable[0] = 0;
1304  IRB.SetInsertPoint(SetjmpTableSize);
1305  IRB.CreateStore(IRB.getInt32(0), SetjmpTable);
1306  SetjmpTableInsts.push_back(SetjmpTable);
1307  SetjmpTableSizeInsts.push_back(SetjmpTableSize);
1308 
1309  // Setjmp transformation
1310  SmallVector<PHINode *, 4> SetjmpRetPHIs;
1311  Function *SetjmpF = M.getFunction("setjmp");
1312  for (auto *U : make_early_inc_range(SetjmpF->users())) {
1313  auto *CB = cast<CallBase>(U);
1314  BasicBlock *BB = CB->getParent();
1315  if (BB->getParent() != &F) // in other function
1316  continue;
1317  if (CB->getOperandBundle(LLVMContext::OB_funclet)) {
1318  std::string S;
1320  SS << "In function " + F.getName() +
1321  ": setjmp within a catch clause is not supported in Wasm EH:\n";
1322  SS << *CB;
1324  }
1325 
1326  CallInst *CI = nullptr;
1327  // setjmp cannot throw. So if it is an invoke, lower it to a call
1328  if (auto *II = dyn_cast<InvokeInst>(CB))
1329  CI = llvm::changeToCall(II);
1330  else
1331  CI = cast<CallInst>(CB);
1332 
1333  // The tail is everything right after the call, and will be reached once
1334  // when setjmp is called, and later when longjmp returns to the setjmp
1336  // Add a phi to the tail, which will be the output of setjmp, which
1337  // indicates if this is the first call or a longjmp back. The phi directly
1338  // uses the right value based on where we arrive from
1339  IRB.SetInsertPoint(Tail->getFirstNonPHI());
1340  PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2, "setjmp.ret");
1341 
1342  // setjmp initial call returns 0
1343  SetjmpRet->addIncoming(IRB.getInt32(0), BB);
1344  // The proper output is now this, not the setjmp call itself
1345  CI->replaceAllUsesWith(SetjmpRet);
1346  // longjmp returns to the setjmp will add themselves to this phi
1347  SetjmpRetPHIs.push_back(SetjmpRet);
1348 
1349  // Fix call target
1350  // Our index in the function is our place in the array + 1 to avoid index
1351  // 0, because index 0 means the longjmp is not ours to handle.
1352  IRB.SetInsertPoint(CI);
1353  Value *Args[] = {CI->getArgOperand(0), IRB.getInt32(SetjmpRetPHIs.size()),
1354  SetjmpTable, SetjmpTableSize};
1355  Instruction *NewSetjmpTable =
1356  IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable");
1357  Instruction *NewSetjmpTableSize =
1358  IRB.CreateCall(GetTempRet0F, None, "setjmpTableSize");
1359  SetjmpTableInsts.push_back(NewSetjmpTable);
1360  SetjmpTableSizeInsts.push_back(NewSetjmpTableSize);
1361  ToErase.push_back(CI);
1362  }
1363 
1364  // Handle longjmpable calls.
1365  if (EnableEmSjLj)
1366  handleLongjmpableCallsForEmscriptenSjLj(
1367  F, SetjmpTableInsts, SetjmpTableSizeInsts, SetjmpRetPHIs);
1368  else // EnableWasmSjLj
1369  handleLongjmpableCallsForWasmSjLj(F, SetjmpTableInsts, SetjmpTableSizeInsts,
1370  SetjmpRetPHIs);
1371 
1372  // Erase everything we no longer need in this function
1373  for (Instruction *I : ToErase)
1374  I->eraseFromParent();
1375 
1376  // Free setjmpTable buffer before each return instruction + function-exiting
1377  // call
1378  SmallVector<Instruction *, 16> ExitingInsts;
1379  for (BasicBlock &BB : F) {
1380  Instruction *TI = BB.getTerminator();
1381  if (isa<ReturnInst>(TI))
1382  ExitingInsts.push_back(TI);
1383  // Any 'call' instruction with 'noreturn' attribute exits the function at
1384  // this point. If this throws but unwinds to another EH pad within this
1385  // function instead of exiting, this would have been an 'invoke', which
1386  // happens if we use Wasm EH or Wasm SjLJ.
1387  for (auto &I : BB) {
1388  if (auto *CI = dyn_cast<CallInst>(&I)) {
1389  bool IsNoReturn = CI->hasFnAttr(Attribute::NoReturn);
1390  if (Function *CalleeF = CI->getCalledFunction())
1391  IsNoReturn |= CalleeF->hasFnAttribute(Attribute::NoReturn);
1392  if (IsNoReturn)
1393  ExitingInsts.push_back(&I);
1394  }
1395  }
1396  }
1397  for (auto *I : ExitingInsts) {
1398  DebugLoc DL = getOrCreateDebugLoc(I, F.getSubprogram());
1399  // If this existing instruction is a call within a catchpad, we should add
1400  // it as "funclet" to the operand bundle of 'free' call
1402  if (auto *CB = dyn_cast<CallBase>(I))
1403  if (auto Bundle = CB->getOperandBundle(LLVMContext::OB_funclet))
1404  Bundles.push_back(OperandBundleDef(*Bundle));
1405  auto *Free = CallInst::CreateFree(SetjmpTable, Bundles, I);
1406  Free->setDebugLoc(DL);
1407  // CallInst::CreateFree may create a bitcast instruction if its argument
1408  // types mismatch. We need to set the debug loc for the bitcast too.
1409  if (auto *FreeCallI = dyn_cast<CallInst>(Free)) {
1410  if (auto *BitCastI = dyn_cast<BitCastInst>(FreeCallI->getArgOperand(0)))
1411  BitCastI->setDebugLoc(DL);
1412  }
1413  }
1414 
1415  // Every call to saveSetjmp can change setjmpTable and setjmpTableSize
1416  // (when buffer reallocation occurs)
1417  // entry:
1418  // setjmpTableSize = 4;
1419  // setjmpTable = (int *) malloc(40);
1420  // setjmpTable[0] = 0;
1421  // ...
1422  // somebb:
1423  // setjmpTable = saveSetjmp(env, label, setjmpTable, setjmpTableSize);
1424  // setjmpTableSize = getTempRet0();
1425  // So we need to make sure the SSA for these variables is valid so that every
1426  // saveSetjmp and testSetjmp calls have the correct arguments.
1427  SSAUpdater SetjmpTableSSA;
1428  SSAUpdater SetjmpTableSizeSSA;
1429  SetjmpTableSSA.Initialize(Type::getInt32PtrTy(C), "setjmpTable");
1430  SetjmpTableSizeSSA.Initialize(Type::getInt32Ty(C), "setjmpTableSize");
1431  for (Instruction *I : SetjmpTableInsts)
1432  SetjmpTableSSA.AddAvailableValue(I->getParent(), I);
1433  for (Instruction *I : SetjmpTableSizeInsts)
1434  SetjmpTableSizeSSA.AddAvailableValue(I->getParent(), I);
1435 
1436  for (auto &U : make_early_inc_range(SetjmpTable->uses()))
1437  if (auto *I = dyn_cast<Instruction>(U.getUser()))
1438  if (I->getParent() != Entry)
1439  SetjmpTableSSA.RewriteUse(U);
1440  for (auto &U : make_early_inc_range(SetjmpTableSize->uses()))
1441  if (auto *I = dyn_cast<Instruction>(U.getUser()))
1442  if (I->getParent() != Entry)
1443  SetjmpTableSizeSSA.RewriteUse(U);
1444 
1445  // Finally, our modifications to the cfg can break dominance of SSA variables.
1446  // For example, in this code,
1447  // if (x()) { .. setjmp() .. }
1448  // if (y()) { .. longjmp() .. }
1449  // We must split the longjmp block, and it can jump into the block splitted
1450  // from setjmp one. But that means that when we split the setjmp block, it's
1451  // first part no longer dominates its second part - there is a theoretically
1452  // possible control flow path where x() is false, then y() is true and we
1453  // reach the second part of the setjmp block, without ever reaching the first
1454  // part. So, we rebuild SSA form here.
1455  rebuildSSA(F);
1456  return true;
1457 }
1458 
1459 // Update each call that can longjmp so it can return to the corresponding
1460 // setjmp. Refer to 4) of "Emscripten setjmp/longjmp handling" section in the
1461 // comments at top of the file for details.
1462 void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1463  Function &F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
1464  SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1465  Module &M = *F.getParent();
1466  LLVMContext &C = F.getContext();
1467  IRBuilder<> IRB(C);
1469 
1470  // We need to pass setjmpTable and setjmpTableSize to testSetjmp function.
1471  // These values are defined in the beginning of the function and also in each
1472  // setjmp callsite, but we don't know which values we should use at this
1473  // point. So here we arbitraily use the ones defined in the beginning of the
1474  // function, and SSAUpdater will later update them to the correct values.
1475  Instruction *SetjmpTable = *SetjmpTableInsts.begin();
1476  Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin();
1477 
1478  // call.em.longjmp BB that will be shared within the function.
1479  BasicBlock *CallEmLongjmpBB = nullptr;
1480  // PHI node for the loaded value of __THREW__ global variable in
1481  // call.em.longjmp BB
1482  PHINode *CallEmLongjmpBBThrewPHI = nullptr;
1483  // PHI node for the loaded value of __threwValue global variable in
1484  // call.em.longjmp BB
1485  PHINode *CallEmLongjmpBBThrewValuePHI = nullptr;
1486  // rethrow.exn BB that will be shared within the function.
1487  BasicBlock *RethrowExnBB = nullptr;
1488 
1489  // Because we are creating new BBs while processing and don't want to make
1490  // all these newly created BBs candidates again for longjmp processing, we
1491  // first make the vector of candidate BBs.
1492  std::vector<BasicBlock *> BBs;
1493  for (BasicBlock &BB : F)
1494  BBs.push_back(&BB);
1495 
1496  // BBs.size() will change within the loop, so we query it every time
1497  for (unsigned I = 0; I < BBs.size(); I++) {
1498  BasicBlock *BB = BBs[I];
1499  for (Instruction &I : *BB) {
1500  if (isa<InvokeInst>(&I)) {
1501  std::string S;
1503  SS << "In function " << F.getName()
1504  << ": When using Wasm EH with Emscripten SjLj, there is a "
1505  "restriction that `setjmp` function call and exception cannot be "
1506  "used within the same function:\n";
1507  SS << I;
1509  }
1510  auto *CI = dyn_cast<CallInst>(&I);
1511  if (!CI)
1512  continue;
1513 
1514  const Value *Callee = CI->getCalledOperand();
1515  if (!canLongjmp(Callee))
1516  continue;
1517  if (isEmAsmCall(Callee))
1518  report_fatal_error("Cannot use EM_ASM* alongside setjmp/longjmp in " +
1519  F.getName() +
1520  ". Please consider using EM_JS, or move the "
1521  "EM_ASM into another function.",
1522  false);
1523 
1524  Value *Threw = nullptr;
1525  BasicBlock *Tail;
1526  if (Callee->getName().startswith("__invoke_")) {
1527  // If invoke wrapper has already been generated for this call in
1528  // previous EH phase, search for the load instruction
1529  // %__THREW__.val = __THREW__;
1530  // in postamble after the invoke wrapper call
1531  LoadInst *ThrewLI = nullptr;
1532  StoreInst *ThrewResetSI = nullptr;
1533  for (auto I = std::next(BasicBlock::iterator(CI)), IE = BB->end();
1534  I != IE; ++I) {
1535  if (auto *LI = dyn_cast<LoadInst>(I))
1536  if (auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
1537  if (GV == ThrewGV) {
1538  Threw = ThrewLI = LI;
1539  break;
1540  }
1541  }
1542  // Search for the store instruction after the load above
1543  // __THREW__ = 0;
1544  for (auto I = std::next(BasicBlock::iterator(ThrewLI)), IE = BB->end();
1545  I != IE; ++I) {
1546  if (auto *SI = dyn_cast<StoreInst>(I)) {
1547  if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand())) {
1548  if (GV == ThrewGV &&
1549  SI->getValueOperand() == getAddrSizeInt(&M, 0)) {
1550  ThrewResetSI = SI;
1551  break;
1552  }
1553  }
1554  }
1555  }
1556  assert(Threw && ThrewLI && "Cannot find __THREW__ load after invoke");
1557  assert(ThrewResetSI && "Cannot find __THREW__ store after invoke");
1558  Tail = SplitBlock(BB, ThrewResetSI->getNextNode());
1559 
1560  } else {
1561  // Wrap call with invoke wrapper and generate preamble/postamble
1562  Threw = wrapInvoke(CI);
1563  ToErase.push_back(CI);
1564  Tail = SplitBlock(BB, CI->getNextNode());
1565 
1566  // If exception handling is enabled, the thrown value can be not a
1567  // longjmp but an exception, in which case we shouldn't silently ignore
1568  // exceptions; we should rethrow them.
1569  // __THREW__'s value is 0 when nothing happened, 1 when an exception is
1570  // thrown, other values when longjmp is thrown.
1571  //
1572  // if (%__THREW__.val == 1)
1573  // goto %eh.rethrow
1574  // else
1575  // goto %normal
1576  //
1577  // eh.rethrow: ;; Rethrow exception
1578  // %exn = call @__cxa_find_matching_catch_2() ;; Retrieve thrown ptr
1579  // __resumeException(%exn)
1580  //
1581  // normal:
1582  // <-- Insertion point. Will insert sjlj handling code from here
1583  // goto %tail
1584  //
1585  // tail:
1586  // ...
1587  if (supportsException(&F) && canThrow(Callee)) {
1588  // We will add a new conditional branch. So remove the branch created
1589  // when we split the BB
1590  ToErase.push_back(BB->getTerminator());
1591 
1592  // Generate rethrow.exn BB once and share it within the function
1593  if (!RethrowExnBB) {
1594  RethrowExnBB = BasicBlock::Create(C, "rethrow.exn", &F);
1595  IRB.SetInsertPoint(RethrowExnBB);
1596  CallInst *Exn =
1597  IRB.CreateCall(getFindMatchingCatch(M, 0), {}, "exn");
1598  IRB.CreateCall(ResumeF, {Exn});
1599  IRB.CreateUnreachable();
1600  }
1601 
1602  IRB.SetInsertPoint(CI);
1603  BasicBlock *NormalBB = BasicBlock::Create(C, "normal", &F);
1604  Value *CmpEqOne =
1605  IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp.eq.one");
1606  IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1607 
1608  IRB.SetInsertPoint(NormalBB);
1609  IRB.CreateBr(Tail);
1610  BB = NormalBB; // New insertion point to insert testSetjmp()
1611  }
1612  }
1613 
1614  // We need to replace the terminator in Tail - SplitBlock makes BB go
1615  // straight to Tail, we need to check if a longjmp occurred, and go to the
1616  // right setjmp-tail if so
1617  ToErase.push_back(BB->getTerminator());
1618 
1619  // Generate a function call to testSetjmp function and preamble/postamble
1620  // code to figure out (1) whether longjmp occurred (2) if longjmp
1621  // occurred, which setjmp it corresponds to
1622  Value *Label = nullptr;
1623  Value *LongjmpResult = nullptr;
1624  BasicBlock *EndBB = nullptr;
1625  wrapTestSetjmp(BB, CI->getDebugLoc(), Threw, SetjmpTable, SetjmpTableSize,
1626  Label, LongjmpResult, CallEmLongjmpBB,
1627  CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI,
1628  EndBB);
1629  assert(Label && LongjmpResult && EndBB);
1630 
1631  // Create switch instruction
1632  IRB.SetInsertPoint(EndBB);
1633  IRB.SetCurrentDebugLocation(EndBB->getInstList().back().getDebugLoc());
1634  SwitchInst *SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.size());
1635  // -1 means no longjmp happened, continue normally (will hit the default
1636  // switch case). 0 means a longjmp that is not ours to handle, needs a
1637  // rethrow. Otherwise the index is the same as the index in P+1 (to avoid
1638  // 0).
1639  for (unsigned I = 0; I < SetjmpRetPHIs.size(); I++) {
1640  SI->addCase(IRB.getInt32(I + 1), SetjmpRetPHIs[I]->getParent());
1641  SetjmpRetPHIs[I]->addIncoming(LongjmpResult, EndBB);
1642  }
1643 
1644  // We are splitting the block here, and must continue to find other calls
1645  // in the block - which is now split. so continue to traverse in the Tail
1646  BBs.push_back(Tail);
1647  }
1648  }
1649 
1650  for (Instruction *I : ToErase)
1651  I->eraseFromParent();
1652 }
1653 
1655  for (const User *U : CPI->users())
1656  if (const auto *CRI = dyn_cast<CleanupReturnInst>(U))
1657  return CRI->getUnwindDest();
1658  return nullptr;
1659 }
1660 
1661 // Create a catchpad in which we catch a longjmp's env and val arguments, test
1662 // if the longjmp corresponds to one of setjmps in the current function, and if
1663 // so, jump to the setjmp dispatch BB from which we go to one of post-setjmp
1664 // BBs. Refer to 4) of "Wasm setjmp/longjmp handling" section in the comments at
1665 // top of the file for details.
1666 void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1667  Function &F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
1668  SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1669  Module &M = *F.getParent();
1670  LLVMContext &C = F.getContext();
1671  IRBuilder<> IRB(C);
1672 
1673  // A function with catchswitch/catchpad instruction should have a personality
1674  // function attached to it. Search for the wasm personality function, and if
1675  // it exists, use it, and if it doesn't, create a dummy personality function.
1676  // (SjLj is not going to call it anyway.)
1677  if (!F.hasPersonalityFn()) {
1679  FunctionType *PersType =
1680  FunctionType::get(IRB.getInt32Ty(), /* isVarArg */ true);
1681  Value *PersF = M.getOrInsertFunction(PersName, PersType).getCallee();
1682  F.setPersonalityFn(
1683  cast<Constant>(IRB.CreateBitCast(PersF, IRB.getInt8PtrTy())));
1684  }
1685 
1686  // Use the entry BB's debugloc as a fallback
1687  BasicBlock *Entry = &F.getEntryBlock();
1688  DebugLoc FirstDL = getOrCreateDebugLoc(&*Entry->begin(), F.getSubprogram());
1689  IRB.SetCurrentDebugLocation(FirstDL);
1690 
1691  // Arbitrarily use the ones defined in the beginning of the function.
1692  // SSAUpdater will later update them to the correct values.
1693  Instruction *SetjmpTable = *SetjmpTableInsts.begin();
1694  Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin();
1695 
1696  // Add setjmp.dispatch BB right after the entry block. Because we have
1697  // initialized setjmpTable/setjmpTableSize in the entry block and split the
1698  // rest into another BB, here 'OrigEntry' is the function's original entry
1699  // block before the transformation.
1700  //
1701  // entry:
1702  // setjmpTable / setjmpTableSize initialization
1703  // setjmp.dispatch:
1704  // switch will be inserted here later
1705  // entry.split: (OrigEntry)
1706  // the original function starts here
1707  BasicBlock *OrigEntry = Entry->getNextNode();
1708  BasicBlock *SetjmpDispatchBB =
1709  BasicBlock::Create(C, "setjmp.dispatch", &F, OrigEntry);
1710  cast<BranchInst>(Entry->getTerminator())->setSuccessor(0, SetjmpDispatchBB);
1711 
1712  // Create catch.dispatch.longjmp BB and a catchswitch instruction
1713  BasicBlock *CatchDispatchLongjmpBB =
1714  BasicBlock::Create(C, "catch.dispatch.longjmp", &F);
1715  IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1716  CatchSwitchInst *CatchSwitchLongjmp =
1717  IRB.CreateCatchSwitch(ConstantTokenNone::get(C), nullptr, 1);
1718 
1719  // Create catch.longjmp BB and a catchpad instruction
1720  BasicBlock *CatchLongjmpBB = BasicBlock::Create(C, "catch.longjmp", &F);
1721  CatchSwitchLongjmp->addHandler(CatchLongjmpBB);
1722  IRB.SetInsertPoint(CatchLongjmpBB);
1723  CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1724 
1725  // Wasm throw and catch instructions can throw and catch multiple values, but
1726  // that requires multivalue support in the toolchain, which is currently not
1727  // very reliable. We instead throw and catch a pointer to a struct value of
1728  // type 'struct __WasmLongjmpArgs', which is defined in Emscripten.
1729  Instruction *CatchCI =
1730  IRB.CreateCall(CatchF, {IRB.getInt32(WebAssembly::C_LONGJMP)}, "thrown");
1731  Value *LongjmpArgs =
1732  IRB.CreateBitCast(CatchCI, LongjmpArgsTy->getPointerTo(), "longjmp.args");
1733  Value *EnvField =
1734  IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0, "env_gep");
1735  Value *ValField =
1736  IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1, "val_gep");
1737  // void *env = __wasm_longjmp_args.env;
1738  Instruction *Env = IRB.CreateLoad(IRB.getInt8PtrTy(), EnvField, "env");
1739  // int val = __wasm_longjmp_args.val;
1740  Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField, "val");
1741 
1742  // %label = testSetjmp(mem[%env], setjmpTable, setjmpTableSize);
1743  // if (%label == 0)
1744  // __wasm_longjmp(%env, %val)
1745  // catchret to %setjmp.dispatch
1746  BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", &F);
1747  BasicBlock *EndBB = BasicBlock::Create(C, "if.end", &F);
1748  Value *EnvP = IRB.CreateBitCast(Env, getAddrPtrType(&M), "env.p");
1749  Value *SetjmpID = IRB.CreateLoad(getAddrIntType(&M), EnvP, "setjmp.id");
1750  Value *Label =
1751  IRB.CreateCall(TestSetjmpF, {SetjmpID, SetjmpTable, SetjmpTableSize},
1752  OperandBundleDef("funclet", CatchPad), "label");
1753  Value *Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1754  IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1755 
1756  IRB.SetInsertPoint(ThenBB);
1757  CallInst *WasmLongjmpCI = IRB.CreateCall(
1758  WasmLongjmpF, {Env, Val}, OperandBundleDef("funclet", CatchPad));
1759  IRB.CreateUnreachable();
1760 
1761  IRB.SetInsertPoint(EndBB);
1762  // Jump to setjmp.dispatch block
1763  IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1764 
1765  // Go back to setjmp.dispatch BB
1766  // setjmp.dispatch:
1767  // switch %label {
1768  // label 1: goto post-setjmp BB 1
1769  // label 2: goto post-setjmp BB 2
1770  // ...
1771  // default: goto splitted next BB
1772  // }
1773  IRB.SetInsertPoint(SetjmpDispatchBB);
1774  PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label.phi");
1775  LabelPHI->addIncoming(Label, EndBB);
1776  LabelPHI->addIncoming(IRB.getInt32(-1), Entry);
1777  SwitchInst *SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.size());
1778  // -1 means no longjmp happened, continue normally (will hit the default
1779  // switch case). 0 means a longjmp that is not ours to handle, needs a
1780  // rethrow. Otherwise the index is the same as the index in P+1 (to avoid
1781  // 0).
1782  for (unsigned I = 0; I < SetjmpRetPHIs.size(); I++) {
1783  SI->addCase(IRB.getInt32(I + 1), SetjmpRetPHIs[I]->getParent());
1784  SetjmpRetPHIs[I]->addIncoming(Val, SetjmpDispatchBB);
1785  }
1786 
1787  // Convert all longjmpable call instructions to invokes that unwind to the
1788  // newly created catch.dispatch.longjmp BB.
1789  SmallVector<CallInst *, 64> LongjmpableCalls;
1790  for (auto *BB = &*F.begin(); BB; BB = BB->getNextNode()) {
1791  for (auto &I : *BB) {
1792  auto *CI = dyn_cast<CallInst>(&I);
1793  if (!CI)
1794  continue;
1795  const Value *Callee = CI->getCalledOperand();
1796  if (!canLongjmp(Callee))
1797  continue;
1798  if (isEmAsmCall(Callee))
1799  report_fatal_error("Cannot use EM_ASM* alongside setjmp/longjmp in " +
1800  F.getName() +
1801  ". Please consider using EM_JS, or move the "
1802  "EM_ASM into another function.",
1803  false);
1804  // This is __wasm_longjmp() call we inserted in this function, which
1805  // rethrows the longjmp when the longjmp does not correspond to one of
1806  // setjmps in this function. We should not convert this call to an invoke.
1807  if (CI == WasmLongjmpCI)
1808  continue;
1809  LongjmpableCalls.push_back(CI);
1810  }
1811  }
1812 
1813  for (auto *CI : LongjmpableCalls) {
1814  // Even if the callee function has attribute 'nounwind', which is true for
1815  // all C functions, it can longjmp, which means it can throw a Wasm
1816  // exception now.
1817  CI->removeFnAttr(Attribute::NoUnwind);
1818  if (Function *CalleeF = CI->getCalledFunction())
1819  CalleeF->removeFnAttr(Attribute::NoUnwind);
1820 
1821  // Change it to an invoke and make it unwind to the catch.dispatch.longjmp
1822  // BB. If the call is enclosed in another catchpad/cleanuppad scope, unwind
1823  // to its parent pad's unwind destination instead to preserve the scope
1824  // structure. It will eventually unwind to the catch.dispatch.longjmp.
1826  BasicBlock *UnwindDest = nullptr;
1827  if (auto Bundle = CI->getOperandBundle(LLVMContext::OB_funclet)) {
1828  Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
1829  while (!UnwindDest) {
1830  if (auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
1831  UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1832  break;
1833  }
1834  if (auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
1835  // getCleanupRetUnwindDest() can return nullptr when
1836  // 1. This cleanuppad's matching cleanupret uwninds to caller
1837  // 2. There is no matching cleanupret because it ends with
1838  // unreachable.
1839  // In case of 2, we need to traverse the parent pad chain.
1840  UnwindDest = getCleanupRetUnwindDest(CPI);
1841  Value *ParentPad = CPI->getParentPad();
1842  if (isa<ConstantTokenNone>(ParentPad))
1843  break;
1844  FromPad = cast<Instruction>(ParentPad);
1845  }
1846  }
1847  }
1848  if (!UnwindDest)
1849  UnwindDest = CatchDispatchLongjmpBB;
1850  changeToInvokeAndSplitBasicBlock(CI, UnwindDest);
1851  }
1852 
1854  for (auto &BB : F) {
1855  if (auto *CSI = dyn_cast<CatchSwitchInst>(BB.getFirstNonPHI())) {
1856  if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1857  IRB.SetInsertPoint(CSI);
1858  ToErase.push_back(CSI);
1859  auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1860  CatchDispatchLongjmpBB, 1);
1861  NewCSI->addHandler(*CSI->handler_begin());
1862  NewCSI->takeName(CSI);
1863  CSI->replaceAllUsesWith(NewCSI);
1864  }
1865  }
1866 
1867  if (auto *CRI = dyn_cast<CleanupReturnInst>(BB.getTerminator())) {
1868  if (CRI->unwindsToCaller()) {
1869  IRB.SetInsertPoint(CRI);
1870  ToErase.push_back(CRI);
1871  IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1872  }
1873  }
1874  }
1875 
1876  for (Instruction *I : ToErase)
1877  I->eraseFromParent();
1878 }
getGlobalVariable
static GlobalVariable * getGlobalVariable(Module &M, Type *Ty, WebAssemblyTargetMachine &TM, const char *Name)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:412
llvm::SSAUpdater::Initialize
void Initialize(Type *Ty, StringRef Name)
Reset this object to get ready for a new set of SSA updates with type 'Ty'.
Definition: SSAUpdater.cpp:52
llvm::SPIRV::StorageClass::Input
@ Input
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
WebAssembly.h
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::Instruction::getModule
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
Definition: Instruction.cpp:65
llvm::CallingConv::WASM_EmscriptenInvoke
@ WASM_EmscriptenInvoke
Calling convention for emscripten __invoke_* functions.
Definition: CallingConv.h:247
llvm::CallBase::getOperandBundle
Optional< OperandBundleUse > getOperandBundle(StringRef Name) const
Return an operand bundle by name, if present.
Definition: InstrTypes.h:2027
llvm::RecurKind::Or
@ Or
Bitwise or logical OR of integers.
canLongjmp
static bool canLongjmp(const Value *Callee)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:600
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:1418
llvm::Type::getInt8PtrTy
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:291
llvm::BasicBlock::iterator
InstListType::iterator iterator
Instruction iterators...
Definition: BasicBlock.h:87
llvm::ModulePass
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:248
DebugInfoMetadata.h
llvm::CallBase::removeFnAttr
void removeFnAttr(Attribute::AttrKind Kind)
Removes the attribute from the function.
Definition: InstrTypes.h:1553
llvm::Function
Definition: Function.h:60
INITIALIZE_PASS
INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLj, DEBUG_TYPE, "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp", false, false) ModulePass *llvm
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:386
llvm::raw_string_ostream
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:632
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
getSignature
static std::string getSignature(FunctionType *FTy)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:432
llvm::LandingPadInst
The landingpad instruction holds all of the information necessary to generate correct exception handl...
Definition: Instructions.h:2903
llvm::CallInst::CreateMalloc
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:
Definition: Instructions.cpp:750
llvm::WebAssembly::C_LONGJMP
@ C_LONGJMP
Definition: WasmEHFuncInfo.h:27
llvm::cl::CommaSeparated
@ CommaSeparated
Definition: CommandLine.h:165
llvm::IRBuilder<>
llvm::GlobalVariable
Definition: GlobalVariable.h:39
llvm::erase_if
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
Definition: STLExtras.h:1807
llvm::FunctionType::get
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Definition: Type.cpp:361
Local.h
llvm::AttributeList::get
static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute >> Attrs)
Create an AttributeList with the specified parameters in it.
Definition: Attributes.cpp:1050
llvm::DominatorTree
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition: Dominators.h:166
llvm::CallBase::hasFnAttr
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
Definition: InstrTypes.h:1483
llvm::Function::setDoesNotThrow
void setDoesNotThrow()
Definition: Function.h:558
llvm::StringMap::end
iterator end()
Definition: StringMap.h:205
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
llvm::AttributeList
Definition: Attributes.h:425
llvm::CallBase::getAttributes
AttributeList getAttributes() const
Return the parameter attributes for this call.
Definition: InstrTypes.h:1474
llvm::CallBase::getFunctionType
FunctionType * getFunctionType() const
Definition: InstrTypes.h:1254
llvm::AttributeList::getFnAttrs
AttributeSet getFnAttrs() const
The function attributes are returned.
Definition: Attributes.cpp:1388
llvm::Optional< unsigned >
llvm::DenseMapBase< DenseMap< KeyT, ValueT, DenseMapInfo< KeyT >, llvm::detail::DenseMapPair< KeyT, ValueT > >, KeyT, ValueT, DenseMapInfo< KeyT >, llvm::detail::DenseMapPair< KeyT, ValueT > >::count
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:147
llvm::IRBuilderBase::getIntN
ConstantInt * getIntN(unsigned N, uint64_t C)
Get a constant N-bit value, zero extended or truncated from a 64-bit value.
Definition: IRBuilder.h:472
llvm::SmallPtrSet
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:450
isEmAsmCall
static bool isEmAsmCall(const Value *Callee)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:681
WebAssemblyTargetMachine.h
llvm::changeToCall
CallInst * changeToCall(InvokeInst *II, DomTreeUpdater *DTU=nullptr)
This function converts the specified invoek into a normall call.
Definition: Local.cpp:2187
llvm::CallBase::arg_begin
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
Definition: InstrTypes.h:1316
llvm::StringMap::find
iterator find(StringRef Key)
Definition: StringMap.h:218
replace
static void replace(Module &M, GlobalVariable *Old, GlobalVariable *New)
Definition: ConstantMerge.cpp:116
llvm::Type::getInt32PtrTy
static PointerType * getInt32PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:299
llvm::Type::getInt32Ty
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:239
llvm::CatchSwitchInst::addHandler
void addHandler(BasicBlock *Dest)
Add an entry to the switch instruction...
Definition: Instructions.cpp:1194
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
llvm::MDNode::get
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition: Metadata.h:1384
llvm::codeview::ProcSymFlags::IsNoReturn
@ IsNoReturn
F
#define F(x, y, z)
Definition: MD5.cpp:55
llvm::FunctionType::isVarArg
bool isVarArg() const
Definition: DerivedTypes.h:123
llvm::BasicBlock
LLVM Basic Block Representation.
Definition: BasicBlock.h:55
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::DominatorTree::dominates
bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
Definition: Dominators.cpp:122
CommandLine.h
SSAUpdaterBulk.h
llvm::CallingConv::Tail
@ Tail
Tail - This calling convention attemps to make calls as fast as possible while guaranteeing that tail...
Definition: CallingConv.h:81
getCleanupRetUnwindDest
static BasicBlock * getCleanupRetUnwindDest(const CleanupPadInst *CPI)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:1654
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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
containsLongjmpableCalls
static bool containsLongjmpableCalls(const Function *F)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:854
llvm::WebAssemblyTargetMachine
Definition: WebAssemblyTargetMachine.h:23
getOrCreateDebugLoc
static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore, DISubprogram *SP)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:1254
C
(vector float) vec_cmpeq(*A, *B) C
Definition: README_ALTIVEC.txt:86
llvm::FunctionType::param_end
param_iterator param_end() const
Definition: DerivedTypes.h:129
llvm::CallBase::getCalledFunction
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
Definition: InstrTypes.h:1396
llvm::CallBase::setAttributes
void setAttributes(AttributeList A)
Set the parameter attributes for this call.
Definition: InstrTypes.h:1478
llvm::SSAUpdaterBulk
Helper class for SSA formation on a set of values defined in multiple blocks.
Definition: SSAUpdaterBulk.h:39
llvm::IRBuilderBase::getIntNTy
IntegerType * getIntNTy(unsigned N)
Fetch the type representing an N-bit integer.
Definition: IRBuilder.h:514
canThrow
static bool canThrow(const Value *V)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:394
llvm::AnalysisUsage
Represent the analysis usage information of a pass.
Definition: PassAnalysisSupport.h:47
llvm::WebAssembly::WasmEnableEmSjLj
cl::opt< bool > WasmEnableEmSjLj
llvm::Value::uses
iterator_range< use_iterator > uses()
Definition: Value.h:376
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
llvm::FunctionType::param_begin
param_iterator param_begin() const
Definition: DerivedTypes.h:128
llvm::Instruction
Definition: Instruction.h:42
llvm::DominatorTreeWrapperPass
Legacy analysis pass which computes a DominatorTree.
Definition: Dominators.h:302
getAddrSizeInt
static Value * getAddrSizeInt(Module *M, uint64_t C)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:483
llvm::report_fatal_error
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:143
EHAllowlist
static cl::list< std::string > EHAllowlist("emscripten-cxx-exceptions-allowed", cl::desc("The list of function names in which Emscripten-style " "exception handling is enabled (see emscripten " "EMSCRIPTEN_CATCHING_ALLOWED options)"), cl::CommaSeparated)
llvm::UndefValue::get
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Definition: Constants.cpp:1777
llvm::ThreadPriority::Low
@ Low
Lower the current thread's priority such that it does not affect foreground tasks significantly.
llvm::FunctionType::params
ArrayRef< Type * > params() const
Definition: DerivedTypes.h:130
llvm::createWebAssemblyLowerEmscriptenEHSjLj
ModulePass * createWebAssemblyLowerEmscriptenEHSjLj()
llvm::OperandBundleDef
OperandBundleDefT< Value * > OperandBundleDef
Definition: AutoUpgrade.h:33
DEBUG_TYPE
#define DEBUG_TYPE
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:288
llvm::None
const NoneType None
Definition: None.h:24
llvm::EHPersonality::Wasm_CXX
@ Wasm_CXX
llvm::Value::use_empty
bool use_empty() const
Definition: Value.h:344
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
WebAssemblyUtilities.h
llvm::StringMap
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:110
llvm::ARM_PROC::IE
@ IE
Definition: ARMBaseInfo.h:27
llvm::Type::getIntNPtrTy
static PointerType * getIntNPtrTy(LLVMContext &C, unsigned N, unsigned AS=0)
Definition: Type.cpp:283
llvm::X86AS::SS
@ SS
Definition: X86.h:193
llvm::LLVMContext::OB_funclet
@ OB_funclet
Definition: LLVMContext.h:91
llvm::AllocFnKind::Free
@ Free
llvm::Clause
Definition: DirectiveEmitter.h:123
SSA
Memory SSA
Definition: MemorySSA.cpp:73
llvm::CleanupPadInst
Definition: Instructions.h:4446
llvm::StoreInst
An instruction for storing to memory.
Definition: Instructions.h:297
llvm::AttributeList::getRetAttrs
AttributeSet getRetAttrs() const
The attributes for the ret value are returned.
Definition: Attributes.cpp:1384
llvm::Constant
This is an important base class in LLVM.
Definition: Constant.h:41
llvm::PointerType::getUnqual
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
Definition: DerivedTypes.h:651
uint64_t
llvm::GlobalValue::getParent
Module * getParent()
Get the module that this global value is contained inside of...
Definition: GlobalValue.h:620
llvm::GlobalValue::GeneralDynamicTLSModel
@ GeneralDynamicTLSModel
Definition: GlobalValue.h:185
llvm::AttributeSet::get
static AttributeSet get(LLVMContext &C, const AttrBuilder &B)
Definition: Attributes.cpp:623
llvm::IRBuilderBase::getInt32
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Definition: IRBuilder.h:461
llvm::PHINode::addIncoming
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
Definition: Instructions.h:2801
llvm::LLVMContext
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:68
llvm::DenseMap
Definition: DenseMap.h:716
I
#define I(x, y, z)
Definition: MD5.cpp:58
llvm::AttrBuilder
Definition: Attributes.h:1024
llvm::FunctionType::getParamType
Type * getParamType(unsigned i) const
Parameter type accessors.
Definition: DerivedTypes.h:135
StringExtras.h
llvm::make_early_inc_range
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition: STLExtras.h:618
llvm::PointerType
Class to represent pointers.
Definition: DerivedTypes.h:632
llvm::Instruction::setDebugLoc
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
Definition: Instruction.h:364
llvm::WebAssembly::WasmEnableSjLj
cl::opt< bool > WasmEnableSjLj
TargetPassConfig.h
llvm::Function::Create
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition: Function.h:137
llvm::ilist_node_with_parent::getPrevNode
NodeTy * getPrevNode()
Definition: ilist_node.h:275
IRBuilder.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::Optional::getValue
constexpr const T & getValue() const &
Definition: Optional.h:306
SI
StandardInstrumentations SI(Debug, VerifyEach)
getAddrPtrType
static Type * getAddrPtrType(Module *M)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:475
getAddrIntType
static Type * getAddrIntType(Module *M)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:468
llvm::getEHPersonalityName
StringRef getEHPersonalityName(EHPersonality Pers)
Definition: EHPersonalities.cpp:47
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
llvm::changeToInvokeAndSplitBasicBlock
BasicBlock * changeToInvokeAndSplitBasicBlock(CallInst *CI, BasicBlock *UnwindEdge, DomTreeUpdater *DTU=nullptr)
Convert the CallInst to InvokeInst with the specified unwind edge basic block.
Definition: Local.cpp:2207
llvm::CallBase::arg_end
User::op_iterator arg_end()
Return the iterator pointing to the end of the argument list.
Definition: InstrTypes.h:1322
llvm::SmallPtrSetImpl::count
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
Definition: SmallPtrSet.h:383
llvm::DominatorTreeBase::recalculate
void recalculate(ParentType &Func)
recalculate - compute a dominator tree for the given function
Definition: GenericDomTree.h:778
nullifySetjmp
static void nullifySetjmp(Function *F)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:867
llvm::BinaryOperator
Definition: InstrTypes.h:188
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::BasicBlock::Create
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:97
llvm::Value::getContext
LLVMContext & getContext() const
All values hold a context through their type.
Definition: Value.cpp:991
DL
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Definition: AArch64SLSHardening.cpp:76
S
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
Definition: README.txt:210
SSAUpdater.h
llvm::Value::getName
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:305
llvm::LoadInst
An instruction for reading from memory.
Definition: Instructions.h:173
llvm::Value::stripPointerCasts
const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition: Value.cpp:682
Callee
amdgpu Simplify well known AMD library false FunctionCallee Callee
Definition: AMDGPULibCalls.cpp:186
llvm::MDNode::getContext
LLVMContext & getContext() const
Definition: Metadata.h:1094
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
llvm::pdb::PDB_SymType::Label
@ Label
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:50
llvm::X86::FirstMacroFusionInstKind::Cmp
@ Cmp
WasmEHFuncInfo.h
llvm::CallBase::arg_size
unsigned arg_size() const
Definition: InstrTypes.h:1339
llvm::ConstantTokenNone::get
static ConstantTokenNone * get(LLVMContext &Context)
Return the ConstantTokenNone.
Definition: Constants.cpp:1470
llvm::Module::getContext
LLVMContext & getContext() const
Get the global data context.
Definition: Module.h:262
llvm::Type::getPointerTo
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
Definition: Type.cpp:774
llvm::CallInst::CreateFree
static Instruction * CreateFree(Value *Source, Instruction *InsertBefore)
Generate the IR for a call to the builtin free function.
Definition: Instructions.cpp:827
llvm::Function::getFunctionType
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition: Function.h:175
llvm::MCID::Add
@ Add
Definition: MCInstrDesc.h:185
llvm::CallBase::getCalledOperand
Value * getCalledOperand() const
Definition: InstrTypes.h:1389
llvm::GlobalValue::ExternalLinkage
@ ExternalLinkage
Externally visible function.
Definition: GlobalValue.h:48
llvm::CatchPadInst
Definition: Instructions.h:4487
llvm::BasicBlock::getInstList
const InstListType & getInstList() const
Return the underlying instruction list container.
Definition: BasicBlock.h:364
llvm::AttributeSet
Definition: Attributes.h:290
llvm::Instruction::getDebugLoc
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
Definition: Instruction.h:367
Dominators.h
llvm::CallBase::getArgOperand
Value * getArgOperand(unsigned i) const
Definition: InstrTypes.h:1341
llvm::SmallPtrSetImplBase::empty
LLVM_NODISCARD bool empty() const
Definition: SmallPtrSet.h:92
llvm::SSAUpdater::RewriteUse
void RewriteUse(Use &U)
Rewrite a use of the symbolic value.
Definition: SSAUpdater.cpp:186
llvm::Function::addFnAttr
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
Definition: Function.cpp:535
llvm::PHINode
Definition: Instructions.h:2651
llvm::DISubprogram
Subprogram description.
Definition: DebugInfoMetadata.h:1803
llvm::SmallVectorImpl< Instruction * >
llvm::CallBase
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Definition: InstrTypes.h:1174
llvm::GlobalValue::getType
PointerType * getType() const
Global values are always pointers.
Definition: GlobalValue.h:276
TM
const char LLVMTargetMachineRef TM
Definition: PassBuilderBindings.cpp:47
llvm::CallInst
This class represents a function call, abstracting a target machine's calling convention.
Definition: Instructions.h:1461
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
llvm::AnalysisUsage::addRequired
AnalysisUsage & addRequired()
Definition: PassAnalysisSupport.h:75
llvm::SwitchInst
Multiway switch.
Definition: Instructions.h:3230
llvm::Value::takeName
void takeName(Value *V)
Transfer the name from V to this value.
Definition: Value.cpp:378
llvm::DebugLoc
A debug info location.
Definition: DebugLoc.h:33
llvm::AMDGPU::HSAMD::Kernel::Key::Args
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Definition: AMDGPUMetadata.h:394
llvm::SSAUpdater::AddAvailableValue
void AddAvailableValue(BasicBlock *BB, Value *V)
Indicate that a rewritten value is available in the specified block with the specified value.
Definition: SSAUpdater.cpp:69
llvm::cl::desc
Definition: CommandLine.h:405
getEmscriptenFunction
static Function * getEmscriptenFunction(FunctionType *Ty, const Twine &Name, Module *M)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:448
llvm::SSAUpdater
Helper class for SSA formation on a set of values defined in multiple blocks.
Definition: SSAUpdater.h:38
llvm::AttributeList::getParamAttrs
AttributeSet getParamAttrs(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
Definition: Attributes.cpp:1380
llvm::BinaryOperator::Create
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.
Definition: Instructions.cpp:2778
BasicBlockUtils.h
llvm::SplitBlock
BasicBlock * SplitBlock(BasicBlock *Old, Instruction *SplitPt, DominatorTree *DT, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="", bool Before=false)
Split the specified block at the specified instruction.
Definition: BasicBlockUtils.cpp:837
llvm::CatchSwitchInst
Definition: Instructions.h:4268
llvm::raw_string_ostream::str
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:650
llvm::FunctionType::getReturnType
Type * getReturnType() const
Definition: DerivedTypes.h:124
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::Value::users
iterator_range< user_iterator > users()
Definition: Value.h:421
llvm::WebAssembly::WasmEnableEmEH
cl::opt< bool > WasmEnableEmEH
llvm::CallBase::setCallingConv
void setCallingConv(CallingConv::ID CC)
Definition: InstrTypes.h:1459
llvm::FunctionType
Class to represent function types.
Definition: DerivedTypes.h:103
llvm::SmallPtrSetImpl::insert
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:365
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:38
llvm::cl::list
Definition: CommandLine.h:1601
llvm::RegState::Undef
@ Undef
Value of the register doesn't matter.
Definition: MachineInstrBuilder.h:52