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