[llvm] r280329 - Revert "Add asm.js-style setjmp/longjmp handling for wasm"

Heejin Ahn via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 31 17:44:37 PDT 2016


Author: aheejin
Date: Wed Aug 31 19:44:37 2016
New Revision: 280329

URL: http://llvm.org/viewvc/llvm-project?rev=280329&view=rev
Log:
Revert "Add asm.js-style setjmp/longjmp handling for wasm"

This reverts commit r280302, it broke the integration tests.

Removed:
    llvm/trunk/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
    llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll
Modified:
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
    llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll
    llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp?rev=280329&r1=280328&r2=280329&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp Wed Aug 31 19:44:37 2016
@@ -8,62 +8,25 @@
 //===----------------------------------------------------------------------===//
 ///
 /// \file
-/// \brief This file lowers exception-related instructions and setjmp/longjmp
-/// function calls in order to use Emscripten's JavaScript try and catch
-/// mechanism.
+/// \brief This file lowers exception-related instructions in order to use
+/// Emscripten's JavaScript try and catch mechanism to handle exceptions.
 ///
-/// To handle exceptions and setjmp/longjmps, this scheme relies on JavaScript's
-/// try and catch syntax and relevant exception-related libraries implemented
-/// in JavaScript glue code that will be produced by Emscripten. This is similar
-/// to the current Emscripten asm.js exception handling in fastcomp. For
-/// fastcomp's EH / SjLj scheme, see these files in fastcomp LLVM branch:
+/// To handle exceptions, this scheme relies on JavaScript's try and catch
+/// syntax and relevant exception-related libraries implemented in JavaScript
+/// glue code that will be produced by Emscripten. This is similar to the
+/// current Emscripten asm.js exception handling in fastcomp.
+/// For fastcomp's EH scheme, see these files in fastcomp LLVM branch:
 /// (Location: https://github.com/kripken/emscripten-fastcomp)
 /// lib/Target/JSBackend/NaCl/LowerEmExceptionsPass.cpp
-/// lib/Target/JSBackend/NaCl/LowerEmSetjmp.cpp
 /// lib/Target/JSBackend/JSBackend.cpp
 /// lib/Target/JSBackend/CallHandlers.h
 ///
-/// * Exception handling
-/// This pass lowers invokes and landingpads into library functions in JS glue
-/// code. Invokes are lowered into function wrappers called invoke wrappers that
-/// exist in JS side, which wraps the original function call with JS try-catch.
-/// If an exception occurred, cxa_throw() function in JS side sets some
-/// variables (see below) so we can check whether an exception occurred from
-/// wasm code and handle it appropriately.
+/// This pass does following things:
 ///
-/// * Setjmp-longjmp handling
-/// This pass lowers setjmp to a reasonably-performant approach for emscripten.
-/// The idea is that each block with a setjmp is broken up into two parts: the
-/// part containing setjmp and the part right after the setjmp. The latter part
-/// is either reached from the setjmp, or later from a longjmp. To handle the
-/// longjmp, all calls that might longjmp are also called using invoke wrappers
-/// and thus JS / try-catch. JS longjmp() function also sets some variables so
-/// we can check / whether a longjmp occurred from wasm code. Each block with a
-/// function call that might longjmp is also split up after the longjmp call.
-/// After the longjmp call, we check whether a longjmp occurred, and if it did,
-/// which setjmp it corresponds to, and jump to the right post-setjmp block.
-/// We assume setjmp-longjmp handling always run after EH handling, which means
-/// we don't expect any exception-related instructions when SjLj runs.
-/// FIXME Currently this scheme does not support indirect call of setjmp,
-/// because of the limitation of the scheme itself. fastcomp does not support it
-/// either.
-///
-/// In detail, this pass does following things:
-///
-/// 1) Create three global variables: __THREW__, __threwValue, and __tempRet0.
-///    __tempRet0 will be set within __cxa_find_matching_catch() function in
+/// 1) Create three global variables: __THREW__, __threwValue, and tempRet0.
+///    tempRet0 will be set within __cxa_find_matching_catch() function in
 ///    JS library, and __THREW__ and __threwValue will be set in invoke wrappers
-///    in JS glue code. For what invoke wrappers are, refer to 3). These
-///    variables are used for both exceptions and setjmp/longjmps.
-///    __THREW__ indicates whether an exception or a longjmp occurred or not. 0
-///    means nothing occurred, 1 means an exception occurred, and other numbers
-///    mean a longjmp occurred. In the case of longjmp, threwValue variable
-///    indicates the corresponding setjmp buffer the longjmp corresponds to.
-///    In exception handling, __tempRet0 indicates the type of an exception
-///    caught, and in setjmp/longjmp, it means the second argument to longjmp
-///    function.
-///
-/// * Exception handling
+///    in JS glue code. For what invoke wrappers are, refer to 3).
 ///
 /// 2) Create setThrew and setTempRet0 functions.
 ///    The global variables created in 1) will exist in wasm address space,
@@ -80,7 +43,7 @@
 ///    }
 ///
 ///    function setTempRet0(value) {
-///      __tempRet0 = value;
+///      tempRet0 = value;
 ///    }
 ///
 /// 3) Lower
@@ -115,10 +78,10 @@
 ///      ... use %val ...
 ///    into
 ///      %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
-///      %val = {%fmc, __tempRet0}
+///      %val = {%fmc, tempRet0}
 ///      ... use %val ...
 ///    Here N is a number calculated based on the number of clauses.
-///    Global variable __tempRet0 is set within __cxa_find_matching_catch() in
+///    Global variable tempRet0 is set within __cxa_find_matching_catch() in
 ///    JS glue code.
 ///
 /// 5) Lower
@@ -133,81 +96,14 @@
 ///      call @llvm_eh_typeid_for(type)
 ///    llvm_eh_typeid_for function will be generated in JS glue code.
 ///
-/// * Setjmp / Longjmp handling
-///
-/// 7) In the function entry that calls setjmp, initialize setjmpTable and
-///    sejmpTableSize as follows:
-///      setjmpTableSize = 4;
-///      setjmpTable = (int *) malloc(40);
-///      setjmpTable[0] = 0;
-///    setjmpTable and setjmpTableSize are used in saveSetjmp() function in JS
-///    code.
-///
-/// 8) Lower
-///      setjmp(buf)
-///    into
-///      setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
-///      setjmpTableSize = __tempRet0;
-///    For each dynamic setjmp call, setjmpTable stores its ID (a number which
-///    is incrementally assigned from 0) and its label (a unique number that
-///    represents each callsite of setjmp). When we need more entries in
-///    setjmpTable, it is reallocated in saveSetjmp() in JS code and it will
-///    return the new table address, and assign the new table size in
-///    __tempRet0. saveSetjmp also stores the setjmp's ID into the buffer buf.
-///    A BB with setjmp is split into two after setjmp call in order to make the
-///    post-setjmp BB the possible destination of longjmp BB.
-///
-/// 9) Lower
-///      longjmp(buf, value)
-///    into
-///      emscripten_longjmp_jmpbuf(buf, value)
-///    emscripten_longjmp_jmpbuf will be lowered to emscripten_longjmp later.
-///
-/// 10) Lower every call that might longjmp into
-///      __THREW__ = 0;
-///      call @invoke_SIG(func, arg1, arg2)
-///      %__THREW__.val = __THREW__;
-///      __THREW__ = 0;
-///      if (%__THREW__.val != 0 & threwValue != 0) {
-///        %label = testSetjmp(mem[%__THREW__.val], setjmpTable,
-///                            setjmpTableSize);
-///        if (%label == 0)
-///          emscripten_longjmp(%__THREW__.val, threwValue);
-///        __tempRet0 = threwValue;
-///      } else {
-///        %label = -1;
-///      }
-///      longjmp_result = __tempRet0;
-///      switch label {
-///        label 1: post-setjmp BB 1
-///        label 2: post-setjmp BB 2
-///        ...
-///        default: splited next BB
-///      }
-///     testSetjmp examines setjmpTable to see if there is a matching setjmp
-///     call. After calling an invoke wrapper, if a longjmp occurred, __THREW__
-///     will be the address of matching jmp_buf buffer and threwValue be the
-///     second argument to longjmp. mem[__THREW__.val] is a setjmp ID that is
-///     stored in saveSetjmp. testSetjmp returns a setjmp label, a unique ID to
-///     each setjmp callsite. Label 0 means this longjmp buffer does not
-///     correspond to one of the setjmp callsites in this function, so in this
-///     case we just chain the longjmp to the caller. (Here we call
-///     emscripten_longjmp, which is different from emscripten_longjmp_jmpbuf.
-///     emscripten_longjmp_jmpbuf takes jmp_buf as its first argument, while
-///     emscripten_longjmp takes an int. Both of them will eventually be lowered
-///     to emscripten_longjmp in s2wasm, but here we need two signatures - we
-///     can't translate an int value to a jmp_buf.)
-///     Label -1 means no longjmp occurred. Otherwise we jump to the right
-///     post-setjmp BB based on the label.
-///
 ///===----------------------------------------------------------------------===//
 
 #include "WebAssembly.h"
 #include "llvm/IR/CallSite.h"
-#include "llvm/IR/Dominators.h"
 #include "llvm/IR/IRBuilder.h"
-#include "llvm/Transforms/Utils/BasicBlockUtils.h"
-#include "llvm/Transforms/Utils/SSAUpdater.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
+#include <set>
 
 using namespace llvm;
 
@@ -229,26 +125,17 @@ class WebAssemblyLowerEmscriptenEHSjLj f
   static const char *EHTypeIDFName;
   static const char *SetThrewFName;
   static const char *SetTempRet0FName;
