LLVM  14.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 global variable with the given name. If it doesn't exist declare it,
410 // which will generate an import and assume that it will exist at link time.
413  const char *Name) {
414  auto *GV = dyn_cast<GlobalVariable>(M.getOrInsertGlobal(Name, Ty));
415  if (!GV)
416  report_fatal_error(Twine("unable to create global: ") + Name);
417 
418  // If the target supports TLS, make this variable thread-local. We can't just
419  // unconditionally make it thread-local and depend on
420  // CoalesceFeaturesAndStripAtomics to downgrade it, because stripping TLS has
421  // the side effect of disallowing the object from being linked into a
422  // shared-memory module, which we don't want to be responsible for.
423  auto *Subtarget = TM.getSubtargetImpl();
424  auto TLS = Subtarget->hasAtomics() && Subtarget->hasBulkMemory()
427  GV->setThreadLocalMode(TLS);
428  return GV;
429 }
430 
431 // Simple function name mangler.
432 // This function simply takes LLVM's string representation of parameter types
433 // and concatenate them with '_'. There are non-alphanumeric characters but llc
434 // is ok with it, and we need to postprocess these names after the lowering
435 // phase anyway.
436 static std::string getSignature(FunctionType *FTy) {
437  std::string Sig;
438  raw_string_ostream OS(Sig);
439  OS << *FTy->getReturnType();
440  for (Type *ParamTy : FTy->params())
441  OS << "_" << *ParamTy;
442  if (FTy->isVarArg())
443  OS << "_...";
444  Sig = OS.str();
445  erase_if(Sig, isSpace);
446  // When s2wasm parses .s file, a comma means the end of an argument. So a
447  // mangled function name can contain any character but a comma.
448  std::replace(Sig.begin(), Sig.end(), ',', '.');
449  return Sig;
450 }
451 
453  Module *M) {
455  // Tell the linker that this function is expected to be imported from the
456  // 'env' module.
457  if (!F->hasFnAttribute("wasm-import-module")) {
458  llvm::AttrBuilder B(M->getContext());
459  B.addAttribute("wasm-import-module", "env");
460  F->addFnAttrs(B);
461  }
462  if (!F->hasFnAttribute("wasm-import-name")) {
463  llvm::AttrBuilder B(M->getContext());
464  B.addAttribute("wasm-import-name", F->getName());
465  F->addFnAttrs(B);
466  }
467  return F;
468 }
469 
470 // Returns an integer type for the target architecture's address space.
471 // i32 for wasm32 and i64 for wasm64.
473  IRBuilder<> IRB(M->getContext());
474  return IRB.getIntNTy(M->getDataLayout().getPointerSizeInBits());
475 }
476 
477 // Returns an integer pointer type for the target architecture's address space.
478 // i32* for wasm32 and i64* for wasm64.
480  return Type::getIntNPtrTy(M->getContext(),
481  M->getDataLayout().getPointerSizeInBits());
482 }
483 
484 // Returns an integer whose type is the integer type for the target's address
485 // space. Returns (i32 C) for wasm32 and (i64 C) for wasm64, when C is the
486 // integer.
488  IRBuilder<> IRB(M->getContext());
489  return IRB.getIntN(M->getDataLayout().getPointerSizeInBits(), C);
490 }
491 
492 // Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
493 // This is because a landingpad instruction contains two more arguments, a
494 // personality function and a cleanup bit, and __cxa_find_matching_catch_N
495 // functions are named after the number of arguments in the original landingpad
496 // instruction.
497 Function *
498 WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
499  unsigned NumClauses) {
500  if (FindMatchingCatches.count(NumClauses))
501  return FindMatchingCatches[NumClauses];
502  PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext());
503  SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy);
504  FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
506  FTy, "__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
507  FindMatchingCatches[NumClauses] = F;
508  return F;
509 }
510 
511 // Generate invoke wrapper seqence with preamble and postamble
512 // Preamble:
513 // __THREW__ = 0;
514 // Postamble:
515 // %__THREW__.val = __THREW__; __THREW__ = 0;
516 // Returns %__THREW__.val, which indicates whether an exception is thrown (or
517 // whether longjmp occurred), for future use.
518 Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallBase *CI) {
519  Module *M = CI->getModule();
520  LLVMContext &C = M->getContext();
521 
522  IRBuilder<> IRB(C);
523  IRB.SetInsertPoint(CI);
524 
525  // Pre-invoke
526  // __THREW__ = 0;
527  IRB.CreateStore(getAddrSizeInt(M, 0), ThrewGV);
528 
529  // Invoke function wrapper in JavaScript
531  // Put the pointer to the callee as first argument, so it can be called
532  // within the invoke wrapper later
533  Args.push_back(CI->getCalledOperand());
534  Args.append(CI->arg_begin(), CI->arg_end());
535  CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
536  NewCall->takeName(CI);
538  NewCall->setDebugLoc(CI->getDebugLoc());
539 
540  // Because we added the pointer to the callee as first argument, all
541  // argument attribute indices have to be incremented by one.
542  SmallVector<AttributeSet, 8> ArgAttributes;
543  const AttributeList &InvokeAL = CI->getAttributes();
544 
545  // No attributes for the callee pointer.
546  ArgAttributes.push_back(AttributeSet());
547  // Copy the argument attributes from the original
548  for (unsigned I = 0, E = CI->arg_size(); I < E; ++I)
549  ArgAttributes.push_back(InvokeAL.getParamAttrs(I));
550 
551  AttrBuilder FnAttrs(CI->getContext(), InvokeAL.getFnAttrs());
552  if (FnAttrs.contains(Attribute::AllocSize)) {
553  // The allocsize attribute (if any) referes to parameters by index and needs
554  // to be adjusted.
555  unsigned SizeArg;
556  Optional<unsigned> NEltArg;
557  std::tie(SizeArg, NEltArg) = FnAttrs.getAllocSizeArgs();
558  SizeArg += 1;
559  if (NEltArg.hasValue())
560  NEltArg = NEltArg.getValue() + 1;
561  FnAttrs.addAllocSizeAttr(SizeArg, NEltArg);
562  }
563 
564  // Reconstruct the AttributesList based on the vector we constructed.
565  AttributeList NewCallAL = AttributeList::get(
566  C, AttributeSet::get(C, FnAttrs), InvokeAL.getRetAttrs(), ArgAttributes);
567  NewCall->setAttributes(NewCallAL);
568 
569  CI->replaceAllUsesWith(NewCall);
570 
571  // Post-invoke
572  // %__THREW__.val = __THREW__; __THREW__ = 0;
573  Value *Threw =
574  IRB.CreateLoad(getAddrIntType(M), ThrewGV, ThrewGV->getName() + ".val");
575  IRB.CreateStore(getAddrSizeInt(M, 0), ThrewGV);
576  return Threw;
577 }
578 
579 // Get matching invoke wrapper based on callee signature
580 Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallBase *CI) {
581  Module *M = CI->getModule();
583  FunctionType *CalleeFTy = CI->getFunctionType();
584 
585  std::string Sig = getSignature(CalleeFTy);
586  if (InvokeWrappers.find(Sig) != InvokeWrappers.end())
587  return InvokeWrappers[Sig];
588 
589  // Put the pointer to the callee as first argument
590  ArgTys.push_back(PointerType::getUnqual(CalleeFTy));
591  // Add argument types
592  ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end());
593 
594  FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
595  CalleeFTy->isVarArg());
596  Function *F = getEmscriptenFunction(FTy, "__invoke_" + Sig, M);
597  InvokeWrappers[Sig] = F;
598  return F;
599 }
600 
601 static bool canLongjmp(const Value *Callee) {
602  if (auto *CalleeF = dyn_cast<Function>(Callee))
603  if (CalleeF->isIntrinsic())
604  return false;
605 
606  // Attempting to transform inline assembly will result in something like:
607  // call void @__invoke_void(void ()* asm ...)
608  // which is invalid because inline assembly blocks do not have addresses
609  // and can't be passed by pointer. The result is a crash with illegal IR.
610  if (isa<InlineAsm>(Callee))
611  return false;
612  StringRef CalleeName = Callee->getName();
613 
614  // TODO Include more functions or consider checking with mangled prefixes
615 
616  // The reason we include malloc/free here is to exclude the malloc/free
617  // calls generated in setjmp prep / cleanup routines.
618  if (CalleeName == "setjmp" || CalleeName == "malloc" || CalleeName == "free")
619  return false;
620 
621  // There are functions in Emscripten's JS glue code or compiler-rt
622  if (CalleeName == "__resumeException" || CalleeName == "llvm_eh_typeid_for" ||
623  CalleeName == "saveSetjmp" || CalleeName == "testSetjmp" ||
624  CalleeName == "getTempRet0" || CalleeName == "setTempRet0")
625  return false;
626 
627  // __cxa_find_matching_catch_N functions cannot longjmp
628  if (Callee->getName().startswith("__cxa_find_matching_catch_"))
629  return false;
630 
631  // Exception-catching related functions
632  //
633  // We intentionally excluded __cxa_end_catch here even though it surely cannot
634  // longjmp, in order to maintain the unwind relationship from all existing
635  // catchpads (and calls within them) to catch.dispatch.longjmp.
636  //
637  // In Wasm EH + Wasm SjLj, we
638  // 1. Make all catchswitch and cleanuppad that unwind to caller unwind to
639  // catch.dispatch.longjmp instead
640  // 2. Convert all longjmpable calls to invokes that unwind to
641  // catch.dispatch.longjmp
642  // But catchswitch BBs are removed in isel, so if an EH catchswitch (generated
643  // from an exception)'s catchpad does not contain any calls that are converted
644  // into invokes unwinding to catch.dispatch.longjmp, this unwind relationship
645  // (EH catchswitch BB -> catch.dispatch.longjmp BB) is lost and
646  // catch.dispatch.longjmp BB can be placed before the EH catchswitch BB in
647  // CFGSort.
648  // int ret = setjmp(buf);
649  // try {
650  // foo(); // longjmps
651  // } catch (...) {
652  // }
653  // Then in this code, if 'foo' longjmps, it first unwinds to 'catch (...)'
654  // catchswitch, and is not caught by that catchswitch because it is a longjmp,
655  // then it should next unwind to catch.dispatch.longjmp BB. But if this 'catch
656  // (...)' catchswitch -> catch.dispatch.longjmp unwind relationship is lost,
657  // it will not unwind to catch.dispatch.longjmp, producing an incorrect
658  // result.
659  //
660  // Every catchpad generated by Wasm C++ contains __cxa_end_catch, so we
661  // intentionally treat it as longjmpable to work around this problem. This is
662  // a hacky fix but an easy one.
663  //
664  // The comment block in findWasmUnwindDestinations() in
665  // SelectionDAGBuilder.cpp is addressing a similar problem.
666  if (CalleeName == "__cxa_begin_catch" ||
667  CalleeName == "__cxa_allocate_exception" || CalleeName == "__cxa_throw" ||
668  CalleeName == "__clang_call_terminate")
669  return false;
670 
671  // std::terminate, which is generated when another exception occurs while
672  // handling an exception, cannot longjmp.
673  if (CalleeName == "_ZSt9terminatev")
674  return false;
675 
676  // Otherwise we don't know
677  return true;
678 }
679 
680 static bool isEmAsmCall(const Value *Callee) {
681  StringRef CalleeName = Callee->getName();
682  // This is an exhaustive list from Emscripten's <emscripten/em_asm.h>.
683  return CalleeName == "emscripten_asm_const_int" ||
684  CalleeName == "emscripten_asm_const_double" ||
685  CalleeName == "emscripten_asm_const_int_sync_on_main_thread" ||
686  CalleeName == "emscripten_asm_const_double_sync_on_main_thread" ||
687  CalleeName == "emscripten_asm_const_async_on_main_thread";
688 }
689 
690 // Generate testSetjmp function call seqence with preamble and postamble.
691 // The code this generates is equivalent to the following JavaScript code:
692 // %__threwValue.val = __threwValue;
693 // if (%__THREW__.val != 0 & %__threwValue.val != 0) {
694 // %label = testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
695 // if (%label == 0)
696 // emscripten_longjmp(%__THREW__.val, %__threwValue.val);
697 // setTempRet0(%__threwValue.val);
698 // } else {
699 // %label = -1;
700 // }
701 // %longjmp_result = getTempRet0();
702 //
703 // As output parameters. returns %label, %longjmp_result, and the BB the last
704 // instruction (%longjmp_result = ...) is in.
705 void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
706  BasicBlock *BB, DebugLoc DL, Value *Threw, Value *SetjmpTable,
707  Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult,
708  BasicBlock *&CallEmLongjmpBB, PHINode *&CallEmLongjmpBBThrewPHI,
709  PHINode *&CallEmLongjmpBBThrewValuePHI, BasicBlock *&EndBB) {
710  Function *F = BB->getParent();
711  Module *M = F->getParent();
712  LLVMContext &C = M->getContext();
713  IRBuilder<> IRB(C);
714  IRB.SetCurrentDebugLocation(DL);
715 
716  // if (%__THREW__.val != 0 & %__threwValue.val != 0)
717  IRB.SetInsertPoint(BB);
718  BasicBlock *ThenBB1 = BasicBlock::Create(C, "if.then1", F);
719  BasicBlock *ElseBB1 = BasicBlock::Create(C, "if.else1", F);
720  BasicBlock *EndBB1 = BasicBlock::Create(C, "if.end", F);
721  Value *ThrewCmp = IRB.CreateICmpNE(Threw, getAddrSizeInt(M, 0));
722  Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
723  ThrewValueGV->getName() + ".val");
724  Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
725  Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp, "cmp1");
726  IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
727 
728  // Generate call.em.longjmp BB once and share it within the function
729  if (!CallEmLongjmpBB) {
730  // emscripten_longjmp(%__THREW__.val, %__threwValue.val);
731  CallEmLongjmpBB = BasicBlock::Create(C, "call.em.longjmp", F);
732  IRB.SetInsertPoint(CallEmLongjmpBB);
733  CallEmLongjmpBBThrewPHI = IRB.CreatePHI(getAddrIntType(M), 4, "threw.phi");
734  CallEmLongjmpBBThrewValuePHI =
735  IRB.CreatePHI(IRB.getInt32Ty(), 4, "threwvalue.phi");
736  CallEmLongjmpBBThrewPHI->addIncoming(Threw, ThenBB1);
737  CallEmLongjmpBBThrewValuePHI->addIncoming(ThrewValue, ThenBB1);
738  IRB.CreateCall(EmLongjmpF,
739  {CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI});
740  IRB.CreateUnreachable();
741  } else {
742  CallEmLongjmpBBThrewPHI->addIncoming(Threw, ThenBB1);
743  CallEmLongjmpBBThrewValuePHI->addIncoming(ThrewValue, ThenBB1);
744  }
745 
746  // %label = testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
747  // if (%label == 0)
748  IRB.SetInsertPoint(ThenBB1);
749  BasicBlock *EndBB2 = BasicBlock::Create(C, "if.end2", F);
750  Value *ThrewPtr =
751  IRB.CreateIntToPtr(Threw, getAddrPtrType(M), Threw->getName() + ".p");
752  Value *LoadedThrew = IRB.CreateLoad(getAddrIntType(M), ThrewPtr,
753  ThrewPtr->getName() + ".loaded");
754  Value *ThenLabel = IRB.CreateCall(
755  TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, "label");
756  Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
757  IRB.CreateCondBr(Cmp2, CallEmLongjmpBB, EndBB2);
758 
759  // setTempRet0(%__threwValue.val);
760  IRB.SetInsertPoint(EndBB2);
761  IRB.CreateCall(SetTempRet0F, ThrewValue);
762  IRB.CreateBr(EndBB1);
763 
764  IRB.SetInsertPoint(ElseBB1);
765  IRB.CreateBr(EndBB1);
766 
767  // longjmp_result = getTempRet0();
768  IRB.SetInsertPoint(EndBB1);
769  PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label");
770  LabelPHI->addIncoming(ThenLabel, EndBB2);
771 
772  LabelPHI->addIncoming(IRB.getInt32(-1), ElseBB1);
773 
774  // Output parameter assignment
775  Label = LabelPHI;
776  EndBB = EndBB1;
777  LongjmpResult = IRB.CreateCall(GetTempRet0F, None, "longjmp_result");
778 }
779 
780 void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
781  DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
782  DT.recalculate(F); // CFG has been changed
783 
785  for (BasicBlock &BB : F) {
786  for (Instruction &I : BB) {
787  unsigned VarID = SSA.AddVariable(I.getName(), I.getType());
788  // If a value is defined by an invoke instruction, it is only available in
789  // its normal destination and not in its unwind destination.
790  if (auto *II = dyn_cast<InvokeInst>(&I))
791  SSA.AddAvailableValue(VarID, II->getNormalDest(), II);
792  else
793  SSA.AddAvailableValue(VarID, &BB, &I);
794  for (auto &U : I.uses()) {
795  auto *User = cast<Instruction>(U.getUser());
796  if (auto *UserPN = dyn_cast<PHINode>(User))
797  if (UserPN->getIncomingBlock(U) == &BB)
798  continue;
799  if (DT.dominates(&I, User))
800  continue;
801  SSA.AddUse(VarID, &U);
802  }
803  }
804  }
805  SSA.RewriteAllUses(&DT);
806 }
807 
808 // Replace uses of longjmp with a new longjmp function in Emscripten library.
809 // In Emscripten SjLj, the new function is
810 // void emscripten_longjmp(uintptr_t, i32)
811 // In Wasm SjLj, the new function is
812 // void __wasm_longjmp(i8*, i32)
813 // Because the original libc longjmp function takes (jmp_buf*, i32), we need a
814 // ptrtoint/bitcast instruction here to make the type match. jmp_buf* will
815 // eventually be lowered to i32/i64 in the wasm backend.
816 void WebAssemblyLowerEmscriptenEHSjLj::replaceLongjmpWith(Function *LongjmpF,
817  Function *NewF) {
818  assert(NewF == EmLongjmpF || NewF == WasmLongjmpF);
819  Module *M = LongjmpF->getParent();
821  LLVMContext &C = LongjmpF->getParent()->getContext();
822  IRBuilder<> IRB(C);
823 
824  // For calls to longjmp, replace it with emscripten_longjmp/__wasm_longjmp and
825  // cast its first argument (jmp_buf*) appropriately
826  for (User *U : LongjmpF->users()) {
827  auto *CI = dyn_cast<CallInst>(U);
828  if (CI && CI->getCalledFunction() == LongjmpF) {
829  IRB.SetInsertPoint(CI);
830  Value *Env = nullptr;
831  if (NewF == EmLongjmpF)
832  Env =
833  IRB.CreatePtrToInt(CI->getArgOperand(0), getAddrIntType(M), "env");
834  else // WasmLongjmpF
835  Env =
836  IRB.CreateBitCast(CI->getArgOperand(0), IRB.getInt8PtrTy(), "env");
837  IRB.CreateCall(NewF, {Env, CI->getArgOperand(1)});
838  ToErase.push_back(CI);
839  }
840  }
841  for (auto *I : ToErase)
842  I->eraseFromParent();
843 
844  // If we have any remaining uses of longjmp's function pointer, replace it
845  // with (void(*)(jmp_buf*, int))emscripten_longjmp / __wasm_longjmp.
846  if (!LongjmpF->uses().empty()) {
847  Value *NewLongjmp =
848  IRB.CreateBitCast(NewF, LongjmpF->getType(), "longjmp.cast");
849  LongjmpF->replaceAllUsesWith(NewLongjmp);
850  }
851 }
852 
853 static bool containsLongjmpableCalls(const Function *F) {
854  for (const auto &BB : *F)
855  for (const auto &I : BB)
856  if (const auto *CB = dyn_cast<CallBase>(&I))
857  if (canLongjmp(CB->getCalledOperand()))
858  return true;
859  return false;
860 }
861 
862 // When a function contains a setjmp call but not other calls that can longjmp,
863 // we don't do setjmp transformation for that setjmp. But we need to convert the
864 // setjmp calls into "i32 0" so they don't cause link time errors. setjmp always
865 // returns 0 when called directly.
866 static void nullifySetjmp(Function *F) {
867  Module &M = *F->getParent();
868  IRBuilder<> IRB(M.getContext());
869  Function *SetjmpF = M.getFunction("setjmp");
871 
872  for (User *U : SetjmpF->users()) {
873  auto *CI = dyn_cast<CallInst>(U);
874  // FIXME 'invoke' to setjmp can happen when we use Wasm EH + Wasm SjLj, but
875  // we don't support two being used together yet.
876  if (!CI)
877  report_fatal_error("Wasm EH + Wasm SjLj is not fully supported yet");
878  BasicBlock *BB = CI->getParent();
879  if (BB->getParent() != F) // in other function
880  continue;
881  ToErase.push_back(CI);
882  CI->replaceAllUsesWith(IRB.getInt32(0));
883  }
884  for (auto *I : ToErase)
885  I->eraseFromParent();
886 }
887 
888 bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
889  LLVM_DEBUG(dbgs() << "********** Lower Emscripten EH & SjLj **********\n");
890 
891  LLVMContext &C = M.getContext();
892  IRBuilder<> IRB(C);
893 
894  Function *SetjmpF = M.getFunction("setjmp");
895  Function *LongjmpF = M.getFunction("longjmp");
896 
897  // In some platforms _setjmp and _longjmp are used instead. Change these to
898  // use setjmp/longjmp instead, because we later detect these functions by
899  // their names.
900  Function *SetjmpF2 = M.getFunction("_setjmp");
901  Function *LongjmpF2 = M.getFunction("_longjmp");
902  if (SetjmpF2) {
903  if (SetjmpF) {
904  if (SetjmpF->getFunctionType() != SetjmpF2->getFunctionType())
905  report_fatal_error("setjmp and _setjmp have different function types");
906  } else {
907  SetjmpF = Function::Create(SetjmpF2->getFunctionType(),
908  GlobalValue::ExternalLinkage, "setjmp", M);
909  }
910  SetjmpF2->replaceAllUsesWith(SetjmpF);
911  }
912  if (LongjmpF2) {
913  if (LongjmpF) {
914  if (LongjmpF->getFunctionType() != LongjmpF2->getFunctionType())
916  "longjmp and _longjmp have different function types");
917  } else {
918  LongjmpF = Function::Create(LongjmpF2->getFunctionType(),
919  GlobalValue::ExternalLinkage, "setjmp", M);
920  }
921  LongjmpF2->replaceAllUsesWith(LongjmpF);
922  }
923 
924  auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
925  assert(TPC && "Expected a TargetPassConfig");
926  auto &TM = TPC->getTM<WebAssemblyTargetMachine>();
927 
928  // Declare (or get) global variables __THREW__, __threwValue, and
929  // getTempRet0/setTempRet0 function which are used in common for both
930  // exception handling and setjmp/longjmp handling
931  ThrewGV = getGlobalVariable(M, getAddrIntType(&M), TM, "__THREW__");
932  ThrewValueGV = getGlobalVariable(M, IRB.getInt32Ty(), TM, "__threwValue");
933  GetTempRet0F = getEmscriptenFunction(
934  FunctionType::get(IRB.getInt32Ty(), false), "getTempRet0", &M);
935  SetTempRet0F = getEmscriptenFunction(
936  FunctionType::get(IRB.getVoidTy(), IRB.getInt32Ty(), false),
937  "setTempRet0", &M);
938  GetTempRet0F->setDoesNotThrow();
939  SetTempRet0F->setDoesNotThrow();
940 
941  bool Changed = false;
942 
943  // Function registration for exception handling
944  if (EnableEmEH) {
945  // Register __resumeException function
946  FunctionType *ResumeFTy =
947  FunctionType::get(IRB.getVoidTy(), IRB.getInt8PtrTy(), false);
948  ResumeF = getEmscriptenFunction(ResumeFTy, "__resumeException", &M);
949  ResumeF->addFnAttr(Attribute::NoReturn);
950 
951  // Register llvm_eh_typeid_for function
952  FunctionType *EHTypeIDTy =
953  FunctionType::get(IRB.getInt32Ty(), IRB.getInt8PtrTy(), false);
954  EHTypeIDF = getEmscriptenFunction(EHTypeIDTy, "llvm_eh_typeid_for", &M);
955  }
956 
957  // Functions that contains calls to setjmp but don't have other longjmpable
958  // calls within them.
959  SmallPtrSet<Function *, 4> SetjmpUsersToNullify;
960 
961  if ((EnableEmSjLj || EnableWasmSjLj) && SetjmpF) {
962  // Precompute setjmp users
963  for (User *U : SetjmpF->users()) {
964  if (auto *CB = dyn_cast<CallBase>(U)) {
965  auto *UserF = CB->getFunction();
966  // If a function that calls setjmp does not contain any other calls that
967  // can longjmp, we don't need to do any transformation on that function,
968  // so can ignore it
969  if (containsLongjmpableCalls(UserF))
970  SetjmpUsers.insert(UserF);
971  else
972  SetjmpUsersToNullify.insert(UserF);
973  } else {
974  std::string S;
976  SS << *U;
977  report_fatal_error(Twine("Indirect use of setjmp is not supported: ") +
978  SS.str());
979  }
980  }
981  }
982 
983  bool SetjmpUsed = SetjmpF && !SetjmpUsers.empty();
984  bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
985  DoSjLj = (EnableEmSjLj | EnableWasmSjLj) && (SetjmpUsed || LongjmpUsed);
986 
987  // Function registration and data pre-gathering for setjmp/longjmp handling
988  if (DoSjLj) {
989  assert(EnableEmSjLj || EnableWasmSjLj);
990  if (EnableEmSjLj) {
991  // Register emscripten_longjmp function
993  IRB.getVoidTy(), {getAddrIntType(&M), IRB.getInt32Ty()}, false);
994  EmLongjmpF = getEmscriptenFunction(FTy, "emscripten_longjmp", &M);
995  EmLongjmpF->addFnAttr(Attribute::NoReturn);
996  } else { // EnableWasmSjLj
997  // Register __wasm_longjmp function, which calls __builtin_wasm_longjmp.
999  IRB.getVoidTy(), {IRB.getInt8PtrTy(), IRB.getInt32Ty()}, false);
1000  WasmLongjmpF = getEmscriptenFunction(FTy, "__wasm_longjmp", &M);
1001  WasmLongjmpF->addFnAttr(Attribute::NoReturn);
1002  }
1003 
1004  if (SetjmpF) {
1005  // Register saveSetjmp function
1006  FunctionType *SetjmpFTy = SetjmpF->getFunctionType();
1007  FunctionType *FTy =
1009  {SetjmpFTy->getParamType(0), IRB.getInt32Ty(),
1010  Type::getInt32PtrTy(C), IRB.getInt32Ty()},
1011  false);
1012  SaveSetjmpF = getEmscriptenFunction(FTy, "saveSetjmp", &M);
1013 
1014  // Register testSetjmp function
1015  FTy = FunctionType::get(
1016  IRB.getInt32Ty(),
1017  {getAddrIntType(&M), Type::getInt32PtrTy(C), IRB.getInt32Ty()},
1018  false);
1019  TestSetjmpF = getEmscriptenFunction(FTy, "testSetjmp", &M);
1020 
1021  // wasm.catch() will be lowered down to wasm 'catch' instruction in
1022  // instruction selection.
1023  CatchF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_catch);
1024  // Type for struct __WasmLongjmpArgs
1025  LongjmpArgsTy = StructType::get(IRB.getInt8PtrTy(), // env
1026  IRB.getInt32Ty() // val
1027  );
1028  }
1029  }
1030 
1031  // Exception handling transformation
1032  if (EnableEmEH) {
1033  for (Function &F : M) {
1034  if (F.isDeclaration())
1035  continue;
1036  Changed |= runEHOnFunction(F);
1037  }
1038  }
1039 
1040  // Setjmp/longjmp handling transformation
1041  if (DoSjLj) {
1042  Changed = true; // We have setjmp or longjmp somewhere
1043  if (LongjmpF)
1044  replaceLongjmpWith(LongjmpF, EnableEmSjLj ? EmLongjmpF : WasmLongjmpF);
1045  // Only traverse functions that uses setjmp in order not to insert
1046  // unnecessary prep / cleanup code in every function
1047  if (SetjmpF)
1048  for (Function *F : SetjmpUsers)
1049  runSjLjOnFunction(*F);
1050  }
1051 
1052  // Replace unnecessary setjmp calls with 0
1053  if ((EnableEmSjLj || EnableWasmSjLj) && !SetjmpUsersToNullify.empty()) {
1054  Changed = true;
1055  assert(SetjmpF);
1056  for (Function *F : SetjmpUsersToNullify)
1057  nullifySetjmp(F);
1058  }
1059 
1060  if (!Changed) {
1061  // Delete unused global variables and functions
1062  if (ResumeF)
1063  ResumeF->eraseFromParent();
1064  if (EHTypeIDF)
1065  EHTypeIDF->eraseFromParent();
1066  if (EmLongjmpF)
1067  EmLongjmpF->eraseFromParent();
1068  if (SaveSetjmpF)
1069  SaveSetjmpF->eraseFromParent();
1070  if (TestSetjmpF)
1071  TestSetjmpF->eraseFromParent();
1072  return false;
1073  }
1074 
1075  return true;
1076 }
1077 
1078 bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
1079  Module &M = *F.getParent();
1080  LLVMContext &C = F.getContext();
1081  IRBuilder<> IRB(C);
1082  bool Changed = false;
1085 
1086  // rethrow.longjmp BB that will be shared within the function.
1087  BasicBlock *RethrowLongjmpBB = nullptr;
1088  // PHI node for the loaded value of __THREW__ global variable in
1089  // rethrow.longjmp BB
1090  PHINode *RethrowLongjmpBBThrewPHI = nullptr;
1091 
1092  for (BasicBlock &BB : F) {
1093  auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
1094  if (!II)
1095  continue;
1096  Changed = true;
1097  LandingPads.insert(II->getLandingPadInst());
1098  IRB.SetInsertPoint(II);
1099 
1100  const Value *Callee = II->getCalledOperand();
1101  bool NeedInvoke = supportsException(&F) && canThrow(Callee);
1102  if (NeedInvoke) {
1103  // Wrap invoke with invoke wrapper and generate preamble/postamble
1104  Value *Threw = wrapInvoke(II);
1105  ToErase.push_back(II);
1106 
1107  // If setjmp/longjmp handling is enabled, the thrown value can be not an
1108  // exception but a longjmp. If the current function contains calls to
1109  // setjmp, it will be appropriately handled in runSjLjOnFunction. But even
1110  // if the function does not contain setjmp calls, we shouldn't silently
1111  // ignore longjmps; we should rethrow them so they can be correctly
1112  // handled in somewhere up the call chain where setjmp is. __THREW__'s
1113  // value is 0 when nothing happened, 1 when an exception is thrown, and
1114  // other values when longjmp is thrown.
1115  //
1116  // if (%__THREW__.val == 0 || %__THREW__.val == 1)
1117  // goto %tail
1118  // else
1119  // goto %longjmp.rethrow
1120  //
1121  // rethrow.longjmp: ;; This is longjmp. Rethrow it
1122  // %__threwValue.val = __threwValue
1123  // emscripten_longjmp(%__THREW__.val, %__threwValue.val);
1124  //
1125  // tail: ;; Nothing happened or an exception is thrown
1126  // ... Continue exception handling ...
1127  if (DoSjLj && EnableEmSjLj && !SetjmpUsers.count(&F) &&
1128  canLongjmp(Callee)) {
1129  // Create longjmp.rethrow BB once and share it within the function
1130  if (!RethrowLongjmpBB) {
1131  RethrowLongjmpBB = BasicBlock::Create(C, "rethrow.longjmp", &F);
1132  IRB.SetInsertPoint(RethrowLongjmpBB);
1133  RethrowLongjmpBBThrewPHI =
1134  IRB.CreatePHI(getAddrIntType(&M), 4, "threw.phi");
1135  RethrowLongjmpBBThrewPHI->addIncoming(Threw, &BB);
1136  Value *ThrewValue = IRB.CreateLoad(IRB.getInt32Ty(), ThrewValueGV,
1137  ThrewValueGV->getName() + ".val");
1138  IRB.CreateCall(EmLongjmpF, {RethrowLongjmpBBThrewPHI, ThrewValue});
1139  IRB.CreateUnreachable();
1140  } else {
1141  RethrowLongjmpBBThrewPHI->addIncoming(Threw, &BB);
1142  }
1143 
1144  IRB.SetInsertPoint(II); // Restore the insert point back
1145  BasicBlock *Tail = BasicBlock::Create(C, "tail", &F);
1146  Value *CmpEqOne =
1147  IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp.eq.one");
1148  Value *CmpEqZero =
1149  IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 0), "cmp.eq.zero");
1150  Value *Or = IRB.CreateOr(CmpEqZero, CmpEqOne, "or");
1151  IRB.CreateCondBr(Or, Tail, RethrowLongjmpBB);
1152  IRB.SetInsertPoint(Tail);
1153  BB.replaceSuccessorsPhiUsesWith(&BB, Tail);
1154  }
1155 
1156  // Insert a branch based on __THREW__ variable
1157  Value *Cmp = IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp");
1158  IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
1159 
1160  } else {
1161  // This can't throw, and we don't need this invoke, just replace it with a
1162  // call+branch
1163  changeToCall(II);
1164  }
1165  }
1166 
1167  // Process resume instructions
1168  for (BasicBlock &BB : F) {
1169  // Scan the body of the basic block for resumes
1170  for (Instruction &I : BB) {
1171  auto *RI = dyn_cast<ResumeInst>(&I);
1172  if (!RI)
1173  continue;
1174  Changed = true;
1175 
1176  // Split the input into legal values
1177  Value *Input = RI->getValue();
1178  IRB.SetInsertPoint(RI);
1179  Value *Low = IRB.CreateExtractValue(Input, 0, "low");
1180  // Create a call to __resumeException function
1181  IRB.CreateCall(ResumeF, {Low});
1182  // Add a terminator to the block
1183  IRB.CreateUnreachable();
1184  ToErase.push_back(RI);
1185  }
1186  }
1187 
1188  // Process llvm.eh.typeid.for intrinsics
1189  for (BasicBlock &BB : F) {
1190  for (Instruction &I : BB) {
1191  auto *CI = dyn_cast<CallInst>(&I);
1192  if (!CI)
1193  continue;
1194  const Function *Callee = CI->getCalledFunction();
1195  if (!Callee)
1196  continue;
1197  if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
1198  continue;
1199  Changed = true;
1200 
1201  IRB.SetInsertPoint(CI);
1202  CallInst *NewCI =
1203  IRB.CreateCall(EHTypeIDF, CI->getArgOperand(0), "typeid");
1204  CI->replaceAllUsesWith(NewCI);
1205  ToErase.push_back(CI);
1206  }
1207  }
1208 
1209  // Look for orphan landingpads, can occur in blocks with no predecessors
1210  for (BasicBlock &BB : F) {
1211  Instruction *I = BB.getFirstNonPHI();
1212  if (auto *LPI = dyn_cast<LandingPadInst>(I))
1213  LandingPads.insert(LPI);
1214  }
1215  Changed |= !LandingPads.empty();
1216 
1217  // Handle all the landingpad for this function together, as multiple invokes
1218  // may share a single lp
1219  for (LandingPadInst *LPI : LandingPads) {
1220  IRB.SetInsertPoint(LPI);
1221  SmallVector<Value *, 16> FMCArgs;
1222  for (unsigned I = 0, E = LPI->getNumClauses(); I < E; ++I) {
1223  Constant *Clause = LPI->getClause(I);
1224  // TODO Handle filters (= exception specifications).
1225  // https://bugs.llvm.org/show_bug.cgi?id=50396
1226  if (LPI->isCatch(I))
1227  FMCArgs.push_back(Clause);
1228  }
1229 
1230  // Create a call to __cxa_find_matching_catch_N function
1231  Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
1232  CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc");
1233  Value *Undef = UndefValue::get(LPI->getType());
1234  Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0");
1235  Value *TempRet0 = IRB.CreateCall(GetTempRet0F, None, "tempret0");
1236  Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
1237 
1238  LPI->replaceAllUsesWith(Pair1);
1239  ToErase.push_back(LPI);
1240  }
1241 
1242  // Erase everything we no longer need in this function
1243  for (Instruction *I : ToErase)
1244  I->eraseFromParent();
1245 
1246  return Changed;
1247 }
1248 
1249 // This tries to get debug info from the instruction before which a new
1250 // instruction will be inserted, and if there's no debug info in that
1251 // instruction, tries to get the info instead from the previous instruction (if
1252 // any). If none of these has debug info and a DISubprogram is provided, it
1253 // creates a dummy debug info with the first line of the function, because IR
1254 // verifier requires all inlinable callsites should have debug info when both a
1255 // caller and callee have DISubprogram. If none of these conditions are met,
1256 // returns empty info.
1257 static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore,
1258  DISubprogram *SP) {
1259  assert(InsertBefore);
1260  if (InsertBefore->getDebugLoc())
1261  return InsertBefore->getDebugLoc();
1262  const Instruction *Prev = InsertBefore->getPrevNode();
1263  if (Prev && Prev->getDebugLoc())
1264  return Prev->getDebugLoc();
1265  if (SP)
1266  return DILocation::get(SP->getContext(), SP->getLine(), 1, SP);
1267  return DebugLoc();
1268 }
1269 
1270 bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
1271  assert(EnableEmSjLj || EnableWasmSjLj);
1272  Module &M = *F.getParent();
1273  LLVMContext &C = F.getContext();
1274  IRBuilder<> IRB(C);
1276  // Vector of %setjmpTable values
1277  SmallVector<Instruction *, 4> SetjmpTableInsts;
1278  // Vector of %setjmpTableSize values
1279  SmallVector<Instruction *, 4> SetjmpTableSizeInsts;
1280 
1281  // Setjmp preparation
1282 
1283  // This instruction effectively means %setjmpTableSize = 4.
1284  // We create this as an instruction intentionally, and we don't want to fold
1285  // this instruction to a constant 4, because this value will be used in
1286  // SSAUpdater.AddAvailableValue(...) later.
1287  BasicBlock *Entry = &F.getEntryBlock();
1288  DebugLoc FirstDL = getOrCreateDebugLoc(&*Entry->begin(), F.getSubprogram());
1289  SplitBlock(Entry, &*Entry->getFirstInsertionPt());
1290 
1291  BinaryOperator *SetjmpTableSize =
1292  BinaryOperator::Create(Instruction::Add, IRB.getInt32(4), IRB.getInt32(0),
1293  "setjmpTableSize", Entry->getTerminator());
1294  SetjmpTableSize->setDebugLoc(FirstDL);
1295  // setjmpTable = (int *) malloc(40);
1296  Instruction *SetjmpTable = CallInst::CreateMalloc(
1297  SetjmpTableSize, IRB.getInt32Ty(), IRB.getInt32Ty(), IRB.getInt32(40),
1298  nullptr, nullptr, "setjmpTable");
1299  SetjmpTable->setDebugLoc(FirstDL);
1300  // CallInst::CreateMalloc may return a bitcast instruction if the result types
1301  // mismatch. We need to set the debug loc for the original call too.
1302  auto *MallocCall = SetjmpTable->stripPointerCasts();
1303  if (auto *MallocCallI = dyn_cast<Instruction>(MallocCall)) {
1304  MallocCallI->setDebugLoc(FirstDL);
1305  }
1306  // setjmpTable[0] = 0;
1307  IRB.SetInsertPoint(SetjmpTableSize);
1308  IRB.CreateStore(IRB.getInt32(0), SetjmpTable);
1309  SetjmpTableInsts.push_back(SetjmpTable);
1310  SetjmpTableSizeInsts.push_back(SetjmpTableSize);
1311 
1312  // Setjmp transformation
1313  SmallVector<PHINode *, 4> SetjmpRetPHIs;
1314  Function *SetjmpF = M.getFunction("setjmp");
1315  for (auto *U : make_early_inc_range(SetjmpF->users())) {
1316  auto *CB = dyn_cast<CallBase>(U);
1317  BasicBlock *BB = CB->getParent();
1318  if (BB->getParent() != &F) // in other function
1319  continue;
1320 
1321  CallInst *CI = nullptr;
1322  // setjmp cannot throw. So if it is an invoke, lower it to a call
1323  if (auto *II = dyn_cast<InvokeInst>(CB))
1324  CI = llvm::changeToCall(II);
1325  else
1326  CI = cast<CallInst>(CB);
1327 
1328  // The tail is everything right after the call, and will be reached once
1329  // when setjmp is called, and later when longjmp returns to the setjmp
1331  // Add a phi to the tail, which will be the output of setjmp, which
1332  // indicates if this is the first call or a longjmp back. The phi directly
1333  // uses the right value based on where we arrive from
1334  IRB.SetInsertPoint(Tail->getFirstNonPHI());
1335  PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2, "setjmp.ret");
1336 
1337  // setjmp initial call returns 0
1338  SetjmpRet->addIncoming(IRB.getInt32(0), BB);
1339  // The proper output is now this, not the setjmp call itself
1340  CI->replaceAllUsesWith(SetjmpRet);
1341  // longjmp returns to the setjmp will add themselves to this phi
1342  SetjmpRetPHIs.push_back(SetjmpRet);
1343 
1344  // Fix call target
1345  // Our index in the function is our place in the array + 1 to avoid index
1346  // 0, because index 0 means the longjmp is not ours to handle.
1347  IRB.SetInsertPoint(CI);
1348  Value *Args[] = {CI->getArgOperand(0), IRB.getInt32(SetjmpRetPHIs.size()),
1349  SetjmpTable, SetjmpTableSize};
1350  Instruction *NewSetjmpTable =
1351  IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable");
1352  Instruction *NewSetjmpTableSize =
1353  IRB.CreateCall(GetTempRet0F, None, "setjmpTableSize");
1354  SetjmpTableInsts.push_back(NewSetjmpTable);
1355  SetjmpTableSizeInsts.push_back(NewSetjmpTableSize);
1356  ToErase.push_back(CI);
1357  }
1358 
1359  // Handle longjmpable calls.
1360  if (EnableEmSjLj)
1361  handleLongjmpableCallsForEmscriptenSjLj(
1362  F, SetjmpTableInsts, SetjmpTableSizeInsts, SetjmpRetPHIs);
1363  else // EnableWasmSjLj
1364  handleLongjmpableCallsForWasmSjLj(F, SetjmpTableInsts, SetjmpTableSizeInsts,
1365  SetjmpRetPHIs);
1366 
1367  // Erase everything we no longer need in this function
1368  for (Instruction *I : ToErase)
1369  I->eraseFromParent();
1370 
1371  // Free setjmpTable buffer before each return instruction + function-exiting
1372  // call
1373  SmallVector<Instruction *, 16> ExitingInsts;
1374  for (BasicBlock &BB : F) {
1375  Instruction *TI = BB.getTerminator();
1376  if (isa<ReturnInst>(TI))
1377  ExitingInsts.push_back(TI);
1378  // Any 'call' instruction with 'noreturn' attribute exits the function at
1379  // this point. If this throws but unwinds to another EH pad within this
1380  // function instead of exiting, this would have been an 'invoke', which
1381  // happens if we use Wasm EH or Wasm SjLJ.
1382  for (auto &I : BB) {
1383  if (auto *CI = dyn_cast<CallInst>(&I)) {
1384  bool IsNoReturn = CI->hasFnAttr(Attribute::NoReturn);
1385  if (Function *CalleeF = CI->getCalledFunction())
1386  IsNoReturn |= CalleeF->hasFnAttribute(Attribute::NoReturn);
1387  if (IsNoReturn)
1388  ExitingInsts.push_back(&I);
1389  }
1390  }
1391  }
1392  for (auto *I : ExitingInsts) {
1393  DebugLoc DL = getOrCreateDebugLoc(I, F.getSubprogram());
1394  // If this existing instruction is a call within a catchpad, we should add
1395  // it as "funclet" to the operand bundle of 'free' call
1397  if (auto *CB = dyn_cast<CallBase>(I))
1398  if (auto Bundle = CB->getOperandBundle(LLVMContext::OB_funclet))
1399  Bundles.push_back(OperandBundleDef(*Bundle));
1400  auto *Free = CallInst::CreateFree(SetjmpTable, Bundles, I);
1401  Free->setDebugLoc(DL);
1402  // CallInst::CreateFree may create a bitcast instruction if its argument
1403  // types mismatch. We need to set the debug loc for the bitcast too.
1404  if (auto *FreeCallI = dyn_cast<CallInst>(Free)) {
1405  if (auto *BitCastI = dyn_cast<BitCastInst>(FreeCallI->getArgOperand(0)))
1406  BitCastI->setDebugLoc(DL);
1407  }
1408  }
1409 
1410  // Every call to saveSetjmp can change setjmpTable and setjmpTableSize
1411  // (when buffer reallocation occurs)
1412  // entry:
1413  // setjmpTableSize = 4;
1414  // setjmpTable = (int *) malloc(40);
1415  // setjmpTable[0] = 0;
1416  // ...
1417  // somebb:
1418  // setjmpTable = saveSetjmp(env, label, setjmpTable, setjmpTableSize);
1419  // setjmpTableSize = getTempRet0();
1420  // So we need to make sure the SSA for these variables is valid so that every
1421  // saveSetjmp and testSetjmp calls have the correct arguments.
1422  SSAUpdater SetjmpTableSSA;
1423  SSAUpdater SetjmpTableSizeSSA;
1424  SetjmpTableSSA.Initialize(Type::getInt32PtrTy(C), "setjmpTable");
1425  SetjmpTableSizeSSA.Initialize(Type::getInt32Ty(C), "setjmpTableSize");
1426  for (Instruction *I : SetjmpTableInsts)
1427  SetjmpTableSSA.AddAvailableValue(I->getParent(), I);
1428  for (Instruction *I : SetjmpTableSizeInsts)
1429  SetjmpTableSizeSSA.AddAvailableValue(I->getParent(), I);
1430 
1431  for (auto &U : make_early_inc_range(SetjmpTable->uses()))
1432  if (auto *I = dyn_cast<Instruction>(U.getUser()))
1433  if (I->getParent() != Entry)
1434  SetjmpTableSSA.RewriteUse(U);
1435  for (auto &U : make_early_inc_range(SetjmpTableSize->uses()))
1436  if (auto *I = dyn_cast<Instruction>(U.getUser()))
1437  if (I->getParent() != Entry)
1438  SetjmpTableSizeSSA.RewriteUse(U);
1439 
1440  // Finally, our modifications to the cfg can break dominance of SSA variables.
1441  // For example, in this code,
1442  // if (x()) { .. setjmp() .. }
1443  // if (y()) { .. longjmp() .. }
1444  // We must split the longjmp block, and it can jump into the block splitted
1445  // from setjmp one. But that means that when we split the setjmp block, it's
1446  // first part no longer dominates its second part - there is a theoretically
1447  // possible control flow path where x() is false, then y() is true and we
1448  // reach the second part of the setjmp block, without ever reaching the first
1449  // part. So, we rebuild SSA form here.
1450  rebuildSSA(F);
1451  return true;
1452 }
1453 
1454 // Update each call that can longjmp so it can return to the corresponding
1455 // setjmp. Refer to 4) of "Emscripten setjmp/longjmp handling" section in the
1456 // comments at top of the file for details.
1457 void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForEmscriptenSjLj(
1458  Function &F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
1459  SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1460  Module &M = *F.getParent();
1461  LLVMContext &C = F.getContext();
1462  IRBuilder<> IRB(C);
1464 
1465  // We need to pass setjmpTable and setjmpTableSize to testSetjmp function.
1466  // These values are defined in the beginning of the function and also in each
1467  // setjmp callsite, but we don't know which values we should use at this
1468  // point. So here we arbitraily use the ones defined in the beginning of the
1469  // function, and SSAUpdater will later update them to the correct values.
1470  Instruction *SetjmpTable = *SetjmpTableInsts.begin();
1471  Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin();
1472 
1473  // call.em.longjmp BB that will be shared within the function.
1474  BasicBlock *CallEmLongjmpBB = nullptr;
1475  // PHI node for the loaded value of __THREW__ global variable in
1476  // call.em.longjmp BB
1477  PHINode *CallEmLongjmpBBThrewPHI = nullptr;
1478  // PHI node for the loaded value of __threwValue global variable in
1479  // call.em.longjmp BB
1480  PHINode *CallEmLongjmpBBThrewValuePHI = nullptr;
1481  // rethrow.exn BB that will be shared within the function.
1482  BasicBlock *RethrowExnBB = nullptr;
1483 
1484  // Because we are creating new BBs while processing and don't want to make
1485  // all these newly created BBs candidates again for longjmp processing, we
1486  // first make the vector of candidate BBs.
1487  std::vector<BasicBlock *> BBs;
1488  for (BasicBlock &BB : F)
1489  BBs.push_back(&BB);
1490 
1491  // BBs.size() will change within the loop, so we query it every time
1492  for (unsigned I = 0; I < BBs.size(); I++) {
1493  BasicBlock *BB = BBs[I];
1494  for (Instruction &I : *BB) {
1495  if (isa<InvokeInst>(&I))
1496  report_fatal_error("When using Wasm EH with Emscripten SjLj, there is "
1497  "a restriction that `setjmp` function call and "
1498  "exception cannot be used within the same function");
1499  auto *CI = dyn_cast<CallInst>(&I);
1500  if (!CI)
1501  continue;
1502 
1503  const Value *Callee = CI->getCalledOperand();
1504  if (!canLongjmp(Callee))
1505  continue;
1506  if (isEmAsmCall(Callee))
1507  report_fatal_error("Cannot use EM_ASM* alongside setjmp/longjmp in " +
1508  F.getName() +
1509  ". Please consider using EM_JS, or move the "
1510  "EM_ASM into another function.",
1511  false);
1512 
1513  Value *Threw = nullptr;
1514  BasicBlock *Tail;
1515  if (Callee->getName().startswith("__invoke_")) {
1516  // If invoke wrapper has already been generated for this call in
1517  // previous EH phase, search for the load instruction
1518  // %__THREW__.val = __THREW__;
1519  // in postamble after the invoke wrapper call
1520  LoadInst *ThrewLI = nullptr;
1521  StoreInst *ThrewResetSI = nullptr;
1522  for (auto I = std::next(BasicBlock::iterator(CI)), IE = BB->end();
1523  I != IE; ++I) {
1524  if (auto *LI = dyn_cast<LoadInst>(I))
1525  if (auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
1526  if (GV == ThrewGV) {
1527  Threw = ThrewLI = LI;
1528  break;
1529  }
1530  }
1531  // Search for the store instruction after the load above
1532  // __THREW__ = 0;
1533  for (auto I = std::next(BasicBlock::iterator(ThrewLI)), IE = BB->end();
1534  I != IE; ++I) {
1535  if (auto *SI = dyn_cast<StoreInst>(I)) {
1536  if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand())) {
1537  if (GV == ThrewGV &&
1538  SI->getValueOperand() == getAddrSizeInt(&M, 0)) {
1539  ThrewResetSI = SI;
1540  break;
1541  }
1542  }
1543  }
1544  }
1545  assert(Threw && ThrewLI && "Cannot find __THREW__ load after invoke");
1546  assert(ThrewResetSI && "Cannot find __THREW__ store after invoke");
1547  Tail = SplitBlock(BB, ThrewResetSI->getNextNode());
1548 
1549  } else {
1550  // Wrap call with invoke wrapper and generate preamble/postamble
1551  Threw = wrapInvoke(CI);
1552  ToErase.push_back(CI);
1553  Tail = SplitBlock(BB, CI->getNextNode());
1554 
1555  // If exception handling is enabled, the thrown value can be not a
1556  // longjmp but an exception, in which case we shouldn't silently ignore
1557  // exceptions; we should rethrow them.
1558  // __THREW__'s value is 0 when nothing happened, 1 when an exception is
1559  // thrown, other values when longjmp is thrown.
1560  //
1561  // if (%__THREW__.val == 1)
1562  // goto %eh.rethrow
1563  // else
1564  // goto %normal
1565  //
1566  // eh.rethrow: ;; Rethrow exception
1567  // %exn = call @__cxa_find_matching_catch_2() ;; Retrieve thrown ptr
1568  // __resumeException(%exn)
1569  //
1570  // normal:
1571  // <-- Insertion point. Will insert sjlj handling code from here
1572  // goto %tail
1573  //
1574  // tail:
1575  // ...
1576  if (supportsException(&F) && canThrow(Callee)) {
1577  // We will add a new conditional branch. So remove the branch created
1578  // when we split the BB
1579  ToErase.push_back(BB->getTerminator());
1580 
1581  // Generate rethrow.exn BB once and share it within the function
1582  if (!RethrowExnBB) {
1583  RethrowExnBB = BasicBlock::Create(C, "rethrow.exn", &F);
1584  IRB.SetInsertPoint(RethrowExnBB);
1585  CallInst *Exn =
1586  IRB.CreateCall(getFindMatchingCatch(M, 0), {}, "exn");
1587  IRB.CreateCall(ResumeF, {Exn});
1588  IRB.CreateUnreachable();
1589  }
1590 
1591  IRB.SetInsertPoint(CI);
1592  BasicBlock *NormalBB = BasicBlock::Create(C, "normal", &F);
1593  Value *CmpEqOne =
1594  IRB.CreateICmpEQ(Threw, getAddrSizeInt(&M, 1), "cmp.eq.one");
1595  IRB.CreateCondBr(CmpEqOne, RethrowExnBB, NormalBB);
1596 
1597  IRB.SetInsertPoint(NormalBB);
1598  IRB.CreateBr(Tail);
1599  BB = NormalBB; // New insertion point to insert testSetjmp()
1600  }
1601  }
1602 
1603  // We need to replace the terminator in Tail - SplitBlock makes BB go
1604  // straight to Tail, we need to check if a longjmp occurred, and go to the
1605  // right setjmp-tail if so
1606  ToErase.push_back(BB->getTerminator());
1607 
1608  // Generate a function call to testSetjmp function and preamble/postamble
1609  // code to figure out (1) whether longjmp occurred (2) if longjmp
1610  // occurred, which setjmp it corresponds to
1611  Value *Label = nullptr;
1612  Value *LongjmpResult = nullptr;
1613  BasicBlock *EndBB = nullptr;
1614  wrapTestSetjmp(BB, CI->getDebugLoc(), Threw, SetjmpTable, SetjmpTableSize,
1615  Label, LongjmpResult, CallEmLongjmpBB,
1616  CallEmLongjmpBBThrewPHI, CallEmLongjmpBBThrewValuePHI,
1617  EndBB);
1618  assert(Label && LongjmpResult && EndBB);
1619 
1620  // Create switch instruction
1621  IRB.SetInsertPoint(EndBB);
1622  IRB.SetCurrentDebugLocation(EndBB->getInstList().back().getDebugLoc());
1623  SwitchInst *SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.size());
1624  // -1 means no longjmp happened, continue normally (will hit the default
1625  // switch case). 0 means a longjmp that is not ours to handle, needs a
1626  // rethrow. Otherwise the index is the same as the index in P+1 (to avoid
1627  // 0).
1628  for (unsigned I = 0; I < SetjmpRetPHIs.size(); I++) {
1629  SI->addCase(IRB.getInt32(I + 1), SetjmpRetPHIs[I]->getParent());
1630  SetjmpRetPHIs[I]->addIncoming(LongjmpResult, EndBB);
1631  }
1632 
1633  // We are splitting the block here, and must continue to find other calls
1634  // in the block - which is now split. so continue to traverse in the Tail
1635  BBs.push_back(Tail);
1636  }
1637  }
1638 
1639  for (Instruction *I : ToErase)
1640  I->eraseFromParent();
1641 }
1642 
1644  for (const User *U : CPI->users())
1645  if (const auto *CRI = dyn_cast<CleanupReturnInst>(U))
1646  return CRI->getUnwindDest();
1647  return nullptr;
1648 }
1649 
1650 // Create a catchpad in which we catch a longjmp's env and val arguments, test
1651 // if the longjmp corresponds to one of setjmps in the current function, and if
1652 // so, jump to the setjmp dispatch BB from which we go to one of post-setjmp
1653 // BBs. Refer to 4) of "Wasm setjmp/longjmp handling" section in the comments at
1654 // top of the file for details.
1655 void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
1656  Function &F, InstVector &SetjmpTableInsts, InstVector &SetjmpTableSizeInsts,
1657  SmallVectorImpl<PHINode *> &SetjmpRetPHIs) {
1658  Module &M = *F.getParent();
1659  LLVMContext &C = F.getContext();
1660  IRBuilder<> IRB(C);
1661 
1662  // A function with catchswitch/catchpad instruction should have a personality
1663  // function attached to it. Search for the wasm personality function, and if
1664  // it exists, use it, and if it doesn't, create a dummy personality function.
1665  // (SjLj is not going to call it anyway.)
1666  if (!F.hasPersonalityFn()) {
1668  FunctionType *PersType =
1669  FunctionType::get(IRB.getInt32Ty(), /* isVarArg */ true);
1670  Value *PersF = M.getOrInsertFunction(PersName, PersType).getCallee();
1671  F.setPersonalityFn(
1672  cast<Constant>(IRB.CreateBitCast(PersF, IRB.getInt8PtrTy())));
1673  }
1674 
1675  // Use the entry BB's debugloc as a fallback
1676  BasicBlock *Entry = &F.getEntryBlock();
1677  DebugLoc FirstDL = getOrCreateDebugLoc(&*Entry->begin(), F.getSubprogram());
1678  IRB.SetCurrentDebugLocation(FirstDL);
1679 
1680  // Arbitrarily use the ones defined in the beginning of the function.
1681  // SSAUpdater will later update them to the correct values.
1682  Instruction *SetjmpTable = *SetjmpTableInsts.begin();
1683  Instruction *SetjmpTableSize = *SetjmpTableSizeInsts.begin();
1684 
1685  // Add setjmp.dispatch BB right after the entry block. Because we have
1686  // initialized setjmpTable/setjmpTableSize in the entry block and split the
1687  // rest into another BB, here 'OrigEntry' is the function's original entry
1688  // block before the transformation.
1689  //
1690  // entry:
1691  // setjmpTable / setjmpTableSize initialization
1692  // setjmp.dispatch:
1693  // switch will be inserted here later
1694  // entry.split: (OrigEntry)
1695  // the original function starts here
1696  BasicBlock *OrigEntry = Entry->getNextNode();
1697  BasicBlock *SetjmpDispatchBB =
1698  BasicBlock::Create(C, "setjmp.dispatch", &F, OrigEntry);
1699  cast<BranchInst>(Entry->getTerminator())->setSuccessor(0, SetjmpDispatchBB);
1700 
1701  // Create catch.dispatch.longjmp BB and a catchswitch instruction
1702  BasicBlock *CatchDispatchLongjmpBB =
1703  BasicBlock::Create(C, "catch.dispatch.longjmp", &F);
1704  IRB.SetInsertPoint(CatchDispatchLongjmpBB);
1705  CatchSwitchInst *CatchSwitchLongjmp =
1706  IRB.CreateCatchSwitch(ConstantTokenNone::get(C), nullptr, 1);
1707 
1708  // Create catch.longjmp BB and a catchpad instruction
1709  BasicBlock *CatchLongjmpBB = BasicBlock::Create(C, "catch.longjmp", &F);
1710  CatchSwitchLongjmp->addHandler(CatchLongjmpBB);
1711  IRB.SetInsertPoint(CatchLongjmpBB);
1712  CatchPadInst *CatchPad = IRB.CreateCatchPad(CatchSwitchLongjmp, {});
1713 
1714  // Wasm throw and catch instructions can throw and catch multiple values, but
1715  // that requires multivalue support in the toolchain, which is currently not
1716  // very reliable. We instead throw and catch a pointer to a struct value of
1717  // type 'struct __WasmLongjmpArgs', which is defined in Emscripten.
1718  Instruction *CatchCI =
1719  IRB.CreateCall(CatchF, {IRB.getInt32(WebAssembly::C_LONGJMP)}, "thrown");
1720  Value *LongjmpArgs =
1721  IRB.CreateBitCast(CatchCI, LongjmpArgsTy->getPointerTo(), "longjmp.args");
1722  Value *EnvField =
1723  IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 0, "env_gep");
1724  Value *ValField =
1725  IRB.CreateConstGEP2_32(LongjmpArgsTy, LongjmpArgs, 0, 1, "val_gep");
1726  // void *env = __wasm_longjmp_args.env;
1727  Instruction *Env = IRB.CreateLoad(IRB.getInt8PtrTy(), EnvField, "env");
1728  // int val = __wasm_longjmp_args.val;
1729  Instruction *Val = IRB.CreateLoad(IRB.getInt32Ty(), ValField, "val");
1730 
1731  // %label = testSetjmp(mem[%env], setjmpTable, setjmpTableSize);
1732  // if (%label == 0)
1733  // __wasm_longjmp(%env, %val)
1734  // catchret to %setjmp.dispatch
1735  BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", &F);
1736  BasicBlock *EndBB = BasicBlock::Create(C, "if.end", &F);
1737  Value *EnvP = IRB.CreateBitCast(Env, getAddrPtrType(&M), "env.p");
1738  Value *SetjmpID = IRB.CreateLoad(getAddrIntType(&M), EnvP, "setjmp.id");
1739  Value *Label =
1740  IRB.CreateCall(TestSetjmpF, {SetjmpID, SetjmpTable, SetjmpTableSize},
1741  OperandBundleDef("funclet", CatchPad), "label");
1742  Value *Cmp = IRB.CreateICmpEQ(Label, IRB.getInt32(0));
1743  IRB.CreateCondBr(Cmp, ThenBB, EndBB);
1744 
1745  IRB.SetInsertPoint(ThenBB);
1746  CallInst *WasmLongjmpCI = IRB.CreateCall(
1747  WasmLongjmpF, {Env, Val}, OperandBundleDef("funclet", CatchPad));
1748  IRB.CreateUnreachable();
1749 
1750  IRB.SetInsertPoint(EndBB);
1751  // Jump to setjmp.dispatch block
1752  IRB.CreateCatchRet(CatchPad, SetjmpDispatchBB);
1753 
1754  // Go back to setjmp.dispatch BB
1755  // setjmp.dispatch:
1756  // switch %label {
1757  // label 1: goto post-setjmp BB 1
1758  // label 2: goto post-setjmp BB 2
1759  // ...
1760  // default: goto splitted next BB
1761  // }
1762  IRB.SetInsertPoint(SetjmpDispatchBB);
1763  PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label.phi");
1764  LabelPHI->addIncoming(Label, EndBB);
1765  LabelPHI->addIncoming(IRB.getInt32(-1), Entry);
1766  SwitchInst *SI = IRB.CreateSwitch(LabelPHI, OrigEntry, SetjmpRetPHIs.size());
1767  // -1 means no longjmp happened, continue normally (will hit the default
1768  // switch case). 0 means a longjmp that is not ours to handle, needs a
1769  // rethrow. Otherwise the index is the same as the index in P+1 (to avoid
1770  // 0).
1771  for (unsigned I = 0; I < SetjmpRetPHIs.size(); I++) {
1772  SI->addCase(IRB.getInt32(I + 1), SetjmpRetPHIs[I]->getParent());
1773  SetjmpRetPHIs[I]->addIncoming(Val, SetjmpDispatchBB);
1774  }
1775 
1776  // Convert all longjmpable call instructions to invokes that unwind to the
1777  // newly created catch.dispatch.longjmp BB.
1778  SmallVector<CallInst *, 64> LongjmpableCalls;
1779  for (auto *BB = &*F.begin(); BB; BB = BB->getNextNode()) {
1780  for (auto &I : *BB) {
1781  auto *CI = dyn_cast<CallInst>(&I);
1782  if (!CI)
1783  continue;
1784  const Value *Callee = CI->getCalledOperand();
1785  if (!canLongjmp(Callee))
1786  continue;
1787  if (isEmAsmCall(Callee))
1788  report_fatal_error("Cannot use EM_ASM* alongside setjmp/longjmp in " +
1789  F.getName() +
1790  ". Please consider using EM_JS, or move the "
1791  "EM_ASM into another function.",
1792  false);
1793  // This is __wasm_longjmp() call we inserted in this function, which
1794  // rethrows the longjmp when the longjmp does not correspond to one of
1795  // setjmps in this function. We should not convert this call to an invoke.
1796  if (CI == WasmLongjmpCI)
1797  continue;
1798  LongjmpableCalls.push_back(CI);
1799  }
1800  }
1801 
1802  for (auto *CI : LongjmpableCalls) {
1803  // Even if the callee function has attribute 'nounwind', which is true for
1804  // all C functions, it can longjmp, which means it can throw a Wasm
1805  // exception now.
1806  CI->removeFnAttr(Attribute::NoUnwind);
1807  if (Function *CalleeF = CI->getCalledFunction())
1808  CalleeF->removeFnAttr(Attribute::NoUnwind);
1809 
1810  // Change it to an invoke and make it unwind to the catch.dispatch.longjmp
1811  // BB. If the call is enclosed in another catchpad/cleanuppad scope, unwind
1812  // to its parent pad's unwind destination instead to preserve the scope
1813  // structure. It will eventually unwind to the catch.dispatch.longjmp.
1815  BasicBlock *UnwindDest = nullptr;
1816  if (auto Bundle = CI->getOperandBundle(LLVMContext::OB_funclet)) {
1817  Instruction *FromPad = cast<Instruction>(Bundle->Inputs[0]);
1818  while (!UnwindDest && FromPad) {
1819  if (auto *CPI = dyn_cast<CatchPadInst>(FromPad)) {
1820  UnwindDest = CPI->getCatchSwitch()->getUnwindDest();
1821  FromPad = nullptr; // stop searching
1822  } else if (auto *CPI = dyn_cast<CleanupPadInst>(FromPad)) {
1823  // getCleanupRetUnwindDest() can return nullptr when
1824  // 1. This cleanuppad's matching cleanupret uwninds to caller
1825  // 2. There is no matching cleanupret because it ends with
1826  // unreachable.
1827  // In case of 2, we need to traverse the parent pad chain.
1828  UnwindDest = getCleanupRetUnwindDest(CPI);
1829  FromPad = cast<Instruction>(CPI->getParentPad());
1830  }
1831  }
1832  }
1833  if (!UnwindDest)
1834  UnwindDest = CatchDispatchLongjmpBB;
1835  changeToInvokeAndSplitBasicBlock(CI, UnwindDest);
1836  }
1837 
1839  for (auto &BB : F) {
1840  if (auto *CSI = dyn_cast<CatchSwitchInst>(BB.getFirstNonPHI())) {
1841  if (CSI != CatchSwitchLongjmp && CSI->unwindsToCaller()) {
1842  IRB.SetInsertPoint(CSI);
1843  ToErase.push_back(CSI);
1844  auto *NewCSI = IRB.CreateCatchSwitch(CSI->getParentPad(),
1845  CatchDispatchLongjmpBB, 1);
1846  NewCSI->addHandler(*CSI->handler_begin());
1847  NewCSI->takeName(CSI);
1848  CSI->replaceAllUsesWith(NewCSI);
1849  }
1850  }
1851 
1852  if (auto *CRI = dyn_cast<CleanupReturnInst>(BB.getTerminator())) {
1853  if (CRI->unwindsToCaller()) {
1854  IRB.SetInsertPoint(CRI);
1855  ToErase.push_back(CRI);
1856  IRB.CreateCleanupRet(CRI->getCleanupPad(), CatchDispatchLongjmpBB);
1857  }
1858  }
1859  }
1860 
1861  for (Instruction *I : ToErase)
1862  I->eraseFromParent();
1863 }
getGlobalVariable
static GlobalVariable * getGlobalVariable(Module &M, Type *Ty, WebAssemblyTargetMachine &TM, const char *Name)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:411
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:53
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
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:66
llvm::CallBase::getOperandBundle
Optional< OperandBundleUse > getOperandBundle(StringRef Name) const
Return an operand bundle by name, if present.
Definition: InstrTypes.h:1992
llvm::RecurKind::Or
@ Or
Bitwise or logical OR of integers.
canLongjmp
static bool canLongjmp(const Value *Callee)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:601
llvm::StructType::get
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition: Type.cpp:408
llvm::Intrinsic::getDeclaration
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=None)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
Definition: Function.cpp:1399
llvm::Type::getInt8PtrTy
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:293
llvm::BasicBlock::iterator
InstListType::iterator iterator
Instruction iterators...
Definition: BasicBlock.h:90
llvm::ModulePass
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:238
DebugInfoMetadata.h
llvm::CallBase::removeFnAttr
void removeFnAttr(Attribute::AttrKind Kind)
Removes the attribute from the function.
Definition: InstrTypes.h:1552
llvm::Function
Definition: Function.h:62
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:631
llvm::GlobalValue::NotThreadLocal
@ NotThreadLocal
Definition: GlobalValue.h:179
llvm::Function::eraseFromParent
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition: Function.cpp:365
llvm::ilist_node_with_parent::getNextNode
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition: ilist_node.h:288
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1177
getSignature
static std::string getSignature(FunctionType *FTy)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:436
llvm::LandingPadInst
The landingpad instruction holds all of the information necessary to generate correct exception handl...
Definition: Instructions.h:2909
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:728
llvm::WebAssembly::C_LONGJMP
@ C_LONGJMP
Definition: WasmEHFuncInfo.h:27
llvm::cl::CommaSeparated
@ CommaSeparated
Definition: CommandLine.h:169
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:1830
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:363
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:1006
llvm::DominatorTree
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition: Dominators.h:151
llvm::CallBase::hasFnAttr
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
Definition: InstrTypes.h:1482
llvm::Function::setDoesNotThrow
void setDoesNotThrow()
Definition: Function.h:559
llvm::StringMap::end
iterator end()
Definition: StringMap.h:203
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:403
llvm::CallBase::getAttributes
AttributeList getAttributes() const
Return the parameter attributes for this call.
Definition: InstrTypes.h:1473
llvm::CallBase::getFunctionType
FunctionType * getFunctionType() const
Definition: InstrTypes.h:1256
llvm::AttributeList::getFnAttrs
AttributeSet getFnAttrs() const
The function attributes are returned.
Definition: Attributes.cpp:1352
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:145
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:489
llvm::SmallPtrSet
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:449
isEmAsmCall
static bool isEmAsmCall(const Value *Callee)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:680
llvm::RegState::Undef
@ Undef
Value of the register doesn't matter.
Definition: MachineInstrBuilder.h:52
WebAssemblyTargetMachine.h
llvm::changeToCall
CallInst * changeToCall(InvokeInst *II, DomTreeUpdater *DTU=nullptr)
This function converts the specified invoek into a normall call.
Definition: Local.cpp:2193
llvm::CallBase::arg_begin
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
Definition: InstrTypes.h:1318
llvm::StringMap::find
iterator find(StringRef Key)
Definition: StringMap.h:216
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:301
llvm::Type::getInt32Ty
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:241
llvm::CatchSwitchInst::addHandler
void addHandler(BasicBlock *Dest)
Add an entry to the switch instruction...
Definition: Instructions.cpp:1172
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
llvm::MDNode::get
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition: Metadata.h:1233
llvm::codeview::ProcSymFlags::IsNoReturn
@ IsNoReturn
llvm::OperandBundleDef
OperandBundleDefT< Value * > OperandBundleDef
Definition: InstrTypes.h:1155
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:58
llvm::Optional::hasValue
constexpr bool hasValue() const
Definition: Optional.h:289
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:115
CommandLine.h
SSAUpdaterBulk.h
getCleanupRetUnwindDest
static BasicBlock * getCleanupRetUnwindDest(const CleanupPadInst *CPI)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:1643
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:657
llvm::User
Definition: User.h:44
containsLongjmpableCalls
static bool containsLongjmpableCalls(const Function *F)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:853
llvm::WebAssemblyTargetMachine
Definition: WebAssemblyTargetMachine.h:23
getOrCreateDebugLoc
static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore, DISubprogram *SP)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:1257
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.
Definition: InstrTypes.h:1398
llvm::CallBase::setAttributes
void setAttributes(AttributeList A)
Set the parameter attributes for this call.
Definition: InstrTypes.h:1477
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:531
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:45
llvm::DominatorTreeWrapperPass
Legacy analysis pass which computes a DominatorTree.
Definition: Dominators.h:287
getAddrSizeInt
static Value * getAddrSizeInt(Module *M, uint64_t C)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:487
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:1782
llvm::FunctionType::params
ArrayRef< Type * > params() const
Definition: DerivedTypes.h:130
llvm::createWebAssemblyLowerEmscriptenEHSjLj
ModulePass * createWebAssemblyLowerEmscriptenEHSjLj()
DEBUG_TYPE
#define DEBUG_TYPE
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:288
llvm::None
const NoneType None
Definition: None.h:23
llvm::EHPersonality::Wasm_CXX
@ Wasm_CXX
llvm::Value::use_empty
bool use_empty() const
Definition: Value.h:344
WebAssemblyUtilities.h
llvm::StringMap
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:108
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:285
llvm::Clause
Definition: DirectiveEmitter.h:123
SSA
Memory SSA
Definition: MemorySSA.cpp:73
llvm::CleanupPadInst
Definition: Instructions.h:4452
llvm::StoreInst
An instruction for storing to memory.
Definition: Instructions.h:309
llvm::AttributeList::getRetAttrs
AttributeSet getRetAttrs() const
The attributes for the ret value are returned.
Definition: Attributes.cpp:1348
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:578
llvm::AttributeSet::get
static AttributeSet get(LLVMContext &C, const AttrBuilder &B)
Definition: Attributes.cpp:599
llvm::IRBuilderBase::getInt32
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Definition: IRBuilder.h:478
llvm::PHINode::addIncoming
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
Definition: Instructions.h:2807
llvm::LLVMContext
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
llvm::DenseMap
Definition: DenseMap.h:714
I
#define I(x, y, z)
Definition: MD5.cpp:58
llvm::AttrBuilder
Definition: Attributes.h:997
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:642
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:367
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:139
llvm::ilist_node_with_parent::getPrevNode
NodeTy * getPrevNode()
Definition: ilist_node.h:274
IRBuilder.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
SI
StandardInstrumentations SI(Debug, VerifyEach)
getAddrPtrType
static Type * getAddrPtrType(Module *M)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:479
getAddrIntType
static Type * getAddrIntType(Module *M)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:472
llvm::getEHPersonalityName
StringRef getEHPersonalityName(EHPersonality Pers)
Definition: EHPersonalities.cpp:46
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:2213
llvm::CallBase::arg_end
User::op_iterator arg_end()
Return the iterator pointing to the end of the argument list.
Definition: InstrTypes.h:1324
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:382
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:866
llvm::BinaryOperator
Definition: InstrTypes.h:190
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
llvm::Value::replaceAllUsesWith
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:532
llvm::BasicBlock::Create
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:100
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::LLVMContext::OB_funclet
@ OB_funclet
Definition: LLVMContext.h:90
llvm::Value::getName
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:309
llvm::LoadInst
An instruction for reading from memory.
Definition: Instructions.h:180
llvm::GlobalValue::LocalExecTLSModel
@ LocalExecTLSModel
Definition: GlobalValue.h:183
llvm::Value::stripPointerCasts
const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition: Value.cpp:685
Callee
amdgpu Simplify well known AMD library false FunctionCallee Callee
Definition: AMDGPULibCalls.cpp:185
llvm::MDNode::getContext
LLVMContext & getContext() const
Definition: Metadata.h:967
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
llvm::CallingConv::WASM_EmscriptenInvoke
@ WASM_EmscriptenInvoke
Calling convention for emscripten __invoke_* functions.
Definition: CallingConv.h:247
llvm::pdb::PDB_SymType::Label
@ Label
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:52
llvm::X86::FirstMacroFusionInstKind::Cmp
@ Cmp
WasmEHFuncInfo.h
llvm::CallBase::arg_size
unsigned arg_size() const
Definition: InstrTypes.h:1341
llvm::ConstantTokenNone::get
static ConstantTokenNone * get(LLVMContext &Context)
Return the ConstantTokenNone.
Definition: Constants.cpp:1475
llvm::Module::getContext
LLVMContext & getContext() const
Get the global data context.
Definition: Module.h:259
llvm::Type::getPointerTo
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
Definition: Type.cpp:776
llvm::CallInst::CreateFree
static Instruction * CreateFree(Value *Source, Instruction *InsertBefore)
Generate the IR for a call to the builtin free function.
Definition: Instructions.cpp:805
llvm::Function::getFunctionType
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition: Function.h:177
llvm::MCID::Add
@ Add
Definition: MCInstrDesc.h:183
llvm::CallBase::getCalledOperand
Value * getCalledOperand() const
Definition: InstrTypes.h:1391
llvm::GlobalValue::ExternalLinkage
@ ExternalLinkage
Externally visible function.
Definition: GlobalValue.h:48
llvm::CatchPadInst
Definition: Instructions.h:4493
llvm::BasicBlock::getInstList
const InstListType & getInstList() const
Return the underlying instruction list container.
Definition: BasicBlock.h:363
llvm::AttributeSet
Definition: Attributes.h:270
llvm::CallingConv::Tail
@ Tail
Tail - This calling convention attemps to make calls as fast as possible while guaranteeing that tail...
Definition: CallingConv.h:81
llvm::Instruction::getDebugLoc
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
Definition: Instruction.h:370
Dominators.h
llvm::CallBase::getArgOperand
Value * getArgOperand(unsigned i) const
Definition: InstrTypes.h:1343
llvm::SmallPtrSetImplBase::empty
LLVM_NODISCARD bool empty() const
Definition: SmallPtrSet.h:91
llvm::SSAUpdater::RewriteUse
void RewriteUse(Use &U)
Rewrite a use of the symbolic value.
Definition: SSAUpdater.cpp:187
llvm::Instruction::getParent
const BasicBlock * getParent() const
Definition: Instruction.h:94
llvm::Function::addFnAttr
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
Definition: Function.cpp:536
llvm::PHINode
Definition: Instructions.h:2657
llvm::DISubprogram
Subprogram description.
Definition: DebugInfoMetadata.h:1826
llvm::SmallVectorImpl< Instruction * >
llvm::CallBase
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Definition: InstrTypes.h:1176
llvm::GlobalValue::getType
PointerType * getType() const
Global values are always pointers.
Definition: GlobalValue.h:271
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:1478
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::X86AS::SS
@ SS
Definition: X86.h:189
llvm::AnalysisUsage::addRequired
AnalysisUsage & addRequired()
Definition: PassAnalysisSupport.h:75
llvm::SwitchInst
Multiway switch.
Definition: Instructions.h:3236
llvm::Value::takeName
void takeName(Value *V)
Transfer the name from V to this value.
Definition: Value.cpp:382
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:389
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:70
llvm::cl::desc
Definition: CommandLine.h:412
getEmscriptenFunction
static Function * getEmscriptenFunction(FunctionType *Ty, const Twine &Name, Module *M)
Definition: WebAssemblyLowerEmscriptenEHSjLj.cpp:452
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:1344
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:2750
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:839
llvm::CatchSwitchInst
Definition: Instructions.h:4274
llvm::raw_string_ostream::str
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:649
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::Optional::getValue
constexpr const T & getValue() const LLVM_LVALUE_FUNCTION
Definition: Optional.h:283
llvm::CallBase::setCallingConv
void setCallingConv(CallingConv::ID CC)
Definition: InstrTypes.h:1458
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:364
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:38
llvm::cl::list
Definition: CommandLine.h:1641