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