-  static const char *EmLongjmpFName;
-  static const char *EmLongjmpJmpbufFName;
-  static const char *SaveSetjmpFName;
-  static const char *TestSetjmpFName;
   static const char *FindMatchingCatchPrefix;
   static const char *InvokePrefix;
 
-  bool EnableEH;   // Enable exception handling
-  bool EnableSjLj; // Enable setjmp/longjmp handling
+  bool DoEH;   // Enable exception handling
+  bool DoSjLj; // Enable setjmp/longjmp handling
 
   GlobalVariable *ThrewGV;
   GlobalVariable *ThrewValueGV;
   GlobalVariable *TempRet0GV;
   Function *ResumeF;
   Function *EHTypeIDF;
-  Function *EmLongjmpF;
-  Function *EmLongjmpJmpbufF;
-  Function *SaveSetjmpF;
-  Function *TestSetjmpF;
-
   // __cxa_find_matching_catch_N functions.
   // Indexed by the number of clauses in an original landingpad instruction.
   DenseMap<int, Function *> FindMatchingCatches;
@@ -263,37 +150,26 @@ class WebAssemblyLowerEmscriptenEHSjLj f
 
   bool runEHOnFunction(Function &F);
   bool runSjLjOnFunction(Function &F);
+  // Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
+  // This is because a landingpad instruction contains two more arguments,
+  // a personality function and a cleanup bit, and __cxa_find_matching_catch_N
+  // functions are named after the number of arguments in the original
+  // landingpad instruction.
   Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
 
-  template <typename CallOrInvoke> Value *wrapInvoke(CallOrInvoke *CI);
-  void wrapTestSetjmp(BasicBlock *BB, Instruction *InsertPt, Value *Threw,
-                      Value *SetjmpTable, Value *SetjmpTableSize, Value *&Label,
-                      Value *&LongjmpResult, BasicBlock *&EndBB);
-  template <typename CallOrInvoke> Function *getInvokeWrapper(CallOrInvoke *CI);
-
+  Function *getInvokeWrapper(Module &M, InvokeInst *II);
   bool areAllExceptionsAllowed() const { return EHWhitelistSet.empty(); }
-  bool canLongjmp(Module &M, const Value *Callee) const;
-
-  void createSetThrewFunction(Module &M);
-  void createSetTempRet0Function(Module &M);
-
-  void rebuildSSA(Function &F);
 
 public:
   static char ID;
 
-  WebAssemblyLowerEmscriptenEHSjLj(bool EnableEH = true, bool EnableSjLj = true)
-      : ModulePass(ID), EnableEH(EnableEH), EnableSjLj(EnableSjLj),
-        ThrewGV(nullptr), ThrewValueGV(nullptr), TempRet0GV(nullptr),
-        ResumeF(nullptr), EHTypeIDF(nullptr), EmLongjmpF(nullptr),
-        EmLongjmpJmpbufF(nullptr), SaveSetjmpF(nullptr), TestSetjmpF(nullptr) {
+  WebAssemblyLowerEmscriptenEHSjLj(bool DoEH = true, bool DoSjLj = true)
+      : ModulePass(ID), DoEH(DoEH), DoSjLj(DoSjLj), ThrewGV(nullptr),
+        ThrewValueGV(nullptr), TempRet0GV(nullptr), ResumeF(nullptr),
+        EHTypeIDF(nullptr) {
     EHWhitelistSet.insert(EHWhitelist.begin(), EHWhitelist.end());
   }
   bool runOnModule(Module &M) override;
-
-  void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<DominatorTreeWrapperPass>();
-  }
 };
 } // End anonymous namespace
 
@@ -305,12 +181,6 @@ const char *WebAssemblyLowerEmscriptenEH
     "llvm_eh_typeid_for";
 const char *WebAssemblyLowerEmscriptenEHSjLj::SetThrewFName = "setThrew";
 const char *WebAssemblyLowerEmscriptenEHSjLj::SetTempRet0FName = "setTempRet0";
-const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpFName =
-    "emscripten_longjmp";
-const char *WebAssemblyLowerEmscriptenEHSjLj::EmLongjmpJmpbufFName =
-    "emscripten_longjmp_jmpbuf";
-const char *WebAssemblyLowerEmscriptenEHSjLj::SaveSetjmpFName = "saveSetjmp";
-const char *WebAssemblyLowerEmscriptenEHSjLj::TestSetjmpFName = "testSetjmp";
 const char *WebAssemblyLowerEmscriptenEHSjLj::FindMatchingCatchPrefix =
     "__cxa_find_matching_catch_";
 const char *WebAssemblyLowerEmscriptenEHSjLj::InvokePrefix = "__invoke_";
@@ -320,9 +190,9 @@ INITIALIZE_PASS(WebAssemblyLowerEmscript
                 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
                 false, false)
 
-ModulePass *llvm::createWebAssemblyLowerEmscriptenEHSjLj(bool EnableEH,
-                                                         bool EnableSjLj) {
-  return new WebAssemblyLowerEmscriptenEHSjLj(EnableEH, EnableSjLj);
+ModulePass *llvm::createWebAssemblyLowerEmscriptenEHSjLj(bool DoEH,
+                                                         bool DoSjLj) {
+  return new WebAssemblyLowerEmscriptenEHSjLj(DoEH, DoSjLj);
 }
 
 static bool canThrow(const Value *V) {
@@ -334,7 +204,7 @@ static bool canThrow(const Value *V) {
     // leave setjmp and longjmp (mostly) alone, we process them properly later
     if (Name == "setjmp" || Name == "longjmp")
       return false;
-    return !F->doesNotThrow();
+    return true;
   }
   // not a function, so an indirect call - can throw, we can't tell
   return true;
@@ -372,11 +242,6 @@ static std::string getSignature(Function
   return Sig;
 }
 
-// Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
-// This is because a landingpad instruction contains two more arguments, a
-// personality function and a cleanup bit, and __cxa_find_matching_catch_N
-// functions are named after the number of arguments in the original landingpad
-// instruction.
 Function *
 WebAssemblyLowerEmscriptenEHSjLj::getFindMatchingCatch(Module &M,
                                                        unsigned NumClauses) {
@@ -392,86 +257,15 @@ WebAssemblyLowerEmscriptenEHSjLj::getFin
   return F;
 }
 
-// Generate invoke wrapper seqence with preamble and postamble
-// Preamble:
-// __THREW__ = 0;
-// Postamble:
-// %__THREW__.val = __THREW__; __THREW__ = 0;
-// Returns %__THREW__.val, which indicates whether an exception is thrown (or
-// whether longjmp occurred), for future use.
-template <typename CallOrInvoke>
-Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallOrInvoke *CI) {
-  LLVMContext &C = CI->getModule()->getContext();
-
-  // If we are calling a function that is noreturn, we must remove that
-  // attribute. The code we insert here does expect it to return, after we
-  // catch the exception.
-  if (CI->doesNotReturn()) {
-    if (auto *F = dyn_cast<Function>(CI->getCalledValue()))
-      F->removeFnAttr(Attribute::NoReturn);
-    CI->removeAttribute(AttributeSet::FunctionIndex, Attribute::NoReturn);
-  }
-
-  IRBuilder<> IRB(C);
-  IRB.SetInsertPoint(CI);
-
-  // Pre-invoke
-  // __THREW__ = 0;
-  IRB.CreateStore(IRB.getInt32(0), ThrewGV);
-
-  // Invoke function wrapper in JavaScript
-  SmallVector<Value *, 16> Args;
-  // Put the pointer to the callee as first argument, so it can be called
-  // within the invoke wrapper later
-  Args.push_back(CI->getCalledValue());
-  Args.append(CI->arg_begin(), CI->arg_end());
-  CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(CI), Args);
-  NewCall->takeName(CI);
-  NewCall->setCallingConv(CI->getCallingConv());
-  NewCall->setDebugLoc(CI->getDebugLoc());
-
-  // Because we added the pointer to the callee as first argument, all
-  // argument attribute indices have to be incremented by one.
-  SmallVector<AttributeSet, 8> AttributesVec;
-  const AttributeSet &InvokePAL = CI->getAttributes();
-  CallSite::arg_iterator AI = CI->arg_begin();
-  unsigned i = 1; // Argument attribute index starts from 1
-  for (unsigned e = CI->getNumArgOperands(); i <= e; ++AI, ++i) {
-    if (InvokePAL.hasAttributes(i)) {
-      AttrBuilder B(InvokePAL, i);
-      AttributesVec.push_back(AttributeSet::get(C, i + 1, B));
-    }
-  }
-  // Add any return attributes.
-  if (InvokePAL.hasAttributes(AttributeSet::ReturnIndex))
-    AttributesVec.push_back(AttributeSet::get(C, InvokePAL.getRetAttributes()));
-  // Add any function attributes.
-  if (InvokePAL.hasAttributes(AttributeSet::FunctionIndex))
-    AttributesVec.push_back(AttributeSet::get(C, InvokePAL.getFnAttributes()));
-  // Reconstruct the AttributesList based on the vector we constructed.
-  AttributeSet NewCallPAL = AttributeSet::get(C, AttributesVec);
-  NewCall->setAttributes(NewCallPAL);
-
-  CI->replaceAllUsesWith(NewCall);
-
-  // Post-invoke
-  // %__THREW__.val = __THREW__; __THREW__ = 0;
-  Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
-  IRB.CreateStore(IRB.getInt32(0), ThrewGV);
-  return Threw;
-}
-
-// Get matching invoke wrapper based on callee signature
-template <typename CallOrInvoke>
-Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(CallOrInvoke *CI) {
-  Module *M = CI->getModule();
+Function *WebAssemblyLowerEmscriptenEHSjLj::getInvokeWrapper(Module &M,
+                                                             InvokeInst *II) {
   SmallVector<Type *, 16> ArgTys;
-  Value *Callee = CI->getCalledValue();
+  Value *Callee = II->getCalledValue();
   FunctionType *CalleeFTy;
   if (auto *F = dyn_cast<Function>(Callee))
     CalleeFTy = F->getFunctionType();
   else {
-    auto *CalleeTy = cast<PointerType>(Callee->getType())->getElementType();
+    auto *CalleeTy = dyn_cast<PointerType>(Callee->getType())->getElementType();
     CalleeFTy = dyn_cast<FunctionType>(CalleeTy);
   }
 
@@ -487,243 +281,42 @@ Function *WebAssemblyLowerEmscriptenEHSj
   FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys,
                                         CalleeFTy->isVarArg());
   Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage,
-                                 InvokePrefix + Sig, M);
+                                 InvokePrefix + Sig, &M);
   InvokeWrappers[Sig] = F;
   return F;
 }
 
-bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(Module &M,
-                                                  const Value *Callee) const {
-  if (auto *CalleeF = dyn_cast<Function>(Callee))
-    if (CalleeF->isIntrinsic())
-      return false;
-
-  // The reason we include malloc/free here is to exclude the malloc/free
-  // calls generated in setjmp prep / cleanup routines.
-  Function *SetjmpF = M.getFunction("setjmp");
-  Function *MallocF = M.getFunction("malloc");
-  Function *FreeF = M.getFunction("free");
-  if (Callee == SetjmpF || Callee == MallocF || Callee == FreeF)
-    return false;
-
-  // There are functions in JS glue code
-  if (Callee == ResumeF || Callee == EHTypeIDF || Callee == SaveSetjmpF ||
-      Callee == TestSetjmpF)
-    return false;
-
-  // __cxa_find_matching_catch_N functions cannot longjmp
-  if (Callee->getName().startswith(FindMatchingCatchPrefix))
-    return false;
-
-  // Exception-catching related functions
-  Function *BeginCatchF = M.getFunction("__cxa_begin_catch");
-  Function *EndCatchF = M.getFunction("__cxa_end_catch");
-  Function *AllocExceptionF = M.getFunction("__cxa_allocate_exception");
-  Function *ThrowF = M.getFunction("__cxa_throw");
-  Function *TerminateF = M.getFunction("__clang_call_terminate");
-  if (Callee == BeginCatchF || Callee == EndCatchF ||
-      Callee == AllocExceptionF || Callee == ThrowF || Callee == TerminateF)
-    return false;
-
-  // Otherwise we don't know
-  return true;
-}
-
-// Generate testSetjmp function call seqence with preamble and postamble.
-// The code this generates is equivalent to the following JavaScript code:
-// if (%__THREW__.val != 0 & threwValue != 0) {
-//   %label = _testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
-//   if (%label == 0)
-//     emscripten_longjmp(%__THREW__.val, threwValue);
-//   __tempRet0 = threwValue;
-// } else {
-//   %label = -1;
-// }
-// %longjmp_result = __tempRet0;
-//
-// As output parameters. returns %label, %longjmp_result, and the BB the last
-// instruction (%longjmp_result = ...) is in.
-void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
-    BasicBlock *BB, Instruction *InsertPt, Value *Threw, Value *SetjmpTable,
-    Value *SetjmpTableSize, Value *&Label, Value *&LongjmpResult,
-    BasicBlock *&EndBB) {
-  Function *F = BB->getParent();
-  LLVMContext &C = BB->getModule()->getContext();
-  IRBuilder<> IRB(C);
-  IRB.SetInsertPoint(InsertPt);
-
-  // if (%__THREW__.val != 0 & threwValue != 0)
-  IRB.SetInsertPoint(BB);
-  BasicBlock *ThenBB1 = BasicBlock::Create(C, "if.then1", F);
-  BasicBlock *ElseBB1 = BasicBlock::Create(C, "if.else1", F);
-  BasicBlock *EndBB1 = BasicBlock::Create(C, "if.end", F);
-  Value *ThrewCmp = IRB.CreateICmpNE(Threw, IRB.getInt32(0));
-  Value *ThrewValue =
-      IRB.CreateLoad(ThrewValueGV, ThrewValueGV->getName() + ".val");
-  Value *ThrewValueCmp = IRB.CreateICmpNE(ThrewValue, IRB.getInt32(0));
-  Value *Cmp1 = IRB.CreateAnd(ThrewCmp, ThrewValueCmp, "cmp1");
-  IRB.CreateCondBr(Cmp1, ThenBB1, ElseBB1);
-
-  // %label = _testSetjmp(mem[%__THREW__.val], _setjmpTable, _setjmpTableSize);
-  // if (%label == 0)
-  IRB.SetInsertPoint(ThenBB1);
-  BasicBlock *ThenBB2 = BasicBlock::Create(C, "if.then2", F);
-  BasicBlock *EndBB2 = BasicBlock::Create(C, "if.end2", F);
-  Value *ThrewInt = IRB.CreateIntToPtr(Threw, Type::getInt32PtrTy(C),
-                                       Threw->getName() + ".i32p");
-  Value *LoadedThrew =
-      IRB.CreateLoad(ThrewInt, ThrewInt->getName() + ".loaded");
-  Value *ThenLabel = IRB.CreateCall(
-      TestSetjmpF, {LoadedThrew, SetjmpTable, SetjmpTableSize}, "label");
-  Value *Cmp2 = IRB.CreateICmpEQ(ThenLabel, IRB.getInt32(0));
-  IRB.CreateCondBr(Cmp2, ThenBB2, EndBB2);
-
-  // emscripten_longjmp(%__THREW__.val, threwValue);
-  IRB.SetInsertPoint(ThenBB2);
-  IRB.CreateCall(EmLongjmpF, {Threw, ThrewValue});
-  IRB.CreateUnreachable();
-
-  // __tempRet0 = threwValue;
-  IRB.SetInsertPoint(EndBB2);
-  IRB.CreateStore(ThrewValue, TempRet0GV);
-  IRB.CreateBr(EndBB1);
-
-  IRB.SetInsertPoint(ElseBB1);
-  IRB.CreateBr(EndBB1);
-
-  // longjmp_result = __tempRet0;
-  IRB.SetInsertPoint(EndBB1);
-  PHINode *LabelPHI = IRB.CreatePHI(IRB.getInt32Ty(), 2, "label");
-  LabelPHI->addIncoming(ThenLabel, EndBB2);
-
-  LabelPHI->addIncoming(IRB.getInt32(-1), ElseBB1);
-
-  // Output parameter assignment
-  Label = LabelPHI;
-  EndBB = EndBB1;
-  LongjmpResult = IRB.CreateLoad(TempRet0GV, "longjmp_result");
-}
-
-// Create setThrew function
-// function setThrew(threw, value) {
-//   if (__THREW__ == 0) {
-//     __THREW__ = threw;
-//     __threwValue = value;
-//   }
-// }
-void WebAssemblyLowerEmscriptenEHSjLj::createSetThrewFunction(Module &M) {
-  LLVMContext &C = M.getContext();
-  IRBuilder<> IRB(C);
-
-  assert(!M.getNamedGlobal(SetThrewFName) && "setThrew already exists");
-  Type *Params[] = {IRB.getInt32Ty(), IRB.getInt32Ty()};
-  FunctionType *FTy = FunctionType::get(IRB.getVoidTy(), Params, false);
-  Function *F =
-      Function::Create(FTy, GlobalValue::ExternalLinkage, SetThrewFName, &M);
-  Argument *Arg1 = &*(F->arg_begin());
-  Argument *Arg2 = &*(++F->arg_begin());
-  Arg1->setName("threw");
-  Arg2->setName("value");
-  BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
-  BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", F);
-  BasicBlock *EndBB = BasicBlock::Create(C, "if.end", F);
-
-  IRB.SetInsertPoint(EntryBB);
-  Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
-  Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getInt32(0), "cmp");
-  IRB.CreateCondBr(Cmp, ThenBB, EndBB);
-
-  IRB.SetInsertPoint(ThenBB);
-  IRB.CreateStore(Arg1, ThrewGV);
-  IRB.CreateStore(Arg2, ThrewValueGV);
-  IRB.CreateBr(EndBB);
-
-  IRB.SetInsertPoint(EndBB);
-  IRB.CreateRetVoid();
-}
-
-// Create setTempRet0 function
-// function setTempRet0(value) {
-//   __tempRet0 = value;
-// }
-void WebAssemblyLowerEmscriptenEHSjLj::createSetTempRet0Function(Module &M) {
-  LLVMContext &C = M.getContext();
-  IRBuilder<> IRB(C);
-
-  assert(!M.getNamedGlobal(SetTempRet0FName) && "setTempRet0 already exists");
-  Type *Params[] = {IRB.getInt32Ty()};
-  FunctionType *FTy = FunctionType::get(IRB.getVoidTy(), Params, false);
-  Function *F =
-      Function::Create(FTy, GlobalValue::ExternalLinkage, SetTempRet0FName, &M);
-  F->arg_begin()->setName("value");
-  BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
-  IRB.SetInsertPoint(EntryBB);
-  IRB.CreateStore(&*F->arg_begin(), TempRet0GV);
-  IRB.CreateRetVoid();
-}
-
-void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA(Function &F) {
-  DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
-  DT.recalculate(F); // CFG has been changed
-  SSAUpdater SSA;
-  for (BasicBlock &BB : F) {
-    for (Instruction &I : BB) {
-      for (auto UI = I.use_begin(), UE = I.use_end(); UI != UE;) {
-        Use &U = *UI;
-        ++UI;
-        SSA.Initialize(I.getType(), I.getName());
-        SSA.AddAvailableValue(&BB, &I);
-        Instruction *User = cast<Instruction>(U.getUser());
-        if (User->getParent() == &BB)
-          continue;
-
-        if (PHINode *UserPN = dyn_cast<PHINode>(User))
-          if (UserPN->getIncomingBlock(U) == &BB)
-            continue;
-
-        if (DT.dominates(&I, User))
-          continue;
-        SSA.RewriteUseAfterInsertions(U);
-      }
-    }
-  }
-}
-
 bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
   LLVMContext &C = M.getContext();
   IRBuilder<> IRB(C);
+  IntegerType *Int1Ty = IRB.getInt1Ty();
+  PointerType *Int8PtrTy = IRB.getInt8PtrTy();
+  IntegerType *Int32Ty = IRB.getInt32Ty();
+  Type *VoidTy = IRB.getVoidTy();
 
-  Function *SetjmpF = M.getFunction("setjmp");
-  Function *LongjmpF = M.getFunction("longjmp");
-  bool SetjmpUsed = SetjmpF && !SetjmpF->use_empty();
-  bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty();
-  bool DoSjLj = EnableSjLj && (SetjmpUsed || LongjmpUsed);
-
-  // Create global variables __THREW__, threwValue, and __tempRet0, which are
+  // Create global variables __THREW__, threwValue, and tempRet0, which are
   // used in common for both exception handling and setjmp/longjmp handling
-  ThrewGV = new GlobalVariable(M, IRB.getInt32Ty(), false,
-                               GlobalValue::ExternalLinkage, IRB.getInt32(0),
-                               createGlobalValueName(M, ThrewGVName));
+  ThrewGV =
+      new GlobalVariable(M, Int1Ty, false, GlobalValue::ExternalLinkage,
+                         IRB.getFalse(), createGlobalValueName(M, ThrewGVName));
   ThrewValueGV = new GlobalVariable(
-      M, IRB.getInt32Ty(), false, GlobalValue::ExternalLinkage, IRB.getInt32(0),
+      M, Int32Ty, false, GlobalValue::ExternalLinkage, IRB.getInt32(0),
       createGlobalValueName(M, ThrewValueGVName));
-  TempRet0GV = new GlobalVariable(M, IRB.getInt32Ty(), false,
+  TempRet0GV = new GlobalVariable(M, Int32Ty, false,
                                   GlobalValue::ExternalLinkage, IRB.getInt32(0),
                                   createGlobalValueName(M, TempRet0GVName));
 
   bool Changed = false;
 
   // Exception handling
-  if (EnableEH) {
+  if (DoEH) {
     // Register __resumeException function
-    FunctionType *ResumeFTy =
-        FunctionType::get(IRB.getVoidTy(), IRB.getInt8PtrTy(), false);
+    FunctionType *ResumeFTy = FunctionType::get(VoidTy, Int8PtrTy, false);
     ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage,
                                ResumeFName, &M);
 
     // Register llvm_eh_typeid_for function
-    FunctionType *EHTypeIDTy =
-        FunctionType::get(IRB.getInt32Ty(), IRB.getInt8PtrTy(), false);
+    FunctionType *EHTypeIDTy = FunctionType::get(Int32Ty, Int8PtrTy, false);
     EHTypeIDF = Function::Create(EHTypeIDTy, GlobalValue::ExternalLinkage,
                                  EHTypeIDFName, &M);
 
@@ -734,80 +327,61 @@ bool WebAssemblyLowerEmscriptenEHSjLj::r
     }
   }
 
+  // TODO: Run CFGSimplify like the emscripten JSBackend?
+
   // Setjmp/longjmp handling
   if (DoSjLj) {
-    Changed = true; // We have setjmp or longjmp somewhere
-
-    Function *MallocF = M.getFunction("malloc");
-    Function *FreeF = M.getFunction("free");
-    if (!MallocF || !FreeF)
-      report_fatal_error(
-          "malloc and free must be linked into the module if setjmp is used");
-
-    // Register saveSetjmp function
-    FunctionType *SetjmpFTy = SetjmpF->getFunctionType();
-    SmallVector<Type *, 4> Params = {SetjmpFTy->getParamType(0),
-                                     IRB.getInt32Ty(), Type::getInt32PtrTy(C),
-                                     IRB.getInt32Ty()};
-    FunctionType *FTy =
-        FunctionType::get(Type::getInt32PtrTy(C), Params, false);
-    SaveSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage,
-                                   SaveSetjmpFName, &M);
-
-    // Register testSetjmp function
-    Params = {IRB.getInt32Ty(), Type::getInt32PtrTy(C), IRB.getInt32Ty()};
-    FTy = FunctionType::get(IRB.getInt32Ty(), Params, false);
-    TestSetjmpF = Function::Create(FTy, GlobalValue::ExternalLinkage,
-                                   TestSetjmpFName, &M);
-
-    if (LongjmpF) {
-      // Replace all uses of longjmp with emscripten_longjmp_jmpbuf, which is
-      // defined in JS code
-      EmLongjmpJmpbufF = Function::Create(LongjmpF->getFunctionType(),
-                                          GlobalValue::ExternalLinkage,
-                                          EmLongjmpJmpbufFName, &M);
-
-      LongjmpF->replaceAllUsesWith(EmLongjmpJmpbufF);
-    }
-    FTy = FunctionType::get(IRB.getVoidTy(),
-                            {IRB.getInt32Ty(), IRB.getInt32Ty()}, false);
-    EmLongjmpF =
-        Function::Create(FTy, GlobalValue::ExternalLinkage, EmLongjmpFName, &M);
-
-    // Only traverse functions that uses setjmp in order not to insert
-    // unnecessary prep / cleanup code in every function
-    SmallPtrSet<Function *, 8> SetjmpUsers;
-    for (User *U : SetjmpF->users()) {
-      auto *UI = cast<Instruction>(U);
-      SetjmpUsers.insert(UI->getFunction());
+    for (Function &F : M) {
+      if (F.isDeclaration())
+        continue;
+      Changed |= runSjLjOnFunction(F);
     }
-    for (Function *F : SetjmpUsers)
-      runSjLjOnFunction(*F);
   }
 
-  if (!Changed) {
-    // Delete unused global variables and functions
-    ThrewGV->eraseFromParent();
-    ThrewValueGV->eraseFromParent();
-    TempRet0GV->eraseFromParent();
-    if (ResumeF)
-      ResumeF->eraseFromParent();
-    if (EHTypeIDF)
-      EHTypeIDF->eraseFromParent();
-    if (EmLongjmpF)
-      EmLongjmpF->eraseFromParent();
-    if (SaveSetjmpF)
-      SaveSetjmpF->eraseFromParent();
-    if (TestSetjmpF)
-      TestSetjmpF->eraseFromParent();
+  if (!Changed)
     return false;
-  }
 
   // If we have made any changes while doing exception handling or
   // setjmp/longjmp handling, we have to create these functions for JavaScript
   // to call.
-  createSetThrewFunction(M);
-  createSetTempRet0Function(M);
+  assert(!M.getNamedGlobal(SetThrewFName) && "setThrew already exists");
+  assert(!M.getNamedGlobal(SetTempRet0FName) && "setTempRet0 already exists");
+
+  // Create setThrew function
+  SmallVector<Type *, 2> Params = {Int1Ty, Int32Ty};
+  FunctionType *FTy = FunctionType::get(VoidTy, Params, false);
+  Function *F =
+      Function::Create(FTy, GlobalValue::ExternalLinkage, SetThrewFName, &M);
+  Argument *Arg1 = &*(F->arg_begin());
+  Argument *Arg2 = &*(++F->arg_begin());
+  Arg1->setName("threw");
+  Arg2->setName("value");
+  BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
+  BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", F);
+  BasicBlock *EndBB = BasicBlock::Create(C, "if.end", F);
+
+  IRB.SetInsertPoint(EntryBB);
+  Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
+  Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getFalse(), "cmp");
+  IRB.CreateCondBr(Cmp, ThenBB, EndBB);
+
+  IRB.SetInsertPoint(ThenBB);
+  IRB.CreateStore(Arg1, ThrewGV);
+  IRB.CreateStore(Arg2, ThrewValueGV);
+  IRB.CreateBr(EndBB);
+
+  IRB.SetInsertPoint(EndBB);
+  IRB.CreateRetVoid();
+
+  // Create setTempRet0 function
+  Params = {Int32Ty};
+  FTy = FunctionType::get(VoidTy, Params, false);
+  F = Function::Create(FTy, GlobalValue::ExternalLinkage, SetTempRet0FName, &M);
+  F->arg_begin()->setName("value");
+  EntryBB = BasicBlock::Create(C, "entry", F);
+  IRB.SetInsertPoint(EntryBB);
+  IRB.CreateStore(&*F->arg_begin(), TempRet0GV);
+  IRB.CreateRetVoid();
 
   return true;
 }
@@ -832,19 +406,73 @@ bool WebAssemblyLowerEmscriptenEHSjLj::r
 
     bool NeedInvoke = AllowExceptions && canThrow(II->getCalledValue());
     if (NeedInvoke) {
-      // Wrap invoke with invoke wrapper and generate preamble/postamble
-      Value *Threw = wrapInvoke(II);
+      // If we are calling a function that is noreturn, we must remove that
+      // attribute. The code we insert here does expect it to return, after we
+      // catch the exception.
+      if (II->doesNotReturn()) {
+        if (auto *F = dyn_cast<Function>(II->getCalledValue()))
+          F->removeFnAttr(Attribute::NoReturn);
+        AttributeSet NewAttrs = II->getAttributes();
+        NewAttrs.removeAttribute(C, AttributeSet::FunctionIndex,
+                                 Attribute::NoReturn);
+        II->setAttributes(NewAttrs);
+      }
+
+      // Pre-invoke
+      // __THREW__ = 0;
+      IRB.CreateStore(IRB.getFalse(), ThrewGV);
+
+      // Invoke function wrapper in JavaScript
+      SmallVector<Value *, 16> CallArgs;
+      // Put the pointer to the callee as first argument, so it can be called
+      // within the invoke wrapper later
+      CallArgs.push_back(II->getCalledValue());
+      CallArgs.append(II->arg_begin(), II->arg_end());
+      CallInst *NewCall = IRB.CreateCall(getInvokeWrapper(M, II), CallArgs);
+      NewCall->takeName(II);
+      NewCall->setCallingConv(II->getCallingConv());
+      NewCall->setDebugLoc(II->getDebugLoc());
+
+      // Because we added the pointer to the callee as first argument, all
+      // argument attribute indices have to be incremented by one.
+      SmallVector<AttributeSet, 8> AttributesVec;
+      const AttributeSet &InvokePAL = II->getAttributes();
+      CallSite::arg_iterator AI = II->arg_begin();
+      unsigned i = 1; // Argument attribute index starts from 1
+      for (unsigned e = II->getNumArgOperands(); i <= e; ++AI, ++i) {
+        if (InvokePAL.hasAttributes(i)) {
+          AttrBuilder B(InvokePAL, i);
+          AttributesVec.push_back(AttributeSet::get(C, i + 1, B));
+        }
+      }
+      // Add any return attributes.
+      if (InvokePAL.hasAttributes(AttributeSet::ReturnIndex))
+        AttributesVec.push_back(
+            AttributeSet::get(C, InvokePAL.getRetAttributes()));
+      // Add any function attributes.
+      if (InvokePAL.hasAttributes(AttributeSet::FunctionIndex))
+        AttributesVec.push_back(
+            AttributeSet::get(C, InvokePAL.getFnAttributes()));
+      // Reconstruct the AttributesList based on the vector we constructed.
+      AttributeSet NewCallPAL = AttributeSet::get(C, AttributesVec);
+      NewCall->setAttributes(NewCallPAL);
+
+      II->replaceAllUsesWith(NewCall);
       ToErase.push_back(II);
 
+      // Post-invoke
+      // %__THREW__.val = __THREW__; __THREW__ = 0;
+      Value *Threw = IRB.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
+      IRB.CreateStore(IRB.getFalse(), ThrewGV);
+
       // Insert a branch based on __THREW__ variable
-      Value *Cmp = IRB.CreateICmpEQ(Threw, IRB.getInt32(1), "cmp");
-      IRB.CreateCondBr(Cmp, II->getUnwindDest(), II->getNormalDest());
+      IRB.CreateCondBr(Threw, II->getUnwindDest(), II->getNormalDest());
 
     } else {
       // This can't throw, and we don't need this invoke, just replace it with a
       // call+branch
-      SmallVector<Value *, 16> Args(II->arg_begin(), II->arg_end());
-      CallInst *NewCall = IRB.CreateCall(II->getCalledValue(), Args);
+      SmallVector<Value *, 16> CallArgs(II->arg_begin(), II->arg_end());
+      CallInst *NewCall = IRB.CreateCall(II->getCalledValue(), CallArgs);
       NewCall->takeName(II);
       NewCall->setCallingConv(II->getCallingConv());
       NewCall->setDebugLoc(II->getDebugLoc());
@@ -871,8 +499,11 @@ bool WebAssemblyLowerEmscriptenEHSjLj::r
       Value *Input = RI->getValue();
       IRB.SetInsertPoint(RI);
       Value *Low = IRB.CreateExtractValue(Input, 0, "low");
+
       // Create a call to __resumeException function
-      IRB.CreateCall(ResumeF, {Low});
+      Value *Args[] = {Low};
+      IRB.CreateCall(ResumeF, Args);
+
       // Add a terminator to the block
       IRB.CreateUnreachable();
       ToErase.push_back(RI);
@@ -917,7 +548,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::r
       // in the interface between JS and wasm, break out filter operands into
       // their component elements.
       if (LPI->isFilter(i)) {
-        auto *ATy = cast<ArrayType>(Clause->getType());
+        ArrayType *ATy = cast<ArrayType>(Clause->getType());
         for (unsigned j = 0, e = ATy->getNumElements(); j < e; ++j) {
           Value *EV = IRB.CreateExtractValue(Clause, makeArrayRef(j), "filter");
           FMCArgs.push_back(EV);
@@ -931,8 +562,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::r
     CallInst *FMCI = IRB.CreateCall(FMCF, FMCArgs, "fmc");
     Value *Undef = UndefValue::get(LPI->getType());
     Value *Pair0 = IRB.CreateInsertValue(Undef, FMCI, 0, "pair0");
-    Value *TempRet0 =
-        IRB.CreateLoad(TempRet0GV, TempRet0GV->getName() + ".val");
+    Value *TempRet0 = IRB.CreateLoad(TempRet0GV, TempRet0GV->getName() + "val");
     Value *Pair1 = IRB.CreateInsertValue(Pair0, TempRet0, 1, "pair1");
 
     LPI->replaceAllUsesWith(Pair1);
@@ -947,235 +577,6 @@ bool WebAssemblyLowerEmscriptenEHSjLj::r
 }
 
 bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
-  Module &M = *F.getParent();
-  LLVMContext &C = F.getContext();
-  IRBuilder<> IRB(C);
-  SmallVector<Instruction *, 64> ToErase;
-  // Vector of %setjmpTable values
-  std::vector<Instruction *> SetjmpTableInsts;
-  // Vector of %setjmpTableSize values
-  std::vector<Instruction *> SetjmpTableSizeInsts;
-
-  // Setjmp preparation
-
-  // This instruction effectively means %setjmpTableSize = 4.
-  // We create this as an instruction intentionally, and we don't want to fold
-  // this instruction to a constant 4, because this value will be used in
-  // SSAUpdater.AddAvailableValue(...) later.
-  BasicBlock &EntryBB = F.getEntryBlock();
-  BinaryOperator *SetjmpTableSize = BinaryOperator::Create(
-      Instruction::Add, IRB.getInt32(4), IRB.getInt32(0), "setjmpTableSize",
-      &*EntryBB.getFirstInsertionPt());
-  // setjmpTable = (int *) malloc(40);
-  Instruction *SetjmpTable = CallInst::CreateMalloc(
-      SetjmpTableSize, IRB.getInt32Ty(), IRB.getInt32Ty(), IRB.getInt32(40),
-      nullptr, nullptr, "setjmpTable");
-  // setjmpTable[0] = 0;
-  IRB.SetInsertPoint(SetjmpTableSize);
-  IRB.CreateStore(IRB.getInt32(0), SetjmpTable);
-  SetjmpTableInsts.push_back(SetjmpTable);
-  SetjmpTableSizeInsts.push_back(SetjmpTableSize);
-
-  // Setjmp transformation
-  std::vector<PHINode *> SetjmpRetPHIs;
-  Function *SetjmpF = M.getFunction("setjmp");
-  for (User *U : SetjmpF->users()) {
-    auto *CI = dyn_cast<CallInst>(U);
-    if (!CI)
-      report_fatal_error("Does not support indirect calls to setjmp");
-
-    BasicBlock *BB = CI->getParent();
-    if (BB->getParent() != &F) // in other function
-      continue;
-
-    // The tail is everything right after the call, and will be reached once
-    // when setjmp is called, and later when longjmp returns to the setjmp
-    BasicBlock *Tail = SplitBlock(BB, CI->getNextNode());
-    // Add a phi to the tail, which will be the output of setjmp, which
-    // indicates if this is the first call or a longjmp back. The phi directly
-    // uses the right value based on where we arrive from
-    IRB.SetInsertPoint(Tail->getFirstNonPHI());
-    PHINode *SetjmpRet = IRB.CreatePHI(IRB.getInt32Ty(), 2, "setjmp.ret");
-
-    // setjmp initial call returns 0
-    SetjmpRet->addIncoming(IRB.getInt32(0), BB);
-    // The proper output is now this, not the setjmp call itself
-    CI->replaceAllUsesWith(SetjmpRet);
-    // longjmp returns to the setjmp will add themselves to this phi
-    SetjmpRetPHIs.push_back(SetjmpRet);
-
-    // Fix call target
-    // Our index in the function is our place in the array + 1 to avoid index
-    // 0, because index 0 means the longjmp is not ours to handle.
-    IRB.SetInsertPoint(CI);
-    Value *Args[] = {CI->getArgOperand(0), IRB.getInt32(SetjmpRetPHIs.size()),
-                     SetjmpTable, SetjmpTableSize};
-    Instruction *NewSetjmpTable =
-        IRB.CreateCall(SaveSetjmpF, Args, "setjmpTable");
-    Instruction *NewSetjmpTableSize =
-        IRB.CreateLoad(TempRet0GV, "setjmpTableSize");
-    SetjmpTableInsts.push_back(NewSetjmpTable);
-    SetjmpTableSizeInsts.push_back(NewSetjmpTableSize);
-    ToErase.push_back(CI);
-  }
-
-  // Update each call that can longjmp so it can return to a setjmp where
-  // relevant.
-
-  // Because we are creating new BBs while processing and don't want to make
-  // all these newly created BBs candidates again for longjmp processing, we
-  // first make the vector of candidate BBs.
-  std::vector<BasicBlock *> BBs;
-  for (BasicBlock &BB : F)
-    BBs.push_back(&BB);
-
-  // BBs.size() will change within the loop, so we query it every time
-  for (unsigned i = 0; i < BBs.size(); i++) {
-    BasicBlock *BB = BBs[i];
-    for (Instruction &I : *BB) {
-      assert(!isa<InvokeInst>(&I));
-      auto *CI = dyn_cast<CallInst>(&I);
-      if (!CI)
-        continue;
-
-      const Value *Callee = CI->getCalledValue();
-      if (!canLongjmp(M, Callee))
-        continue;
-
-      Value *Threw = nullptr;
-      BasicBlock *Tail;
-      if (Callee->getName().startswith(InvokePrefix)) {
-        // If invoke wrapper has already been generated for this call in
-        // previous EH phase, search for the load instruction
-        // %__THREW__.val = __THREW__;
-        // in postamble after the invoke wrapper call
-        LoadInst *ThrewLI = nullptr;
-        StoreInst *ThrewResetSI = nullptr;
-        for (auto I = std::next(BasicBlock::iterator(CI)), IE = BB->end();
-             I != IE; ++I) {
-          if (auto *LI = dyn_cast<LoadInst>(I))
-            if (auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
-              if (GV == ThrewGV) {
-                Threw = ThrewLI = LI;
-                break;
-              }
-        }
-        // Search for the store instruction after the load above
-        // __THREW__ = 0;
-        for (auto I = std::next(BasicBlock::iterator(ThrewLI)), IE = BB->end();
-             I != IE; ++I) {
-          if (auto *SI = dyn_cast<StoreInst>(I))
-            if (auto *GV = dyn_cast<GlobalVariable>(SI->getPointerOperand()))
-              if (GV == ThrewGV && SI->getValueOperand() == IRB.getInt32(0)) {
-                ThrewResetSI = SI;
-                break;
-              }
-        }
-        assert(Threw && ThrewLI && "Cannot find __THREW__ load after invoke");
-        assert(ThrewResetSI && "Cannot find __THREW__ store after invoke");
-        Tail = SplitBlock(BB, ThrewResetSI->getNextNode());
-
-      } else {
-        // Wrap call with invoke wrapper and generate preamble/postamble
-        Threw = wrapInvoke(CI);
-        ToErase.push_back(CI);
-        Tail = SplitBlock(BB, CI->getNextNode());
-      }
-
-      // We need to replace the terminator in Tail - SplitBlock makes BB go
-      // straight to Tail, we need to check if a longjmp occurred, and go to the
-      // right setjmp-tail if so
-      ToErase.push_back(BB->getTerminator());
-
-      // Generate a function call to testSetjmp function and preamble/postamble
-      // code to figure out (1) whether longjmp occurred (2) if longjmp
-      // occurred, which setjmp it corresponds to
-      Value *Label = nullptr;
-      Value *LongjmpResult = nullptr;
-      BasicBlock *EndBB = nullptr;
-      wrapTestSetjmp(BB, CI, Threw, SetjmpTable, SetjmpTableSize, Label,
-                     LongjmpResult, EndBB);
-      assert(Label && LongjmpResult && EndBB);
-
-      // Create switch instruction
-      IRB.SetInsertPoint(EndBB);
-      SwitchInst *SI = IRB.CreateSwitch(Label, Tail, SetjmpRetPHIs.size());
-      // -1 means no longjmp happened, continue normally (will hit the default
-      // switch case). 0 means a longjmp that is not ours to handle, needs a
-      // rethrow. Otherwise the index is the same as the index in P+1 (to avoid
-      // 0).
-      for (unsigned i = 0; i < SetjmpRetPHIs.size(); i++) {
-        SI->addCase(IRB.getInt32(i + 1), SetjmpRetPHIs[i]->getParent());
-        SetjmpRetPHIs[i]->addIncoming(LongjmpResult, EndBB);
-      }
-
-      // We are splitting the block here, and must continue to find other calls
-      // in the block - which is now split. so continue to traverse in the Tail
-      BBs.push_back(Tail);
-    }
-  }
-
-  // Erase everything we no longer need in this function
-  for (Instruction *I : ToErase)
-    I->eraseFromParent();
-
-  // Free setjmpTable buffer before each return instruction
-  for (BasicBlock &BB : F) {
-    TerminatorInst *TI = BB.getTerminator();
-    if (isa<ReturnInst>(TI))
-      CallInst::CreateFree(SetjmpTable, TI);
-  }
-
-  // Every call to saveSetjmp can change setjmpTable and setjmpTableSize
-  // (when buffer reallocation occurs)
-  // entry:
-  //   setjmpTableSize = 4;
-  //   setjmpTable = (int *) malloc(40);
-  //   setjmpTable[0] = 0;
-  // ...
-  // somebb:
-  //   setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
-  //   setjmpTableSize = __tempRet0;
-  // So we need to make sure the SSA for these variables is valid so that every
-  // saveSetjmp and testSetjmp calls have the correct arguments.
-  SSAUpdater SetjmpTableSSA;
-  SSAUpdater SetjmpTableSizeSSA;
-  SetjmpTableSSA.Initialize(Type::getInt32PtrTy(C), "setjmpTable");
-  SetjmpTableSizeSSA.Initialize(Type::getInt32Ty(C), "setjmpTableSize");
-  for (Instruction *I : SetjmpTableInsts)
-    SetjmpTableSSA.AddAvailableValue(I->getParent(), I);
-  for (Instruction *I : SetjmpTableSizeInsts)
-    SetjmpTableSizeSSA.AddAvailableValue(I->getParent(), I);
-
-  for (auto UI = SetjmpTable->use_begin(), UE = SetjmpTable->use_end();
-       UI != UE;) {
-    // Grab the use before incrementing the iterator.
-    Use &U = *UI;
-    // Increment the iterator before removing the use from the list.
-    ++UI;
-    if (Instruction *I = dyn_cast<Instruction>(U.getUser()))
-      if (I->getParent() != &EntryBB)
-        SetjmpTableSSA.RewriteUse(U);
-  }
-  for (auto UI = SetjmpTableSize->use_begin(), UE = SetjmpTableSize->use_end();
-       UI != UE;) {
-    Use &U = *UI;
-    ++UI;
-    if (Instruction *I = dyn_cast<Instruction>(U.getUser()))
-      if (I->getParent() != &EntryBB)
-        SetjmpTableSizeSSA.RewriteUse(U);
-  }
-
-  // Finally, our modifications to the cfg can break dominance of SSA variables.
-  // For example, in this code,
-  // if (x()) { .. setjmp() .. }
-  // if (y()) { .. longjmp() .. }
-  // We must split the longjmp block, and it can jump into the block splitted
-  // from setjmp one. But that means that when we split the setjmp block, it's
-  // first part no longer dominates its second part - there is a theoretically
-  // possible control flow path where x() is false, then y() is true and we
-  // reach the second part of the setjmp block, without ever reaching the first
-  // part. So, we rebuild SSA form here.
-  rebuildSSA(F);
-  return true;
+  // TODO
+  return false;
 }

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp?rev=280329&r1=280328&r2=280329&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp Wed Aug 31 19:44:37 2016
@@ -165,14 +165,7 @@ void WebAssemblyPassConfig::addIRPasses(
   if (getOptLevel() != CodeGenOpt::None)
     addPass(createWebAssemblyOptimizeReturned());
 
-  // If exception handling is not enabled, we lower invokes into calls and
-  // simplify CFG to delete unreachable landingpad blocks.
-  if (!EnableEmException) {
-    addPass(createLowerInvokePass());
-    addPass(createCFGSimplificationPass());
-  }
-
-  // Handle exceptions and setjmp/longjmp if enabled.
+  // Handle exceptions.
   if (EnableEmException || EnableEmSjLj)
     addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException,
                                                    EnableEmSjLj));

Removed: llvm/trunk/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll?rev=280328&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll (removed)
@@ -1,61 +0,0 @@
-; RUN: llc < %s -enable-emscripten-cxx-exceptions | FileCheck %s --check-prefix=EH
-; RUN: llc < %s -enable-emscripten-sjlj | FileCheck %s --check-prefix=SJLJ
-; RUN: llc < %s | FileCheck %s --check-prefix=NONE
-
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
-
-%struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] }
-
-define hidden void @exception() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
-; EH-LABEL:   type exception, at function
-; NONE-LABEL: type exception, at function
-entry:
-  invoke void @foo()
-          to label %try.cont unwind label %lpad
-; EH:   call __invoke_void at FUNCTION
-; NONE: call foo at FUNCTION
-
-lpad:                                             ; preds = %entry
-  %0 = landingpad { i8*, i32 }
-          catch i8* null
-  %1 = extractvalue { i8*, i32 } %0, 0
-  %2 = extractvalue { i8*, i32 } %0, 1
-  %3 = call i8* @__cxa_begin_catch(i8* %1) #2
-  call void @__cxa_end_catch()
-  br label %try.cont
-
-try.cont:                                         ; preds = %entry, %lpad
-  ret void
-}
-
-define hidden void @setjmp_longjmp() {
-; SJLJ-LABEL: type setjmp_longjmp, at function
-; NONE-LABEL: type setjmp_longjmp, at function
-entry:
-  %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
-  %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
-  %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
-  %arraydecay1 = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
-  call void @longjmp(%struct.__jmp_buf_tag* %arraydecay1, i32 1) #1
-  unreachable
-; SJLJ: i32.call ${{[a-zA-Z0-9]+}}=, saveSetjmp at FUNCTION
-; SJLJ: i32.call ${{[a-zA-Z0-9]+}}=, testSetjmp at FUNCTION
-; NONE: i32.call ${{[a-zA-Z0-9]+}}=, setjmp at FUNCTION
-; NONE: call longjmp at FUNCTION
-}
-
-declare void @foo()
-declare i32 @__gxx_personality_v0(...)
-declare i8* @__cxa_begin_catch(i8*)
-declare void @__cxa_end_catch()
-; Function Attrs: returns_twice
-declare i32 @setjmp(%struct.__jmp_buf_tag*) #0
-; Function Attrs: noreturn
-declare void @longjmp(%struct.__jmp_buf_tag*, i32) #1
-declare i8* @malloc(i32)
-declare void @free(i8*)
-
-attributes #0 = { returns_twice }
-attributes #1 = { noreturn }
-attributes #2 = { nounwind }

Modified: llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll?rev=280329&r1=280328&r2=280329&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll Wed Aug 31 19:44:37 2016
@@ -1,8 +1,5 @@
 ; RUN: opt < %s -wasm-lower-em-ehsjlj -emscripten-cxx-exceptions-whitelist=do_catch -S | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
-
 define void @dont_catch() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
 ; CHECK-LABEL: @dont_catch(
 entry:
@@ -37,7 +34,7 @@ entry:
   invoke void @foo()
           to label %invoke.cont unwind label %lpad
 ; CHECK: entry:
-; CHECK-NEXT: store i32 0, i32*
+; CHECK-NEXT: store i1 false, i1*
 ; CHECK-NEXT: call void @__invoke_void(void ()* @foo)
 
 invoke.cont:                                      ; preds = %entry

Modified: llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll?rev=280329&r1=280328&r2=280329&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll Wed Aug 31 19:44:37 2016
@@ -1,13 +1,10 @@
 ; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s
 
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
-
 @_ZTIi = external constant i8*
 @_ZTIc = external constant i8*
-; CHECK-DAG: @[[__THREW__:__THREW__.*]] = global i32 0
-; CHECK-DAG: @[[THREWVALUE:__threwValue.*]] = global i32 0
-; CHECK-DAG: @[[TEMPRET0:__tempRet0.*]] = global i32 0
+; CHECK: @[[__THREW__:__THREW__.*]] = global i1 false
+; CHECK: @[[THREWVALUE:__threwValue.*]] = global i32 0
+; CHECK: @[[TEMPRET0:__tempRet0.*]] = global i32 0
 
 ; Test invoke instruction with clauses (try-catch block)
 define void @clause() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
@@ -16,12 +13,11 @@ entry:
   invoke void @foo(i32 3)
           to label %invoke.cont unwind label %lpad
 ; CHECK: entry:
-; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: store i1 false, i1* @[[__THREW__]]
 ; CHECK-NEXT: call void @__invoke_void_i32(void (i32)* @foo, i32 3)
-; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]]
-; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
-; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__VAL]], 1
-; CHECK-NEXT: br i1 %cmp, label %lpad, label %invoke.cont
+; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i1, i1* @[[__THREW__]]
+; CHECK-NEXT: store i1 false, i1* @[[__THREW__]]
+; CHECK-NEXT: br i1 %[[__THREW__VAL]], label %lpad, label %invoke.cont
 
 invoke.cont:                                      ; preds = %entry
   br label %try.cont
@@ -72,12 +68,11 @@ entry:
   invoke void @foo(i32 3)
           to label %invoke.cont unwind label %lpad
 ; CHECK: entry:
-; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: store i1 false, i1* @[[__THREW__]]
 ; CHECK-NEXT: call void @__invoke_void_i32(void (i32)* @foo, i32 3)
-; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]]
-; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
-; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__VAL]], 1
-; CHECK-NEXT: br i1 %cmp, label %lpad, label %invoke.cont
+; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i1, i1* @[[__THREW__]]
+; CHECK-NEXT: store i1 false, i1* @[[__THREW__]]
+; CHECK-NEXT: br i1 %[[__THREW__VAL]], label %lpad, label %invoke.cont
 
 invoke.cont:                                      ; preds = %entry
   ret void
@@ -123,7 +118,7 @@ entry:
   %0 = invoke noalias i8* @bar(i8 signext 1, i8 zeroext 2)
           to label %invoke.cont unwind label %lpad
 ; CHECK: entry:
-; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
+; CHECK-NEXT: store i1 false, i1* @[[__THREW__]]
 ; CHECK-NEXT: %0 = call noalias i8* @"__invoke_i8*_i8_i8"(i8* (i8, i8)* @bar, i8 signext 1, i8 zeroext 2)
 
 invoke.cont:                                      ; preds = %entry
@@ -167,19 +162,19 @@ declare i8* @__cxa_begin_catch(i8*)
 declare void @__cxa_end_catch()
 declare void @__cxa_call_unexpected(i8*)
 
-; JS glue functions and invoke wrappers declaration
-; CHECK-DAG: declare void @__resumeException(i8*)
-; CHECK-DAG: declare void @__invoke_void_i32(void (i32)*, i32)
-; CHECK-DAG: declare i8* @__cxa_find_matching_catch_4(i8*, i8*)
+; JS glue functions and invoke wrappers registration
+; CHECK: declare void @__resumeException(i8*)
+; CHECK: declare void @__invoke_void_i32(void (i32)*, i32)
+; CHECK: declare i8* @__cxa_find_matching_catch_4(i8*, i8*)
 
 ; setThrew function creation
-; CHECK-LABEL: define void @setThrew(i32 %threw, i32 %value) {
+; CHECK-LABEL: define void @setThrew(i1 %threw, i32 %value) {
 ; CHECK: entry:
-; CHECK-NEXT: %[[__THREW__]].val = load i32, i32* @[[__THREW__]]
-; CHECK-NEXT: %cmp = icmp eq i32 %[[__THREW__]].val, 0
+; CHECK-NEXT: %[[__THREW__]].val = load i1, i1* @[[__THREW__]]
+; CHECK-NEXT: %cmp = icmp eq i1 %[[__THREW__]].val, false
 ; CHECK-NEXT: br i1 %cmp, label %if.then, label %if.end
 ; CHECK: if.then:
-; CHECK-NEXT: store i32 %threw, i32* @[[__THREW__]]
+; CHECK-NEXT: store i1 %threw, i1* @[[__THREW__]]
 ; CHECK-NEXT: store i32 %value, i32* @[[THREWVALUE]]
 ; CHECK-NEXT: br label %if.end
 ; CHECK: if.end:

Removed: llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll?rev=280328&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll (removed)
@@ -1,213 +0,0 @@
-; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s
-
-target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
-
-%struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] }
-
- at global_var = hidden global i32 0, align 4
-; CHECK-DAG: @[[__THREW__:__THREW__.*]] = global i32 0
-; CHECK-DAG: @[[THREWVALUE:__threwValue.*]] = global i32 0
-; CHECK-DAG: @[[TEMPRET0:__tempRet0.*]] = global i32 0
-
-; Test a simple setjmp - longjmp sequence
-define hidden void @setjmp_longjmp() {
-; CHECK-LABEL: @setjmp_longjmp
-entry:
-  %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
-  %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
-  %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
-  %arraydecay1 = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
-  call void @longjmp(%struct.__jmp_buf_tag* %arraydecay1, i32 1) #1
-  unreachable
-; CHECK: entry:
-; CHECK-NEXT: %[[MALLOCCALL:.*]] = tail call i8* @malloc(i32 40)
-; CHECK-NEXT: %[[SETJMP_TABLE:.*]] = bitcast i8* %[[MALLOCCALL]] to i32*
-; CHECK-NEXT: store i32 0, i32* %[[SETJMP_TABLE]]
-; CHECK-NEXT: %[[SETJMP_TABLE_SIZE:.*]] = add i32 4, 0
-; CHECK-NEXT: %[[BUF:.*]] = alloca [1 x %struct.__jmp_buf_tag]
-; CHECK-NEXT: %[[ARRAYDECAY:.*]] = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %[[BUF]], i32 0, i32 0
-; CHECK-NEXT: %[[SETJMP_TABLE1:.*]] = call i32* @saveSetjmp(%struct.__jmp_buf_tag* %[[ARRAYDECAY]], i32 1, i32* %[[SETJMP_TABLE]], i32 %[[SETJMP_TABLE_SIZE]])
-; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = load i32, i32* @[[TEMPRET0]]
-; CHECK-NEXT: br label %entry.split
-
-; CHECK: entry.split:
-; CHECK-NEXT: phi i32 [ 0, %entry ], [ %[[LONGJMP_RESULT:.*]], %if.end ]
-; CHECK-NEXT: %[[ARRAYDECAY1:.*]] = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %[[BUF]], i32 0, i32 0
-; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
-; CHECK-NEXT: call void @"__invoke_void_%struct.__jmp_buf_tag*_i32"(void (%struct.__jmp_buf_tag*, i32)* @emscripten_longjmp_jmpbuf, %struct.__jmp_buf_tag* %[[ARRAYDECAY1]], i32 1)
-; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]]
-; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
-; CHECK-NEXT: %[[CMP0:.*]] = icmp ne i32 %__THREW__.val, 0
-; CHECK-NEXT: %[[THREWVALUE_VAL:.*]] = load i32, i32* @[[THREWVALUE]]
-; CHECK-NEXT: %[[CMP1:.*]] = icmp ne i32 %[[THREWVALUE_VAL]], 0
-; CHECK-NEXT: %[[CMP:.*]] = and i1 %[[CMP0]], %[[CMP1]]
-; CHECK-NEXT: br i1 %[[CMP]], label %if.then1, label %if.else1
-
-; CHECK: entry.split.split:
-; CHECK-NEXT: unreachable
-
-; CHECK: if.then1:
-; CHECK-NEXT: %[[__THREW__VAL_I32P:.*]] = inttoptr i32 %[[__THREW__VAL]] to i32*
-; CHECK-NEXT: %[[__THREW__VAL_I32P_LOADED:.*]] = load i32, i32* %[[__THREW__VAL_I32P]]
-; CHECK-NEXT: %[[LABEL:.*]] = call i32 @testSetjmp(i32 %[[__THREW__VAL_I32P_LOADED]], i32* %[[SETJMP_TABLE1]], i32 %[[SETJMP_TABLE_SIZE1]])
-; CHECK-NEXT: %[[CMP:.*]] = icmp eq i32 %[[LABEL]], 0
-; CHECK-NEXT: br i1 %[[CMP]], label %if.then2, label %if.end2
-
-; CHECK: if.else1:
-; CHECK-NEXT: br label %if.end
-
-; CHECK: if.end:
-; CHECK-NEXT: %[[LABEL_PHI:.*]] = phi i32 [ %[[LABEL:.*]], %if.end2 ], [ -1, %if.else1 ]
-; CHECK-NEXT: %[[LONGJMP_RESULT]] = load i32, i32* @[[TEMPRET0]]
-; CHECK-NEXT: switch i32 %[[LABEL_PHI]], label %entry.split.split [
-; CHECK-NEXT:   i32 1, label %entry.split
-; CHECK-NEXT: ]
-
-; CHECK: if.then2:
-; CHECK-NEXT: call void @emscripten_longjmp(i32 %[[__THREW__VAL]], i32 %[[THREWVALUE_VAL]])
-; CHECK-NEXT: unreachable
-
-; CHECK: if.end2:
-; CHECK-NEXT: store i32 %[[THREWVALUE_VAL]], i32* @[[TEMPRET0]]
-; CHECK-NEXT: br label %if.end
-}
-
-; Test a case of a function call (which is not longjmp) after a setjmp
-define hidden void @setjmp_other() {
-; CHECK-LABEL: @setjmp_other
-entry:
-  %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
-  %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
-  %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
-  call void @foo()
-  ret void
-; CHECK: entry:
-; CHECK: %[[SETJMP_TABLE:.*]] = call i32* @saveSetjmp(
-
-; CHECK: entry.split:
-; CHECK: call void @__invoke_void(void ()* @foo)
-
-; CHECK: entry.split.split:
-; CHECK-NEXT: %[[BUF:.*]] = bitcast i32* %[[SETJMP_TABLE]] to i8*
-; CHECK-NEXT: tail call void @free(i8* %[[BUF]])
-; CHECK-NEXT: ret void
-}
-
-; Test a case when a function call is within try-catch, after a setjmp
-define hidden void @exception_and_longjmp() #3 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
-; CHECK-LABEL: @exception_and_longjmp
-entry:
-  %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
-  %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
-  %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
-  invoke void @foo()
-          to label %try.cont unwind label %lpad
-
-; CHECK: entry.split:
-; CHECK: store i32 0, i32* @[[__THREW__]]
-; CHECK-NEXT: call void @__invoke_void(void ()* @foo)
-; CHECK-NEXT: %[[__THREW__VAL:.*]] = load i32, i32* @[[__THREW__]]
-; CHECK-NEXT: store i32 0, i32* @[[__THREW__]]
-; CHECK-NEXT: %[[CMP0:.*]] = icmp ne i32 %[[__THREW__VAL]], 0
-; CHECK-NEXT: %[[THREWVALUE_VAL:.*]] = load i32, i32* @[[THREWVALUE]]
-; CHECK-NEXT: %[[CMP1:.*]] = icmp ne i32 %[[THREWVALUE_VAL]], 0
-; CHECK-NEXT: %[[CMP:.*]] = and i1 %[[CMP0]], %[[CMP1]]
-; CHECK-NEXT: br i1 %[[CMP]], label %if.then1, label %if.else1
-
-; CHECK: entry.split.split:
-; CHECK-NEXT: %[[CMP:.*]] = icmp eq i32 %[[__THREW__VAL]], 1
-; CHECK-NEXT: br i1 %[[CMP]], label %lpad, label %try.cont
-
-lpad:                                             ; preds = %entry
-  %0 = landingpad { i8*, i32 }
-          catch i8* null
-  %1 = extractvalue { i8*, i32 } %0, 0
-  %2 = extractvalue { i8*, i32 } %0, 1
-  %3 = call i8* @__cxa_begin_catch(i8* %1) #2
-  call void @__cxa_end_catch()
-  br label %try.cont
-
-try.cont:                                         ; preds = %entry, %lpad
-  ret void
-}
-
-; Test SSA validity
-define hidden void @ssa(i32 %n) {
-; CHECK-LABEL: @ssa
-entry:
-  %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
-  %cmp = icmp sgt i32 %n, 5
-  br i1 %cmp, label %if.then, label %if.end
-; CHECK: entry:
-; CHECK: %[[SETJMP_TABLE0:.*]] = bitcast i8*
-; CHECK: %[[SETJMP_TABLE_SIZE0:.*]] = add i32 4, 0
-
-if.then:                                          ; preds = %entry
-  %0 = load i32, i32* @global_var, align 4
-  %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
-  %call = call i32 @setjmp(%struct.__jmp_buf_tag* %arraydecay) #0
-  store i32 %0, i32* @global_var, align 4
-  br label %if.end
-; CHECK: if.then:
-; CHECK: %[[VAR0:.*]] = load i32, i32* @global_var, align 4
-; CHECK: %[[SETJMP_TABLE1:.*]] = call i32* @saveSetjmp(
-; CHECK-NEXT: %[[SETJMP_TABLE_SIZE1:.*]] = load i32, i32* @[[TEMPRET0]]
-
-; CHECK: if.then.split:
-; CHECK: %[[VAR1:.*]] = phi i32 [ %[[VAR0]], %if.then ], [ %[[VAR2:.*]], %if.end3 ]
-; CHECK: %[[SETJMP_TABLE_SIZE2:.*]] = phi i32 [ %[[SETJMP_TABLE_SIZE1]], %if.then ], [ %[[SETJMP_TABLE_SIZE3:.*]], %if.end3 ]
-; CHECK: %[[SETJMP_TABLE2:.*]] = phi i32* [ %[[SETJMP_TABLE1]], %if.then ], [ %[[SETJMP_TABLE3:.*]], %if.end3 ]
-; CHECK: store i32 %[[VAR1]], i32* @global_var, align 4
-
-if.end:                                           ; preds = %if.then, %entry
-  %arraydecay1 = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
-  call void @longjmp(%struct.__jmp_buf_tag* %arraydecay1, i32 5) #1
-  unreachable
-; CHECK: if.end:
-; CHECK: %[[VAR2]] = phi i32 [ %[[VAR1]], %if.then.split ], [ undef, %entry ]
-; CHECK: %[[SETJMP_TABLE_SIZE3]] = phi i32 [ %[[SETJMP_TABLE_SIZE2]], %if.then.split ], [ %[[SETJMP_TABLE_SIZE0]], %entry ]
-; CHECK: %[[SETJMP_TABLE3]] = phi i32* [ %[[SETJMP_TABLE2]], %if.then.split ], [ %[[SETJMP_TABLE0]], %entry ]
-}
-
-; Test a case when a function only calls other functions that are neither setjmp nor longjmp
-define hidden void @only_other_func() {
-entry:
-  call void @foo()
-  ret void
-; CHECK: call void @foo()
-}
-
-; Test a case when a function only calls longjmp and not setjmp
-define hidden void @only_longjmp() {
-entry:
-  %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
-  %arraydecay = getelementptr inbounds [1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* %buf, i32 0, i32 0
-  call void @longjmp(%struct.__jmp_buf_tag* %arraydecay, i32 5) #1
-  unreachable
-; CHECK: %[[ARRAYDECAY:.*]] = getelementptr inbounds
-; CHECK-NEXT: call void @emscripten_longjmp_jmpbuf(%struct.__jmp_buf_tag* %[[ARRAYDECAY]], i32 5) #1
-}
-
-declare void @foo()
-; Function Attrs: returns_twice
-declare i32 @setjmp(%struct.__jmp_buf_tag*) #0
-; Function Attrs: noreturn
-declare void @longjmp(%struct.__jmp_buf_tag*, i32) #1
-declare i32 @__gxx_personality_v0(...)
-declare i8* @__cxa_begin_catch(i8*)
-declare void @__cxa_end_catch()
-declare i8* @malloc(i32)
-declare void @free(i8*)
-
-; JS glue functions and invoke wrappers declaration
-; CHECK-DAG: declare i32* @saveSetjmp(%struct.__jmp_buf_tag*, i32, i32*, i32)
-; CHECK-DAG: declare i32 @testSetjmp(i32, i32*, i32)
-; CHECK-DAG: declare void @emscripten_longjmp_jmpbuf(%struct.__jmp_buf_tag*, i32)
-; CHECK-DAG: declare void @emscripten_longjmp(i32, i32)
-; CHECK-DAG: declare void @__invoke_void(void ()*)
-; CHECK-DAG: declare void @"__invoke_void_%struct.__jmp_buf_tag*_i32"(void (%struct.__jmp_buf_tag*, i32)*, %struct.__jmp_buf_tag*, i32)
-
-attributes #0 = { returns_twice }
-attributes #1 = { noreturn }
-attributes #2 = { nounwind }




More information about the llvm-commits mailing list