[llvm] r352598 - [WebAssembly] Exception handling: Switch to the new proposal

Heejin Ahn via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 29 19:21:57 PST 2019


Author: aheejin
Date: Tue Jan 29 19:21:57 2019
New Revision: 352598

URL: http://llvm.org/viewvc/llvm-project?rev=352598&view=rev
Log:
[WebAssembly] Exception handling: Switch to the new proposal

Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
 https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)

- Instruction changes
  - Now we have one single `catch` instruction that returns a except_ref
    value
  - `throw` now can take variable number of operations
  - `rethrow` does not have 'depth' argument anymore
  - `br_on_exn` queries an except_ref to see if it matches the tag and
    branches to the given label if true.
  - `extract_exception` is a pseudo instruction that simulates popping
    values from wasm stack. This is to make `br_on_exn`, a very special
    instruction, work: `br_on_exn` puts values onto the stack only if it
    is taken, and the # of values can vay depending on the tag.

- Now there's only one `catch` per `try`, this patch removes all special
  handling for terminate pad with a call to `__clang_call_terminate`.
  Before it was the only case there are two catch clauses (a normal
  `catch` and `catch_all` per `try`).

- Make `rethrow` act as a terminator like `throw`. This splits BB after
  `rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
  after `rethrow` in LateEHPrepare.

- Now we stop at all catchpads (because we add wasm `catch` instruction
  that catches all exceptions), this creates new
  `findWasmUnwindDestinations` function in SelectionDAGBuilder.

- Now we use `br_on_exn` instrution to figure out if an except_ref
  matches the current tag or not, LateEHPrepare generates this sequence
  for catch pads:
```
  catch
  block i32
  br_on_exn $__cpp_exception
  end_block
  extract_exception
```

- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo

- Other various misc. changes to switch to the new proposal.

Reviewers: dschuff

Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits

Differential Revision: https://reviews.llvm.org/D57134

Added:
    llvm/trunk/test/MC/WebAssembly/annotations.s
Removed:
    llvm/trunk/test/CodeGen/WebAssembly/annotations.mir
    llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.mir
Modified:
    llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td
    llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp
    llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
    llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp
    llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h
    llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
    llvm/trunk/test/CodeGen/WebAssembly/exception.ll
    llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll
    llvm/trunk/test/MC/WebAssembly/basic-assembly.s
    llvm/trunk/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp

Modified: llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td (original)
+++ llvm/trunk/include/llvm/IR/IntrinsicsWebAssembly.td Tue Jan 29 19:21:57 2019
@@ -49,11 +49,12 @@ def int_wasm_get_exception : Intrinsic<[
                                        [IntrHasSideEffects]>;
 def int_wasm_get_ehselector : Intrinsic<[llvm_i32_ty], [llvm_token_ty],
                                         [IntrHasSideEffects]>;
-
-// wasm.catch returns the pointer to the exception object caught by wasm 'catch'
-// instruction.
-def int_wasm_catch : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty],
-                               [IntrHasSideEffects]>;
+// This is the same as llvm.wasm.get.exception except that it does not take a
+// token operand. This is only for instruction selection purpose.
+// TODO Remove this redundant intrinsic and do custom lowering on
+// int_wasm_get_exception instead
+def int_wasm_extract_exception : Intrinsic<[llvm_ptr_ty], [],
+                                           [IntrHasSideEffects]>;
 
 // WebAssembly EH must maintain the landingpads in the order assigned to them
 // by WasmEHPrepare pass to generate landingpad table in EHStreamer. This is

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/WasmException.cpp Tue Jan 29 19:21:57 2019
@@ -18,10 +18,10 @@
 using namespace llvm;
 
 void WasmException::endModule() {
-  // This is the symbol used in 'throw' and 'if_except' instruction to denote
+  // This is the symbol used in 'throw' and 'br_on_exn' instruction to denote
   // this is a C++ exception. This symbol has to be emitted somewhere once in
   // the module.  Check if the symbol has already been created, i.e., we have at
-  // least one 'throw' or 'if_except' instruction in the module, and emit the
+  // least one 'throw' or 'br_on_exn' instruction in the module, and emit the
   // symbol only if so.
   SmallString<60> NameStr;
   Mangler::getNameWithPrefix(NameStr, "__cpp_exception", Asm->getDataLayout());

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Tue Jan 29 19:21:57 2019
@@ -1456,6 +1456,36 @@ void SelectionDAGBuilder::visitCleanupPa
   }
 }
 
+// For wasm, there's alwyas a single catch pad attached to a catchswitch, and
+// the control flow always stops at the single catch pad, as it does for a
+// cleanup pad. In case the exception caught is not of the types the catch pad
+// catches, it will be rethrown by a rethrow.
+static void findWasmUnwindDestinations(
+    FunctionLoweringInfo &FuncInfo, const BasicBlock *EHPadBB,
+    BranchProbability Prob,
+    SmallVectorImpl<std::pair<MachineBasicBlock *, BranchProbability>>
+        &UnwindDests) {
+  while (EHPadBB) {
+    const Instruction *Pad = EHPadBB->getFirstNonPHI();
+    if (isa<CleanupPadInst>(Pad)) {
+      // Stop on cleanup pads.
+      UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob);
+      UnwindDests.back().first->setIsEHScopeEntry();
+      break;
+    } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) {
+      // Add the catchpad handlers to the possible destinations. We don't
+      // continue to the unwind destination of the catchswitch for wasm.
+      for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) {
+        UnwindDests.emplace_back(FuncInfo.MBBMap[CatchPadBB], Prob);
+        UnwindDests.back().first->setIsEHScopeEntry();
+      }
+      break;
+    } else {
+      continue;
+    }
+  }
+}
+
 /// When an invoke or a cleanupret unwinds to the next EH pad, there are
 /// many places it could ultimately go. In the IR, we have a single unwind
 /// destination, but in the machine CFG, we enumerate all the possible blocks.
@@ -1476,6 +1506,11 @@ static void findUnwindDestinations(
   bool IsWasmCXX = Personality == EHPersonality::Wasm_CXX;
   bool IsSEH = isAsynchronousEHPersonality(Personality);
 
+  if (IsWasmCXX) {
+    findWasmUnwindDestinations(FuncInfo, EHPadBB, Prob, UnwindDests);
+    return;
+  }
+
   while (EHPadBB) {
     const Instruction *Pad = EHPadBB->getFirstNonPHI();
     BasicBlock *NewEHPadBB = nullptr;
@@ -1488,8 +1523,7 @@ static void findUnwindDestinations(
       // personalities.
       UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob);
       UnwindDests.back().first->setIsEHScopeEntry();
-      if (!IsWasmCXX)
-        UnwindDests.back().first->setIsEHFuncletEntry();
+      UnwindDests.back().first->setIsEHFuncletEntry();
       break;
     } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) {
       // Add the catchpad handlers to the possible destinations.

Modified: llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp (original)
+++ llvm/trunk/lib/CodeGen/WasmEHPrepare.cpp Tue Jan 29 19:21:57 2019
@@ -7,7 +7,8 @@
 //===----------------------------------------------------------------------===//
 //
 // This transformation is designed for use by code generators which use
-// WebAssembly exception handling scheme.
+// WebAssembly exception handling scheme. This currently supports C++
+// exceptions.
 //
 // WebAssembly exception handling uses Windows exception IR for the middle level
 // representation. This pass does the following transformation for every
@@ -22,53 +23,20 @@
 //
 // - After:
 //   catchpad ...
-//   exn = wasm.catch(0); // 0 is a tag for C++
-//   wasm.landingpad.index(index);
+//   exn = wasm.extract.exception();
 //   // Only add below in case it's not a single catch (...)
+//   wasm.landingpad.index(index);
 //   __wasm_lpad_context.lpad_index = index;
 //   __wasm_lpad_context.lsda = wasm.lsda();
 //   _Unwind_CallPersonality(exn);
-//   int selector = __wasm.landingpad_context.selector;
+//   selector = __wasm.landingpad_context.selector;
 //   ...
 //
-// Also, does the following for a cleanuppad block with a call to
-// __clang_call_terminate():
-// - Before:
-//   cleanuppad ...
-//   exn = wasm.get.exception();
-//   __clang_call_terminate(exn);
-//
-// - After:
-//   cleanuppad ...
-//   exn = wasm.catch(0); // 0 is a tag for C++
-//   __clang_call_terminate(exn);
-//
-//
-// * Background: WebAssembly EH instructions
-// WebAssembly's try and catch instructions are structured as follows:
-// try
-//   instruction*
-// catch (C++ tag)
-//   instruction*
-// ...
-// catch_all
-//   instruction*
-// try_end
-//
-// A catch instruction in WebAssembly does not correspond to a C++ catch clause.
-// In WebAssembly, there is a single catch instruction for all C++ exceptions.
-// There can be more catch instructions for exceptions in other languages, but
-// they are not generated for now. catch_all catches all exceptions including
-// foreign exceptions (e.g. JavaScript). We turn catchpads into catch (C++ tag)
-// and cleanuppads into catch_all, with one exception: cleanuppad with a call to
-// __clang_call_terminate should be both in catch (C++ tag) and catch_all.
-//
 //
 // * Background: Direct personality function call
 // In WebAssembly EH, the VM is responsible for unwinding the stack once an
 // exception is thrown. After the stack is unwound, the control flow is
-// transfered to WebAssembly 'catch' instruction, which returns a caught
-// exception object.
+// transfered to WebAssembly 'catch' instruction.
 //
 // Unwinding the stack is not done by libunwind but the VM, so the personality
 // function in libcxxabi cannot be called from libunwind during the unwinding
@@ -137,18 +105,18 @@ class WasmEHPrepare : public FunctionPas
   Value *SelectorField = nullptr;  // selector
 
   Function *ThrowF = nullptr;           // wasm.throw() intrinsic
-  Function *CatchF = nullptr;           // wasm.catch.extract() intrinsic
+  Function *RethrowF = nullptr;         // wasm.rethrow() intrinsic
   Function *LPadIndexF = nullptr;       // wasm.landingpad.index() intrinsic
   Function *LSDAF = nullptr;            // wasm.lsda() intrinsic
   Function *GetExnF = nullptr;          // wasm.get.exception() intrinsic
+  Function *ExtractExnF = nullptr;      // wasm.extract.exception() intrinsic
   Function *GetSelectorF = nullptr;     // wasm.get.ehselector() intrinsic
   Function *CallPersonalityF = nullptr; // _Unwind_CallPersonality() wrapper
-  Function *ClangCallTermF = nullptr;   // __clang_call_terminate() function
 
   bool prepareEHPads(Function &F);
   bool prepareThrows(Function &F);
 
-  void prepareEHPad(BasicBlock *BB, unsigned Index);
+  void prepareEHPad(BasicBlock *BB, bool NeedLSDA, unsigned Index = 0);
   void prepareTerminateCleanupPad(BasicBlock *BB);
 
 public:
@@ -208,25 +176,29 @@ bool WasmEHPrepare::prepareThrows(Functi
 
   // wasm.throw() intinsic, which will be lowered to wasm 'throw' instruction.
   ThrowF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_throw);
-
-  // Insert an unreachable instruction after a call to @llvm.wasm.throw and
-  // delete all following instructions within the BB, and delete all the dead
-  // children of the BB as well.
-  for (User *U : ThrowF->users()) {
-    // A call to @llvm.wasm.throw() is only generated from
-    // __builtin_wasm_throw() builtin call within libcxxabi, and cannot be an
-    // InvokeInst.
-    auto *ThrowI = cast<CallInst>(U);
-    if (ThrowI->getFunction() != &F)
-      continue;
-    Changed = true;
-    auto *BB = ThrowI->getParent();
-    SmallVector<BasicBlock *, 4> Succs(succ_begin(BB), succ_end(BB));
-    auto &InstList = BB->getInstList();
-    InstList.erase(std::next(BasicBlock::iterator(ThrowI)), InstList.end());
-    IRB.SetInsertPoint(BB);
-    IRB.CreateUnreachable();
-    eraseDeadBBsAndChildren(Succs);
+  // wasm.rethrow() intinsic, which will be lowered to wasm 'rethrow'
+  // instruction.
+  RethrowF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_rethrow);
+
+  // Insert an unreachable instruction after a call to @llvm.wasm.throw /
+  // @llvm.wasm.rethrow and delete all following instructions within the BB, and
+  // delete all the dead children of the BB as well.
+  for (auto L : {ThrowF->users(), RethrowF->users()}) {
+    for (User *U : L) {
+      // A call to @llvm.wasm.throw() is only generated from __cxa_throw()
+      // builtin call within libcxxabi, and cannot be an InvokeInst.
+      auto *ThrowI = cast<CallInst>(U);
+      if (ThrowI->getFunction() != &F)
+        continue;
+      Changed = true;
+      auto *BB = ThrowI->getParent();
+      SmallVector<BasicBlock *, 4> Succs(succ_begin(BB), succ_end(BB));
+      auto &InstList = BB->getInstList();
+      InstList.erase(std::next(BasicBlock::iterator(ThrowI)), InstList.end());
+      IRB.SetInsertPoint(BB);
+      IRB.CreateUnreachable();
+      eraseDeadBBsAndChildren(Succs);
+    }
   }
 
   return Changed;
@@ -262,8 +234,6 @@ bool WasmEHPrepare::prepareEHPads(Functi
   SelectorField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 2,
                                          "selector_gep");
 
-  // wasm.catch() intinsic, which will be lowered to wasm 'catch' instruction.
-  CatchF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_catch);
   // wasm.landingpad.index() intrinsic, which is to specify landingpad index
   LPadIndexF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_landingpad_index);
   // wasm.lsda() intrinsic. Returns the address of LSDA table for the current
@@ -274,75 +244,70 @@ bool WasmEHPrepare::prepareEHPads(Functi
   GetExnF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_exception);
   GetSelectorF = Intrinsic::getDeclaration(&M, Intrinsic::wasm_get_ehselector);
 
+  // wasm.extract.exception() is the same as wasm.get.exception() but it does
+  // not take a token argument. This will be lowered down to EXTRACT_EXCEPTION
+  // pseudo instruction in instruction selection, which will be expanded using
+  // 'br_on_exn' instruction later.
+  ExtractExnF =
+      Intrinsic::getDeclaration(&M, Intrinsic::wasm_extract_exception);
+
   // _Unwind_CallPersonality() wrapper function, which calls the personality
   CallPersonalityF = cast<Function>(M.getOrInsertFunction(
       "_Unwind_CallPersonality", IRB.getInt32Ty(), IRB.getInt8PtrTy()));
   CallPersonalityF->setDoesNotThrow();
 
-  // __clang_call_terminate() function, which is inserted by clang in case a
-  // cleanup throws
-  ClangCallTermF = M.getFunction("__clang_call_terminate");
-
   unsigned Index = 0;
   for (auto *BB : CatchPads) {
     auto *CPI = cast<CatchPadInst>(BB->getFirstNonPHI());
     // In case of a single catch (...), we don't need to emit LSDA
     if (CPI->getNumArgOperands() == 1 &&
         cast<Constant>(CPI->getArgOperand(0))->isNullValue())
-      prepareEHPad(BB, -1);
+      prepareEHPad(BB, false);
     else
-      prepareEHPad(BB, Index++);
+      prepareEHPad(BB, true, Index++);
   }
 
-  if (!ClangCallTermF)
-    return !CatchPads.empty();
-
-  // Cleanuppads will turn into catch_all later, but cleanuppads with a call to
-  // __clang_call_terminate() is a special case. __clang_call_terminate() takes
-  // an exception object, so we have to duplicate call in both 'catch <C++ tag>'
-  // and 'catch_all' clauses. Here we only insert a call to catch; the
-  // duplication will be done later. In catch_all, the exception object will be
-  // set to null.
+  // Cleanup pads don't need LSDA.
   for (auto *BB : CleanupPads)
-    for (auto &I : *BB)
-      if (auto *CI = dyn_cast<CallInst>(&I))
-        if (CI->getCalledValue() == ClangCallTermF)
-          prepareEHPad(BB, -1);
+    prepareEHPad(BB, false);
 
   return true;
 }
 
-void WasmEHPrepare::prepareEHPad(BasicBlock *BB, unsigned Index) {
+// Prepare an EH pad for Wasm EH handling. If NeedLSDA is false, Index is
+// ignored.
+void WasmEHPrepare::prepareEHPad(BasicBlock *BB, bool NeedLSDA,
+                                 unsigned Index) {
   assert(BB->isEHPad() && "BB is not an EHPad!");
   IRBuilder<> IRB(BB->getContext());
-
   IRB.SetInsertPoint(&*BB->getFirstInsertionPt());
-  // The argument to wasm.catch() is the tag for C++ exceptions, which we set to
-  // 0 for this module.
-  // Pseudocode: void *exn = wasm.catch(0);
-  Instruction *Exn = IRB.CreateCall(CatchF, IRB.getInt32(0), "exn");
-  // Replace the return value of wasm.get.exception() with the return value from
-  // wasm.catch().
+
   auto *FPI = cast<FuncletPadInst>(BB->getFirstNonPHI());
   Instruction *GetExnCI = nullptr, *GetSelectorCI = nullptr;
   for (auto &U : FPI->uses()) {
     if (auto *CI = dyn_cast<CallInst>(U.getUser())) {
       if (CI->getCalledValue() == GetExnF)
         GetExnCI = CI;
-      else if (CI->getCalledValue() == GetSelectorF)
+      if (CI->getCalledValue() == GetSelectorF)
         GetSelectorCI = CI;
     }
   }
 
-  assert(GetExnCI && "wasm.get.exception() call does not exist");
-  GetExnCI->replaceAllUsesWith(Exn);
+  // Cleanup pads w/o __clang_call_terminate call do not have any of
+  // wasm.get.exception() or wasm.get.ehselector() calls. We need to do nothing.
+  if (!GetExnCI) {
+    assert(!GetSelectorCI &&
+           "wasm.get.ehselector() cannot exist w/o wasm.get.exception()");
+    return;
+  }
+
+  Instruction *ExtractExnCI = IRB.CreateCall(ExtractExnF, {}, "exn");
+  GetExnCI->replaceAllUsesWith(ExtractExnCI);
   GetExnCI->eraseFromParent();
 
   // In case it is a catchpad with single catch (...) or a cleanuppad, we don't
   // need to call personality function because we don't need a selector.
-  if (FPI->getNumArgOperands() == 0 ||
-      (FPI->getNumArgOperands() == 1 &&
-       cast<Constant>(FPI->getArgOperand(0))->isNullValue())) {
+  if (!NeedLSDA) {
     if (GetSelectorCI) {
       assert(GetSelectorCI->use_empty() &&
              "wasm.get.ehselector() still has uses!");
@@ -350,7 +315,7 @@ void WasmEHPrepare::prepareEHPad(BasicBl
     }
     return;
   }
-  IRB.SetInsertPoint(Exn->getNextNode());
+  IRB.SetInsertPoint(ExtractExnCI->getNextNode());
 
   // This is to create a map of <landingpad EH label, landingpad index> in
   // SelectionDAGISel, which is to be used in EHStreamer to emit LSDA tables.
@@ -372,8 +337,8 @@ void WasmEHPrepare::prepareEHPad(BasicBl
     IRB.CreateStore(IRB.CreateCall(LSDAF), LSDAField);
 
   // Pseudocode: _Unwind_CallPersonality(exn);
-  CallInst *PersCI =
-      IRB.CreateCall(CallPersonalityF, Exn, OperandBundleDef("funclet", CPI));
+  CallInst *PersCI = IRB.CreateCall(CallPersonalityF, ExtractExnCI,
+                                    OperandBundleDef("funclet", CPI));
   PersCI->setDoesNotThrow();
 
   // Pseudocode: int selector = __wasm.landingpad_context.selector;
@@ -387,15 +352,15 @@ void WasmEHPrepare::prepareEHPad(BasicBl
 }
 
 void llvm::calculateWasmEHInfo(const Function *F, WasmEHFuncInfo &EHInfo) {
+  // If an exception is not caught by a catchpad (i.e., it is a foreign
+  // exception), it will unwind to its parent catchswitch's unwind destination.
+  // We don't record an unwind destination for cleanuppads because every
+  // exception should be caught by it.
   for (const auto &BB : *F) {
     if (!BB.isEHPad())
       continue;
     const Instruction *Pad = BB.getFirstNonPHI();
 
-    // If an exception is not caught by a catchpad (i.e., it is a foreign
-    // exception), it will unwind to its parent catchswitch's unwind
-    // destination. We don't record an unwind destination for cleanuppads
-    // because every exception should be caught by it.
     if (const auto *CatchPad = dyn_cast<CatchPadInst>(Pad)) {
       const auto *UnwindBB = CatchPad->getCatchSwitch()->getUnwindDest();
       if (!UnwindBB)

Modified: llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp Tue Jan 29 19:21:57 2019
@@ -122,61 +122,48 @@ void WebAssemblyInstPrinter::printInst(c
       }
       break;
 
-    case WebAssembly::CATCH_I32:
-    case WebAssembly::CATCH_I32_S:
-    case WebAssembly::CATCH_I64:
-    case WebAssembly::CATCH_I64_S:
-    case WebAssembly::CATCH_ALL:
-    case WebAssembly::CATCH_ALL_S:
-      // There can be multiple catch instructions for one try instruction, so we
-      // print a label only for the first 'catch' label.
-      if (LastSeenEHInst != CATCH) {
-        if (EHPadStack.empty()) {
-          printAnnotation(OS, "try-catch mismatch!");
-        } else {
-          printAnnotation(OS,
-                          "catch" + utostr(EHPadStack.pop_back_val()) + ':');
-        }
+    case WebAssembly::CATCH:
+    case WebAssembly::CATCH_S:
+      if (EHPadStack.empty()) {
+        printAnnotation(OS, "try-catch mismatch!");
+      } else {
+        printAnnotation(OS, "catch" + utostr(EHPadStack.pop_back_val()) + ':');
       }
-      LastSeenEHInst = CATCH;
       break;
     }
 
     // Annotate any control flow label references.
-    unsigned NumFixedOperands = Desc.NumOperands;
-    SmallSet<uint64_t, 8> Printed;
-    for (unsigned i = 0, e = MI->getNumOperands(); i < e; ++i) {
-      // See if this operand denotes a basic block target.
-      if (i < NumFixedOperands) {
-        // A non-variable_ops operand, check its type.
-        if (Desc.OpInfo[i].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
-          continue;
+
+    // rethrow instruction does not take any depth argument and rethrows to the
+    // nearest enclosing catch scope, if any. If there's no enclosing catch
+    // scope, it throws up to the caller.
+    if (Opc == WebAssembly::RETHROW || Opc == WebAssembly::RETHROW_S) {
+      if (EHPadStack.empty()) {
+        printAnnotation(OS, "to caller");
       } else {
-        // A variable_ops operand, which currently can be immediates (used in
-        // br_table) which are basic block targets, or for call instructions
-        // when using -wasm-keep-registers (in which case they are registers,
-        // and should not be processed).
-        if (!MI->getOperand(i).isImm())
-          continue;
+        printAnnotation(OS, "down to catch" + utostr(EHPadStack.back()));
       }
-      uint64_t Depth = MI->getOperand(i).getImm();
-      if (!Printed.insert(Depth).second)
-        continue;
 
-      if (Opc == WebAssembly::RETHROW || Opc == WebAssembly::RETHROW_S) {
-        if (Depth > EHPadStack.size()) {
-          printAnnotation(OS, "Invalid depth argument!");
-        } else if (Depth == EHPadStack.size()) {
-          // This can happen when rethrow instruction breaks out of all nests
-          // and throws up to the current function's caller.
-          printAnnotation(OS, utostr(Depth) + ": " + "to caller");
+    } else {
+      unsigned NumFixedOperands = Desc.NumOperands;
+      SmallSet<uint64_t, 8> Printed;
+      for (unsigned I = 0, E = MI->getNumOperands(); I < E; ++I) {
+        // See if this operand denotes a basic block target.
+        if (I < NumFixedOperands) {
+          // A non-variable_ops operand, check its type.
+          if (Desc.OpInfo[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
+            continue;
         } else {
-          uint64_t CatchNo = EHPadStack.rbegin()[Depth];
-          printAnnotation(OS, utostr(Depth) + ": " + "down to catch" +
-                                  utostr(CatchNo));
+          // A variable_ops operand, which currently can be immediates (used in
+          // br_table) which are basic block targets, or for call instructions
+          // when using -wasm-keep-registers (in which case they are registers,
+          // and should not be processed).
+          if (!MI->getOperand(I).isImm())
+            continue;
         }
-
-      } else {
+        uint64_t Depth = MI->getOperand(I).getImm();
+        if (!Printed.insert(Depth).second)
+          continue;
         if (Depth >= ControlFlowStack.size()) {
           printAnnotation(OS, "Invalid depth argument!");
         } else {

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp Tue Jan 29 19:21:57 2019
@@ -43,6 +43,8 @@ using namespace llvm;
 
 #define DEBUG_TYPE "asm-printer"
 
+extern cl::opt<bool> WasmKeepRegisters;
+
 //===----------------------------------------------------------------------===//
 // Helpers.
 //===----------------------------------------------------------------------===//
@@ -304,6 +306,14 @@ void WebAssemblyAsmPrinter::EmitInstruct
       OutStreamer->AddBlankLine();
     }
     break;
+  case WebAssembly::EXTRACT_EXCEPTION_I32:
+  case WebAssembly::EXTRACT_EXCEPTION_I32_S:
+    // These are pseudo instructions that simulates popping values from stack.
+    // We print these only when we have -wasm-keep-registers on for assembly
+    // readability.
+    if (!WasmKeepRegisters)
+      break;
+    LLVM_FALLTHROUGH;
   default: {
     WebAssemblyMCInstLower MCInstLowering(OutContext, *this);
     MCInst TmpInst;

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp Tue Jan 29 19:21:57 2019
@@ -37,6 +37,7 @@
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
+#include <cstring>
 using namespace llvm;
 
 #define DEBUG_TYPE "wasm-cfg-stackify"
@@ -110,11 +111,9 @@ FunctionPass *llvm::createWebAssemblyCFG
 static bool ExplicitlyBranchesTo(MachineBasicBlock *Pred,
                                  MachineBasicBlock *MBB) {
   for (MachineInstr &MI : Pred->terminators())
-    // Even if a rethrow takes a BB argument, it is not a branch
-    if (!WebAssembly::isRethrow(MI))
-      for (MachineOperand &MO : MI.explicit_operands())
-        if (MO.isMBB() && MO.getMBB() == MBB)
-          return true;
+    for (MachineOperand &MO : MI.explicit_operands())
+      if (MO.isMBB() && MO.getMBB() == MBB)
+        return true;
   return false;
 }
 
@@ -217,12 +216,20 @@ void WebAssemblyCFGStackify::placeBlockM
   // which reduces overall stack height.
   MachineBasicBlock *Header = nullptr;
   bool IsBranchedTo = false;
+  bool IsBrOnExn = false;
+  MachineInstr *BrOnExn = nullptr;
   int MBBNumber = MBB.getNumber();
   for (MachineBasicBlock *Pred : MBB.predecessors()) {
     if (Pred->getNumber() < MBBNumber) {
       Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
-      if (ExplicitlyBranchesTo(Pred, &MBB))
+      if (ExplicitlyBranchesTo(Pred, &MBB)) {
         IsBranchedTo = true;
+        if (Pred->getFirstTerminator()->getOpcode() == WebAssembly::BR_ON_EXN) {
+          IsBrOnExn = true;
+          assert(!BrOnExn && "There should be only one br_on_exn per block");
+          BrOnExn = &*Pred->getFirstTerminator();
+        }
+      }
     }
   }
   if (!Header)
@@ -299,11 +306,27 @@ void WebAssemblyCFGStackify::placeBlockM
   }
 
   // Add the BLOCK.
+
+  // 'br_on_exn' extracts except_ref object and pushes variable number of values
+  // depending on its tag. For C++ exception, its a single i32 value, and the
+  // generated code will be in the form of:
+  // block i32
+  //   br_on_exn 0, $__cpp_exception
+  //   rethrow
+  // end_block
+  WebAssembly::ExprType ReturnType = WebAssembly::ExprType::Void;
+  if (IsBrOnExn) {
+    const char *TagName = BrOnExn->getOperand(1).getSymbolName();
+    if (std::strcmp(TagName, "__cpp_exception") != 0)
+      llvm_unreachable("Only C++ exception is supported");
+    ReturnType = WebAssembly::ExprType::I32;
+  }
+
   auto InsertPos = GetLatestInsertPos(Header, BeforeSet, AfterSet);
   MachineInstr *Begin =
       BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
               TII.get(WebAssembly::BLOCK))
-          .addImm(int64_t(WebAssembly::ExprType::Void));
+          .addImm(int64_t(ReturnType));
 
   // Decide where in Header to put the END_BLOCK.
   BeforeSet.clear();
@@ -416,11 +439,6 @@ void WebAssemblyCFGStackify::placeTryMar
   if (!MBB.isEHPad())
     return;
 
-  // catch_all terminate pad is grouped together with catch terminate pad and
-  // does not need a separate TRY and END_TRY marker.
-  if (WebAssembly::isCatchAllTerminatePad(MBB))
-    return;
-
   MachineFunction &MF = *MBB.getParent();
   auto &MDT = getAnalysis<MachineDominatorTree>();
   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
@@ -529,7 +547,8 @@ void WebAssemblyCFGStackify::placeTryMar
   // throw.
   if (MBB.isPredecessor(Header)) {
     auto TermPos = Header->getFirstTerminator();
-    if (TermPos == Header->end() || !WebAssembly::isRethrow(*TermPos)) {
+    if (TermPos == Header->end() ||
+        TermPos->getOpcode() != WebAssembly::RETHROW) {
       for (const auto &MI : reverse(*Header)) {
         if (MI.isCall()) {
           AfterSet.insert(&MI);
@@ -674,7 +693,6 @@ static void AppendEndToFunction(MachineF
 
 /// Insert LOOP/TRY/BLOCK markers at appropriate places.
 void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {
-  const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
   // We allocate one more than the number of blocks in the function to
   // accommodate for the possible fake block we may insert at the end.
   ScopeTops.resize(MF.getNumBlockIDs() + 1);
@@ -682,6 +700,7 @@ void WebAssemblyCFGStackify::placeMarker
   for (auto &MBB : MF)
     placeLoopMarker(MBB);
   // Place the TRY for MBB if MBB is the EH pad of an exception.
+  const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
   if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
       MF.getFunction().hasPersonalityFn())
     for (auto &MBB : MF)
@@ -692,12 +711,8 @@ void WebAssemblyCFGStackify::placeMarker
 }
 
 void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
-  const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
   // Now rewrite references to basic blocks to be depth immediates.
-  // We need two stacks: one for normal scopes and the other for EH pad scopes.
-  // EH pad stack is used to rewrite depths in rethrow instructions.
   SmallVector<const MachineBasicBlock *, 8> Stack;
-  SmallVector<const MachineBasicBlock *, 8> EHPadStack;
   for (auto &MBB : reverse(MF)) {
     for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) {
       MachineInstr &MI = *I;
@@ -714,26 +729,6 @@ void WebAssemblyCFGStackify::rewriteDept
                    MBB.getNumber() &&
                "Block/try marker should be balanced");
         Stack.pop_back();
-        EHPadStack.pop_back();
-        break;
-
-      case WebAssembly::CATCH_I32:
-      case WebAssembly::CATCH_I64:
-      case WebAssembly::CATCH_ALL:
-        // Currently the only case there are more than one catch for a try is
-        // for catch terminate pad, in the form of
-        //   try
-        //   catch
-        //     call @__clang_call_terminate
-        //     unreachable
-        //   catch_all
-        //     call @std::terminate
-        //     unreachable
-        //   end
-        // So we shouldn't push the current BB for the second catch_all block
-        // here.
-        if (!WebAssembly::isCatchAllTerminatePad(MBB))
-          EHPadStack.push_back(&MBB);
         break;
 
       case WebAssembly::LOOP:
@@ -750,23 +745,6 @@ void WebAssemblyCFGStackify::rewriteDept
         Stack.push_back(EndToBegin[&MI]->getParent());
         break;
 
-      case WebAssembly::RETHROW: {
-        // Rewrite MBB operands to be depth immediates.
-        unsigned EHPadDepth = GetDepth(EHPadStack, MI.getOperand(0).getMBB());
-        MI.RemoveOperand(0);
-        MI.addOperand(MF, MachineOperand::CreateImm(EHPadDepth));
-        break;
-      }
-
-      case WebAssembly::RETHROW_TO_CALLER: {
-        MachineInstr *Rethrow =
-            BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(WebAssembly::RETHROW))
-                .addImm(EHPadStack.size());
-        MI.eraseFromParent();
-        I = MachineBasicBlock::reverse_iterator(Rethrow);
-        break;
-      }
-
       default:
         if (MI.isTerminator()) {
           // Rewrite MBB operands to be depth immediates.

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp Tue Jan 29 19:21:57 2019
@@ -77,7 +77,7 @@ bool WebAssemblyEHRestoreStackPointer::r
     // function uses the red zone, but that only happens with leaf functions,
     // and we don't restore __stack_pointer in leaf functions anyway.
     auto InsertPos = MBB.begin();
-    if (WebAssembly::isCatch(*MBB.begin()))
+    if (MBB.begin()->getOpcode() == WebAssembly::CATCH)
       InsertPos++;
     FrameLowering->writeSPToGlobal(WebAssembly::SP32, MF, MBB, InsertPos,
                                    MBB.begin()->getDebugLoc());

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp Tue Jan 29 19:21:57 2019
@@ -50,10 +50,6 @@ void WebAssemblyExceptionInfo::recalcula
     MachineBasicBlock *EHPad = DomNode->getBlock();
     if (!EHPad->isEHPad())
       continue;
-    // We group catch & catch-all terminate pads together, so skip the second
-    // one
-    if (WebAssembly::isCatchAllTerminatePad(*EHPad))
-      continue;
     auto *WE = new WebAssemblyException(EHPad);
     discoverAndMapException(WE, MDT, MDF);
     Exceptions.push_back(WE);
@@ -104,16 +100,6 @@ void WebAssemblyExceptionInfo::discoverA
 
   // Map blocks that belong to a catchpad / cleanuppad
   MachineBasicBlock *EHPad = WE->getEHPad();
-
-  // We group catch & catch-all terminate pads together within an exception
-  if (WebAssembly::isCatchTerminatePad(*EHPad)) {
-    assert(EHPad->succ_size() == 1 &&
-           "Catch terminate pad has more than one successors");
-    changeExceptionFor(EHPad, WE);
-    changeExceptionFor(*(EHPad->succ_begin()), WE);
-    return;
-  }
-
   SmallVector<MachineBasicBlock *, 8> WL;
   WL.push_back(EHPad);
   while (!WL.empty()) {

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp Tue Jan 29 19:21:57 2019
@@ -884,13 +884,13 @@ SDValue WebAssemblyTargetLowering::Lower
     return LowerFRAMEADDR(Op, DAG);
   case ISD::CopyToReg:
     return LowerCopyToReg(Op, DAG);
-  case ISD::INTRINSIC_WO_CHAIN:
-    return LowerINTRINSIC_WO_CHAIN(Op, DAG);
   case ISD::EXTRACT_VECTOR_ELT:
   case ISD::INSERT_VECTOR_ELT:
     return LowerAccessVectorElement(Op, DAG);
   case ISD::INTRINSIC_VOID:
-    return LowerINTRINSIC_VOID(Op, DAG);
+  case ISD::INTRINSIC_WO_CHAIN:
+  case ISD::INTRINSIC_W_CHAIN:
+    return LowerIntrinsic(Op, DAG);
   case ISD::SIGN_EXTEND_INREG:
     return LowerSIGN_EXTEND_INREG(Op, DAG);
   case ISD::BUILD_VECTOR:
@@ -1035,17 +1035,28 @@ SDValue WebAssemblyTargetLowering::Lower
                       MachinePointerInfo(SV), 0);
 }
 
-SDValue
-WebAssemblyTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
-                                                   SelectionDAG &DAG) const {
-  unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op,
+                                                  SelectionDAG &DAG) const {
+  MachineFunction &MF = DAG.getMachineFunction();
+  unsigned IntNo;
+  switch (Op.getOpcode()) {
+  case ISD::INTRINSIC_VOID:
+  case ISD::INTRINSIC_W_CHAIN:
+    IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
+    break;
+  case ISD::INTRINSIC_WO_CHAIN:
+    IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+    break;
+  default:
+    llvm_unreachable("Invalid intrinsic");
+  }
   SDLoc DL(Op);
+
   switch (IntNo) {
   default:
     return {}; // Don't custom lower most intrinsics.
 
   case Intrinsic::wasm_lsda: {
-    MachineFunction &MF = DAG.getMachineFunction();
     EVT VT = Op.getValueType();
     const TargetLowering &TLI = DAG.getTargetLoweringInfo();
     MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
@@ -1055,43 +1066,26 @@ WebAssemblyTargetLowering::LowerINTRINSI
     return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
                        DAG.getMCSymbol(S, PtrVT));
   }
-  }
-}
-
-SDValue
-WebAssemblyTargetLowering::LowerINTRINSIC_VOID(SDValue Op,
-                                               SelectionDAG &DAG) const {
-  MachineFunction &MF = DAG.getMachineFunction();
-  unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
-  SDLoc DL(Op);
-
-  switch (IntNo) {
-  default:
-    return {}; // Don't custom lower most intrinsics.
 
   case Intrinsic::wasm_throw: {
+    // We only support C++ exceptions for now
     int Tag = cast<ConstantSDNode>(Op.getOperand(2).getNode())->getZExtValue();
-    switch (Tag) {
-    case CPP_EXCEPTION: {
-      const TargetLowering &TLI = DAG.getTargetLoweringInfo();
-      MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
-      const char *SymName = MF.createExternalSymbolName("__cpp_exception");
-      SDValue SymNode =
-          DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
-                      DAG.getTargetExternalSymbol(
-                          SymName, PtrVT, WebAssemblyII::MO_SYMBOL_EVENT));
-      return DAG.getNode(WebAssemblyISD::THROW, DL,
-                         MVT::Other, // outchain type
-                         {
-                             Op.getOperand(0), // inchain
-                             SymNode,          // exception symbol
-                             Op.getOperand(3)  // thrown value
-                         });
-    }
-    default:
+    if (Tag != CPP_EXCEPTION)
       llvm_unreachable("Invalid tag!");
-    }
-    break;
+    const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+    MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
+    const char *SymName = MF.createExternalSymbolName("__cpp_exception");
+    SDValue SymNode =
+        DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
+                    DAG.getTargetExternalSymbol(
+                        SymName, PtrVT, WebAssemblyII::MO_SYMBOL_EVENT));
+    return DAG.getNode(WebAssemblyISD::THROW, DL,
+                       MVT::Other, // outchain type
+                       {
+                           Op.getOperand(0), // inchain
+                           SymNode,          // exception symbol
+                           Op.getOperand(3)  // thrown value
+                       });
   }
   }
 }

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyISelLowering.h Tue Jan 29 19:21:57 2019
@@ -96,8 +96,7 @@ private:
   SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerCopyToReg(SDValue Op, SelectionDAG &DAG) const;
-  SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
-  SDValue LowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerIntrinsic(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerSIGN_EXTEND_INREG(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const;

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td Tue Jan 29 19:21:57 2019
@@ -141,23 +141,11 @@ let Predicates = [HasExceptionHandling]
 
 // Throwing an exception: throw / rethrow
 let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
-defm THROW_I32 : I<(outs), (ins event_op:$tag, I32:$val),
-                   (outs), (ins event_op:$tag),
-                   [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag),
-                                      I32:$val)],
-                   "throw   \t$tag, $val", "throw   \t$tag",
-                   0x08>;
-defm THROW_I64 : I<(outs), (ins event_op:$tag, I64:$val),
-                   (outs), (ins event_op:$tag),
-                   [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag),
-                                      I64:$val)],
-                   "throw   \t$tag, $val", "throw   \t$tag",
-                   0x08>;
-defm RETHROW : NRI<(outs), (ins bb_op:$dst), [], "rethrow \t$dst", 0x09>;
-let isCodeGenOnly = 1 in
-// This is used when the destination for rethrow is the caller function. This
-// will be converted to a rethrow in CFGStackify.
-defm RETHROW_TO_CALLER : NRI<(outs), (ins), [], "rethrow">;
+defm THROW : I<(outs), (ins event_op:$tag, variable_ops),
+               (outs), (ins event_op:$tag),
+               [(WebAssemblythrow (WebAssemblywrapper texternalsym:$tag))],
+               "throw   \t$tag", "throw   \t$tag", 0x08>;
+defm RETHROW : NRI<(outs), (ins), [(int_wasm_rethrow)], "rethrow", 0x09>;
 } // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
 
 // Region within which an exception is caught: try / end_try
@@ -166,24 +154,33 @@ defm TRY     : NRI<(outs), (ins Signatur
 defm END_TRY : NRI<(outs), (ins), [], "end_try", 0x0b>;
 } // Uses = [VALUE_STACK], Defs = [VALUE_STACK]
 
-// Catching an exception: catch / catch_all
-let hasCtrlDep = 1, hasSideEffects = 1 in {
-defm CATCH_I32 : I<(outs I32:$dst), (ins i32imm:$tag),
-                   (outs), (ins i32imm:$tag),
-                   [(set I32:$dst, (int_wasm_catch imm:$tag))],
-                   "i32.catch   \t$dst, $tag", "i32.catch   \t$tag", 0x07>;
-defm CATCH_I64 : I<(outs I64:$dst), (ins i32imm:$tag),
-                   (outs), (ins i32imm:$tag),
-                   [(set I64:$dst, (int_wasm_catch imm:$tag))],
-                   "i64.catch   \t$dst, $tag", "i64.catch   \t$tag", 0x07>;
-defm CATCH_ALL : NRI<(outs), (ins), [], "catch_all", 0x05>;
-}
+// Catching an exception: catch / extract_exception
+let hasCtrlDep = 1, hasSideEffects = 1 in
+defm CATCH : I<(outs EXCEPT_REF:$dst), (ins), (outs), (ins), [],
+               "catch   \t$dst", "catch", 0x07>;
+
+// Querying / extracing exception: br_on_exn
+// br_on_exn queries an except_ref to see if it matches the corresponding
+// exception tag index. If true it branches to the given label and pushes the
+// corresponding argument values of the exception onto the stack.
+let isBranch = 1, isTerminator = 1, hasCtrlDep = 1 in
+defm BR_ON_EXN : I<(outs), (ins bb_op:$dst, event_op:$tag, EXCEPT_REF:$exn),
+                   (outs), (ins bb_op:$dst, event_op:$tag), [],
+                   "br_on_exn \t$dst, $tag, $exn", "br_on_exn \t$dst, $tag",
+                   0x0a>;
+// This is a pseudo instruction that simulates popping a value from stack, which
+// has been pushed by br_on_exn
+let isCodeGenOnly = 1, hasSideEffects = 1 in
+defm EXTRACT_EXCEPTION_I32 : NRI<(outs I32:$dst), (ins),
+                                 [(set I32:$dst, (int_wasm_extract_exception))],
+                                 "extract_exception\t$dst">;
 
 // Pseudo instructions: cleanupret / catchret
 let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
-    isCodeGenOnly = 1, isEHScopeReturn = 1 in {
-  defm CLEANUPRET : NRI<(outs), (ins), [(cleanupret)], "", 0>;
+    isPseudo = 1, isEHScopeReturn = 1 in {
+  defm CLEANUPRET : NRI<(outs), (ins), [(cleanupret)], "cleanupret", 0>;
   defm CATCHRET : NRI<(outs), (ins bb_op:$dst, bb_op:$from),
-                   [(catchret bb:$dst, bb:$from)], "", 0>;
-}
+                      [(catchret bb:$dst, bb:$from)], "catchret", 0>;
+} // isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
+  // isPseudo = 1, isEHScopeReturn = 1
 }

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp Tue Jan 29 19:21:57 2019
@@ -134,6 +134,17 @@ bool WebAssemblyInstrInfo::analyzeBranch
       else
         FBB = MI.getOperand(0).getMBB();
       break;
+    case WebAssembly::BR_ON_EXN:
+      if (HaveCond)
+        return true;
+      // If we're running after CFGStackify, we can't optimize further.
+      if (!MI.getOperand(0).isMBB())
+        return true;
+      Cond.push_back(MachineOperand::CreateImm(true));
+      Cond.push_back(MI.getOperand(2));
+      TBB = MI.getOperand(0).getMBB();
+      HaveCond = true;
+      break;
     }
     if (MI.isBarrier())
       break;
@@ -179,9 +190,22 @@ unsigned WebAssemblyInstrInfo::insertBra
 
   assert(Cond.size() == 2 && "Expected a flag and a successor block");
 
+  MachineFunction &MF = *MBB.getParent();
+  auto &MRI = MF.getRegInfo();
+  bool IsBrOnExn = Cond[1].isReg() && MRI.getRegClass(Cond[1].getReg()) ==
+                                          &WebAssembly::EXCEPT_REFRegClass;
+
   if (Cond[0].getImm()) {
-    BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);
+    if (IsBrOnExn) {
+      const char *CPPExnSymbol = MF.createExternalSymbolName("__cpp_exception");
+      BuildMI(&MBB, DL, get(WebAssembly::BR_ON_EXN))
+          .addMBB(TBB)
+          .addExternalSymbol(CPPExnSymbol, WebAssemblyII::MO_SYMBOL_EVENT)
+          .add(Cond[1]);
+    } else
+      BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]);
   } else {
+    assert(!IsBrOnExn && "br_on_exn does not have a reversed condition");
     BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]);
   }
   if (!FBB)
@@ -193,7 +217,15 @@ unsigned WebAssemblyInstrInfo::insertBra
 
 bool WebAssemblyInstrInfo::reverseBranchCondition(
     SmallVectorImpl<MachineOperand> &Cond) const {
-  assert(Cond.size() == 2 && "Expected a flag and a successor block");
+  assert(Cond.size() == 2 && "Expected a flag and a condition expression");
+
+  // br_on_exn's condition cannot be reversed
+  MachineFunction &MF = *Cond[1].getParent()->getParent()->getParent();
+  auto &MRI = MF.getRegInfo();
+  if (Cond[1].isReg() &&
+      MRI.getRegClass(Cond[1].getReg()) == &WebAssembly::EXCEPT_REFRegClass)
+    return true;
+
   Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());
   return false;
 }

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td Tue Jan 29 19:21:57 2019
@@ -66,7 +66,7 @@ def SDT_WebAssemblyArgument : SDTypeProf
 def SDT_WebAssemblyReturn   : SDTypeProfile<0, -1, []>;
 def SDT_WebAssemblyWrapper  : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
                                                    SDTCisPtrTy<0>]>;
-def SDT_WebAssemblyThrow    : SDTypeProfile<0, 2, [SDTCisPtrTy<0>]>;
+def SDT_WebAssemblyThrow    : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
 
 //===----------------------------------------------------------------------===//
 // WebAssembly-specific DAG Nodes.
@@ -94,7 +94,7 @@ def WebAssemblyreturn   : SDNode<"WebAss
 def WebAssemblywrapper  : SDNode<"WebAssemblyISD::Wrapper",
                                  SDT_WebAssemblyWrapper>;
 def WebAssemblythrow : SDNode<"WebAssemblyISD::THROW", SDT_WebAssemblyThrow,
-                              [SDNPHasChain]>;
+                              [SDNPHasChain, SDNPVariadic]>;
 
 //===----------------------------------------------------------------------===//
 // WebAssembly-specific Operands.

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp Tue Jan 29 19:21:57 2019
@@ -15,6 +15,7 @@
 #include "WebAssembly.h"
 #include "WebAssemblySubtarget.h"
 #include "WebAssemblyUtilities.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/WasmEHFuncInfo.h"
 #include "llvm/MC/MCAsmInfo.h"
@@ -25,19 +26,14 @@ using namespace llvm;
 namespace {
 class WebAssemblyLateEHPrepare final : public MachineFunctionPass {
   StringRef getPassName() const override {
-    return "WebAssembly Prepare Exception";
+    return "WebAssembly Late Prepare Exception";
   }
 
   bool runOnMachineFunction(MachineFunction &MF) override;
-
   bool removeUnnecessaryUnreachables(MachineFunction &MF);
   bool replaceFuncletReturns(MachineFunction &MF);
-  bool hoistCatches(MachineFunction &MF);
-  bool addCatchAlls(MachineFunction &MF);
-  bool addRethrows(MachineFunction &MF);
-  bool ensureSingleBBTermPads(MachineFunction &MF);
-  bool mergeTerminatePads(MachineFunction &MF);
-  bool addCatchAllTerminatePads(MachineFunction &MF);
+  bool addCatches(MachineFunction &MF);
+  bool addExceptionExtraction(MachineFunction &MF);
 
 public:
   static char ID; // Pass identification, replacement for typeid
@@ -112,15 +108,11 @@ bool WebAssemblyLateEHPrepare::runOnMach
 
   bool Changed = false;
   Changed |= removeUnnecessaryUnreachables(MF);
-  Changed |= addRethrows(MF);
   if (!MF.getFunction().hasPersonalityFn())
     return Changed;
   Changed |= replaceFuncletReturns(MF);
-  Changed |= hoistCatches(MF);
-  Changed |= addCatchAlls(MF);
-  Changed |= ensureSingleBBTermPads(MF);
-  Changed |= mergeTerminatePads(MF);
-  Changed |= addCatchAllTerminatePads(MF);
+  Changed |= addCatches(MF);
+  Changed |= addExceptionExtraction(MF);
   return Changed;
 }
 
@@ -129,7 +121,8 @@ bool WebAssemblyLateEHPrepare::removeUnn
   bool Changed = false;
   for (auto &MBB : MF) {
     for (auto &MI : MBB) {
-      if (!WebAssembly::isThrow(MI))
+      if (MI.getOpcode() != WebAssembly::THROW &&
+          MI.getOpcode() != WebAssembly::RETHROW)
         continue;
       Changed = true;
 
@@ -152,7 +145,6 @@ bool WebAssemblyLateEHPrepare::removeUnn
 bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) {
   bool Changed = false;
   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
-  auto *EHInfo = MF.getWasmEHFuncInfo();
 
   for (auto &MBB : MF) {
     auto Pos = MBB.getFirstTerminator();
@@ -173,13 +165,7 @@ bool WebAssemblyLateEHPrepare::replaceFu
     }
     case WebAssembly::CLEANUPRET: {
       // Replace a cleanupret with a rethrow
-      if (EHInfo->hasThrowUnwindDest(&MBB))
-        BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW))
-            .addMBB(EHInfo->getThrowUnwindDest(&MBB));
-      else
-        BuildMI(MBB, TI, TI->getDebugLoc(),
-                TII.get(WebAssembly::RETHROW_TO_CALLER));
-
+      BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW));
       TI->eraseFromParent();
       Changed = true;
       break;
@@ -189,233 +175,158 @@ bool WebAssemblyLateEHPrepare::replaceFu
   return Changed;
 }
 
-// Hoist catch instructions to the beginning of their matching EH pad BBs in
-// case,
-// (1) catch instruction is not the first instruction in EH pad.
-// ehpad:
-//   some_other_instruction
-//   ...
-//   %exn = catch 0
-// (2) catch instruction is in a non-EH pad BB. For example,
-// ehpad:
-//   br bb0
-// bb0:
-//   %exn = catch 0
-bool WebAssemblyLateEHPrepare::hoistCatches(MachineFunction &MF) {
-  bool Changed = false;
-  SmallVector<MachineInstr *, 16> Catches;
-  for (auto &MBB : MF)
-    for (auto &MI : MBB)
-      if (WebAssembly::isCatch(MI))
-        Catches.push_back(&MI);
-
-  for (auto *Catch : Catches) {
-    MachineBasicBlock *EHPad = getMatchingEHPad(Catch);
-    assert(EHPad && "No matching EH pad for catch");
-    if (EHPad->begin() == Catch)
-      continue;
-    Changed = true;
-    EHPad->insert(EHPad->begin(), Catch->removeFromParent());
-  }
-  return Changed;
-}
-
-// Add catch_all to beginning of cleanup pads.
-bool WebAssemblyLateEHPrepare::addCatchAlls(MachineFunction &MF) {
+// Add catch instruction to beginning of catchpads and cleanuppads.
+bool WebAssemblyLateEHPrepare::addCatches(MachineFunction &MF) {
   bool Changed = false;
   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
-
+  MachineRegisterInfo &MRI = MF.getRegInfo();
   for (auto &MBB : MF) {
-    if (!MBB.isEHPad())
-      continue;
-    // This runs after hoistCatches(), so we assume that if there is a catch,
-    // that should be the first instruction in an EH pad.
-    if (!WebAssembly::isCatch(*MBB.begin())) {
+    if (MBB.isEHPad()) {
       Changed = true;
+      unsigned DstReg =
+          MRI.createVirtualRegister(&WebAssembly::EXCEPT_REFRegClass);
       BuildMI(MBB, MBB.begin(), MBB.begin()->getDebugLoc(),
-              TII.get(WebAssembly::CATCH_ALL));
+              TII.get(WebAssembly::CATCH), DstReg);
     }
   }
   return Changed;
 }
 
-// Add a 'rethrow' instruction after __cxa_rethrow() call
-bool WebAssemblyLateEHPrepare::addRethrows(MachineFunction &MF) {
-  bool Changed = false;
+// Wasm uses 'br_on_exn' instruction to check the tag of an exception. It takes
+// except_ref type object returned by 'catch', and branches to the destination
+// if it matches a given tag. We currently use __cpp_exception symbol to
+// represent the tag for all C++ exceptions.
+//
+// block $l (result i32)
+//   ...
+//   ;; except_ref $e is on the stack at this point
+//   br_on_exn $l $e ;; branch to $l with $e's arguments
+//   ...
+// end
+// ;; Here we expect the extracted values are on top of the wasm value stack
+// ... Handle exception using values ...
+//
+// br_on_exn takes an except_ref object and branches if it matches the given
+// tag. There can be multiple br_on_exn instructions if we want to match for
+// another tag, but for now we only test for __cpp_exception tag, and if it does
+// not match, i.e., it is a foreign exception, we rethrow it.
+//
+// In the destination BB that's the target of br_on_exn, extracted exception
+// values (in C++'s case a single i32, which represents an exception pointer)
+// are placed on top of the wasm stack. Because we can't model wasm stack in
+// LLVM instruction, we use 'extract_exception' pseudo instruction to retrieve
+// it. The pseudo instruction will be deleted later.
+bool WebAssemblyLateEHPrepare::addExceptionExtraction(MachineFunction &MF) {
   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
   auto *EHInfo = MF.getWasmEHFuncInfo();
-
-  for (auto &MBB : MF)
+  SmallVector<MachineInstr *, 16> ExtractInstrs;
+  for (auto &MBB : MF) {
     for (auto &MI : MBB) {
-      // Check if it is a call to __cxa_rethrow()
-      if (!MI.isCall())
-        continue;
-      MachineOperand &CalleeOp = MI.getOperand(0);
-      if (!CalleeOp.isGlobal() ||
-          CalleeOp.getGlobal()->getName() != WebAssembly::CxaRethrowFn)
-        continue;
-
-      // Now we have __cxa_rethrow() call
-      Changed = true;
-      auto InsertPt = std::next(MachineBasicBlock::iterator(MI));
-      while (InsertPt != MBB.end() && InsertPt->isLabel()) // Skip EH_LABELs
-        ++InsertPt;
-      MachineInstr *Rethrow = nullptr;
-      if (EHInfo->hasThrowUnwindDest(&MBB))
-        Rethrow = BuildMI(MBB, InsertPt, MI.getDebugLoc(),
-                          TII.get(WebAssembly::RETHROW))
-                      .addMBB(EHInfo->getThrowUnwindDest(&MBB));
-      else
-        Rethrow = BuildMI(MBB, InsertPt, MI.getDebugLoc(),
-                          TII.get(WebAssembly::RETHROW_TO_CALLER));
-
-      // Because __cxa_rethrow does not return, the instruction after the
-      // rethrow should be an unreachable or a branch to another BB that should
-      // eventually lead to an unreachable. Delete it because rethrow itself is
-      // a terminator, and also delete non-EH pad successors if any.
-      MBB.erase(std::next(MachineBasicBlock::iterator(Rethrow)), MBB.end());
-      SmallVector<MachineBasicBlock *, 8> NonPadSuccessors;
-      for (auto *Succ : MBB.successors())
-        if (!Succ->isEHPad())
-          NonPadSuccessors.push_back(Succ);
-      for (auto *Succ : NonPadSuccessors)
-        MBB.removeSuccessor(Succ);
-      eraseDeadBBsAndChildren(NonPadSuccessors);
+      if (MI.getOpcode() == WebAssembly::EXTRACT_EXCEPTION_I32) {
+        if (MI.getOperand(0).isDead())
+          MI.eraseFromParent();
+        else
+          ExtractInstrs.push_back(&MI);
+      }
     }
-  return Changed;
-}
-
-// Terminate pads are an single-BB EH pad in the form of
-// termpad:
-//   %exn = catch 0
-//   call @__clang_call_terminate(%exn)
-//   unreachable
-// (There can be local.set and local.gets before the call if we didn't run
-// RegStackify)
-// But code transformations can change or add more control flow, so the call to
-// __clang_call_terminate() function may not be in the original EH pad anymore.
-// This ensures every terminate pad is a single BB in the form illustrated
-// above.
-bool WebAssemblyLateEHPrepare::ensureSingleBBTermPads(MachineFunction &MF) {
-  const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
+  }
+  if (ExtractInstrs.empty())
+    return false;
 
-  // Find calls to __clang_call_terminate()
-  SmallVector<MachineInstr *, 8> ClangCallTerminateCalls;
-  for (auto &MBB : MF)
-    for (auto &MI : MBB)
+  // Find terminate pads.
+  SmallSet<MachineBasicBlock *, 8> TerminatePads;
+  for (auto &MBB : MF) {
+    for (auto &MI : MBB) {
       if (MI.isCall()) {
         const MachineOperand &CalleeOp = MI.getOperand(0);
         if (CalleeOp.isGlobal() && CalleeOp.getGlobal()->getName() ==
                                        WebAssembly::ClangCallTerminateFn)
-          ClangCallTerminateCalls.push_back(&MI);
+          TerminatePads.insert(getMatchingEHPad(&MI));
       }
-
-  bool Changed = false;
-  for (auto *Call : ClangCallTerminateCalls) {
-    MachineBasicBlock *EHPad = getMatchingEHPad(Call);
-    assert(EHPad && "No matching EH pad for catch");
-
-    // If it is already the form we want, skip it
-    if (Call->getParent() == EHPad &&
-        Call->getNextNode()->getOpcode() == WebAssembly::UNREACHABLE)
-      continue;
-
-    // In case the __clang_call_terminate() call is not in its matching EH pad,
-    // move the call to the end of EH pad and add an unreachable instruction
-    // after that. Delete all successors and their children if any, because here
-    // the program terminates.
-    Changed = true;
-    MachineInstr *Catch = &*EHPad->begin();
-    // This runs after hoistCatches(), so catch instruction should be at the top
-    assert(WebAssembly::isCatch(*Catch));
-    // Takes the result register of the catch instruction as argument. There may
-    // have been some other local.set/local.gets in between, but at this point
-    // we don't care.
-    Call->getOperand(1).setReg(Catch->getOperand(0).getReg());
-    auto InsertPos = std::next(MachineBasicBlock::iterator(Catch));
-    EHPad->insert(InsertPos, Call->removeFromParent());
-    BuildMI(*EHPad, InsertPos, Call->getDebugLoc(),
-            TII.get(WebAssembly::UNREACHABLE));
-    EHPad->erase(InsertPos, EHPad->end());
-    SmallVector<MachineBasicBlock *, 8> Succs(EHPad->succ_begin(),
-                                              EHPad->succ_end());
-    for (auto *Succ : Succs)
-      EHPad->removeSuccessor(Succ);
-    eraseDeadBBsAndChildren(Succs);
+    }
   }
-  return Changed;
-}
 
-// In case there are multiple terminate pads, merge them into one for code size.
-// This runs after ensureSingleBBTermPads() and assumes every terminate pad is a
-// single BB.
-// In principle this violates EH scope relationship because it can merge
-// multiple inner EH scopes, each of which is in different outer EH scope. But
-// getEHScopeMembership() function will not be called after this, so it is fine.
-bool WebAssemblyLateEHPrepare::mergeTerminatePads(MachineFunction &MF) {
-  SmallVector<MachineBasicBlock *, 8> TermPads;
-  for (auto &MBB : MF)
-    if (WebAssembly::isCatchTerminatePad(MBB))
-      TermPads.push_back(&MBB);
-  if (TermPads.empty())
-    return false;
+  for (auto *Extract : ExtractInstrs) {
+    MachineBasicBlock *EHPad = getMatchingEHPad(Extract);
+    assert(EHPad && "No matching EH pad for extract_exception");
+    MachineInstr *Catch = &*EHPad->begin();
+    if (Catch->getNextNode() != Extract)
+      EHPad->insert(Catch->getNextNode(), Extract->removeFromParent());
 
-  MachineBasicBlock *UniqueTermPad = TermPads.front();
-  for (auto *TermPad :
-       llvm::make_range(std::next(TermPads.begin()), TermPads.end())) {
-    SmallVector<MachineBasicBlock *, 2> Preds(TermPad->pred_begin(),
-                                              TermPad->pred_end());
-    for (auto *Pred : Preds)
-      Pred->replaceSuccessor(TermPad, UniqueTermPad);
-    TermPad->eraseFromParent();
+    // - Before:
+    // ehpad:
+    //   %exnref:except_ref = catch
+    //   %exn:i32 = extract_exception
+    //   ... use exn ...
+    //
+    // - After:
+    // ehpad:
+    //   %exnref:except_ref = catch
+    //   br_on_exn %thenbb, $__cpp_exception, %exnref
+    //   br %elsebb
+    // elsebb:
+    //   rethrow
+    // thenbb:
+    //   %exn:i32 = extract_exception
+    //   ... use exn ...
+    unsigned ExnRefReg = Catch->getOperand(0).getReg();
+    auto *ThenMBB = MF.CreateMachineBasicBlock();
+    auto *ElseMBB = MF.CreateMachineBasicBlock();
+    MF.insert(std::next(MachineFunction::iterator(EHPad)), ElseMBB);
+    MF.insert(std::next(MachineFunction::iterator(ElseMBB)), ThenMBB);
+    ThenMBB->splice(ThenMBB->end(), EHPad, Extract, EHPad->end());
+    ThenMBB->transferSuccessors(EHPad);
+    EHPad->addSuccessor(ThenMBB);
+    EHPad->addSuccessor(ElseMBB);
+
+    DebugLoc DL = Extract->getDebugLoc();
+    const char *CPPExnSymbol = MF.createExternalSymbolName("__cpp_exception");
+    BuildMI(EHPad, DL, TII.get(WebAssembly::BR_ON_EXN))
+        .addMBB(ThenMBB)
+        .addExternalSymbol(CPPExnSymbol, WebAssemblyII::MO_SYMBOL_EVENT)
+        .addReg(ExnRefReg);
+    BuildMI(EHPad, DL, TII.get(WebAssembly::BR)).addMBB(ElseMBB);
+
+    // When this is a terminate pad with __clang_call_terminate() call, we don't
+    // rethrow it anymore and call __clang_call_terminate() with a nullptr
+    // argument, which will call std::terminate().
+    //
+    // - Before:
+    // ehpad:
+    //   %exnref:except_ref = catch
+    //   %exn:i32 = extract_exception
+    //   call @__clang_call_terminate(%exn)
+    //   unreachable
+    //
+    // - After:
+    // ehpad:
+    //   %exnref:except_ref = catch
+    //   br_on_exn %thenbb, $__cpp_exception, %exnref
+    //   br %elsebb
+    // elsebb:
+    //   call @__clang_call_terminate(0)
+    //   unreachable
+    // thenbb:
+    //   %exn:i32 = extract_exception
+    //   call @__clang_call_terminate(%exn)
+    //   unreachable
+    if (TerminatePads.count(EHPad)) {
+      Function *ClangCallTerminateFn =
+          MF.getFunction().getParent()->getFunction(
+              WebAssembly::ClangCallTerminateFn);
+      assert(ClangCallTerminateFn &&
+             "There is no __clang_call_terminate() function");
+      BuildMI(ElseMBB, DL, TII.get(WebAssembly::CALL_VOID))
+          .addGlobalAddress(ClangCallTerminateFn)
+          .addImm(0);
+      BuildMI(ElseMBB, DL, TII.get(WebAssembly::UNREACHABLE));
+
+    } else {
+      BuildMI(ElseMBB, DL, TII.get(WebAssembly::RETHROW));
+      if (EHInfo->hasEHPadUnwindDest(EHPad))
+        EHInfo->setThrowUnwindDest(ElseMBB, EHInfo->getEHPadUnwindDest(EHPad));
+    }
   }
-  return true;
-}
-
-// Terminate pads are cleanup pads, so they should start with a 'catch_all'
-// instruction. But in the Itanium model, when we have a C++ exception object,
-// we pass them to __clang_call_terminate function, which calls __cxa_end_catch
-// with the passed exception pointer and then std::terminate. This is the reason
-// that terminate pads are generated with not a catch_all but a catch
-// instruction in clang and earlier llvm passes. Here we append a terminate pad
-// with a catch_all after each existing terminate pad so we can also catch
-// foreign exceptions. For every terminate pad:
-//   %exn = catch 0
-//   call @__clang_call_terminate(%exn)
-//   unreachable
-// We append this BB right after that:
-//   catch_all
-//   call @std::terminate()
-//   unreachable
-bool WebAssemblyLateEHPrepare::addCatchAllTerminatePads(MachineFunction &MF) {
-  const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
-  SmallVector<MachineBasicBlock *, 8> TermPads;
-  for (auto &MBB : MF)
-    if (WebAssembly::isCatchTerminatePad(MBB))
-      TermPads.push_back(&MBB);
-  if (TermPads.empty())
-    return false;
 
-  Function *StdTerminateFn =
-      MF.getFunction().getParent()->getFunction(WebAssembly::StdTerminateFn);
-  assert(StdTerminateFn && "There is no std::terminate() function");
-  for (auto *CatchTermPad : TermPads) {
-    DebugLoc DL = CatchTermPad->findDebugLoc(CatchTermPad->begin());
-    auto *CatchAllTermPad = MF.CreateMachineBasicBlock();
-    MF.insert(std::next(MachineFunction::iterator(CatchTermPad)),
-              CatchAllTermPad);
-    CatchAllTermPad->setIsEHPad();
-    BuildMI(CatchAllTermPad, DL, TII.get(WebAssembly::CATCH_ALL));
-    BuildMI(CatchAllTermPad, DL, TII.get(WebAssembly::CALL_VOID))
-        .addGlobalAddress(StdTerminateFn);
-    BuildMI(CatchAllTermPad, DL, TII.get(WebAssembly::UNREACHABLE));
-
-    // Actually this CatchAllTermPad (new terminate pad with a catch_all) is not
-    // a successor of an existing terminate pad. CatchAllTermPad should have all
-    // predecessors CatchTermPad has instead. This is a hack to force
-    // CatchAllTermPad be always sorted right after CatchTermPad; the correct
-    // predecessor-successor relationships will be restored in CFGStackify pass.
-    CatchTermPad->addSuccessor(CatchAllTermPad);
-  }
   return true;
 }

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp Tue Jan 29 19:21:57 2019
@@ -36,7 +36,7 @@ using namespace llvm;
 
 // This disables the removal of registers when lowering into MC, as required
 // by some current tests.
-static cl::opt<bool>
+cl::opt<bool>
     WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
                       cl::desc("WebAssembly: output stack registers in"
                                " instruction output for test purposes only."),

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp Tue Jan 29 19:21:57 2019
@@ -317,6 +317,18 @@ static bool IsSafeToMove(const MachineIn
                          AliasAnalysis &AA, const MachineRegisterInfo &MRI) {
   assert(Def->getParent() == Insert->getParent());
 
+  // 'catch' and 'extract_exception' should be the first instruction of a BB and
+  // cannot move.
+  if (Def->getOpcode() == WebAssembly::CATCH ||
+      Def->getOpcode() == WebAssembly::EXTRACT_EXCEPTION_I32) {
+    const MachineBasicBlock *MBB = Def->getParent();
+    auto NextI = std::next(MachineBasicBlock::const_iterator(Def));
+    for (auto E = MBB->end(); NextI != E && NextI->isDebugInstr(); ++NextI)
+      ;
+    if (NextI != Insert)
+      return false;
+  }
+
   // Check for register dependencies.
   SmallVector<unsigned, 4> MutableRegisters;
   for (const MachineOperand &MO : Def->operands()) {
@@ -819,6 +831,24 @@ bool WebAssemblyRegStackify::runOnMachin
         if (WebAssembly::isArgument(*Def))
           continue;
 
+        // Currently catch's return value register cannot be stackified, because
+        // the wasm LLVM backend currently does not support live-in values
+        // entering blocks, which is a part of multi-value proposal.
+        //
+        // Once we support live-in values of wasm blocks, this can be:
+        // catch                           ; push except_ref value onto stack
+        // block except_ref -> i32
+        // br_on_exn $__cpp_exception      ; pop the except_ref value
+        // end_block
+        //
+        // But because we don't support it yet, the catch instruction's dst
+        // register should be assigned to a local to be propagated across
+        // 'block' boundary now.
+        //
+        // TODO Fix this once we support the multi-value proposal.
+        if (Def->getOpcode() == WebAssembly::CATCH)
+          continue;
+
         // Decide which strategy to take. Prefer to move a single-use value
         // over cloning it, and prefer cloning over introducing a tee.
         // For moving, we require the def to be in the same block as the use;

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp Tue Jan 29 19:21:57 2019
@@ -301,8 +301,10 @@ void WebAssemblyPassConfig::addPreEmitPa
   addPass(createWebAssemblyFixIrreducibleControlFlow());
 
   // Do various transformations for exception handling.
+  // Every CFG-changing optimizations should come before this.
   addPass(createWebAssemblyLateEHPrepare());
 
+  // Preparations and optimizations related to register stackification.
   if (getOptLevel() != CodeGenOpt::None) {
     // LiveIntervals isn't commonly run this late. Re-establish preconditions.
     addPass(createWebAssemblyPrepareForLiveIntervals());

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp Tue Jan 29 19:21:57 2019
@@ -242,50 +242,10 @@ bool WebAssembly::isMarker(const Machine
   }
 }
 
-bool WebAssembly::isThrow(const MachineInstr &MI) {
-  switch (MI.getOpcode()) {
-  case WebAssembly::THROW_I32:
-  case WebAssembly::THROW_I32_S:
-  case WebAssembly::THROW_I64:
-  case WebAssembly::THROW_I64_S:
-    return true;
-  default:
-    return false;
-  }
-}
-
-bool WebAssembly::isRethrow(const MachineInstr &MI) {
-  switch (MI.getOpcode()) {
-  case WebAssembly::RETHROW:
-  case WebAssembly::RETHROW_S:
-  case WebAssembly::RETHROW_TO_CALLER:
-  case WebAssembly::RETHROW_TO_CALLER_S:
-    return true;
-  default:
-    return false;
-  }
-}
-
-bool WebAssembly::isCatch(const MachineInstr &MI) {
-  switch (MI.getOpcode()) {
-  case WebAssembly::CATCH_I32:
-  case WebAssembly::CATCH_I32_S:
-  case WebAssembly::CATCH_I64:
-  case WebAssembly::CATCH_I64_S:
-  case WebAssembly::CATCH_ALL:
-  case WebAssembly::CATCH_ALL_S:
-    return true;
-  default:
-    return false;
-  }
-}
-
 bool WebAssembly::mayThrow(const MachineInstr &MI) {
   switch (MI.getOpcode()) {
-  case WebAssembly::THROW_I32:
-  case WebAssembly::THROW_I32_S:
-  case WebAssembly::THROW_I64:
-  case WebAssembly::THROW_I64_S:
+  case WebAssembly::THROW:
+  case WebAssembly::THROW_S:
   case WebAssembly::RETHROW:
   case WebAssembly::RETHROW_S:
     return true;
@@ -308,41 +268,3 @@ bool WebAssembly::mayThrow(const Machine
     return false;
   return true;
 }
-
-bool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) {
-  if (!MBB.isEHPad())
-    return false;
-  bool SeenCatch = false;
-  for (auto &MI : MBB) {
-    if (MI.getOpcode() == WebAssembly::CATCH_I32 ||
-        MI.getOpcode() == WebAssembly::CATCH_I64 ||
-        MI.getOpcode() == WebAssembly::CATCH_I32_S ||
-        MI.getOpcode() == WebAssembly::CATCH_I64_S)
-      SeenCatch = true;
-    if (SeenCatch && MI.isCall()) {
-      const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
-      if (CalleeOp.isGlobal() &&
-          CalleeOp.getGlobal()->getName() == ClangCallTerminateFn)
-        return true;
-    }
-  }
-  return false;
-}
-
-bool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) {
-  if (!MBB.isEHPad())
-    return false;
-  bool SeenCatchAll = false;
-  for (auto &MI : MBB) {
-    if (MI.getOpcode() == WebAssembly::CATCH_ALL ||
-        MI.getOpcode() == WebAssembly::CATCH_ALL_S)
-      SeenCatchAll = true;
-    if (SeenCatchAll && MI.isCall()) {
-      const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
-      if (CalleeOp.isGlobal() &&
-          CalleeOp.getGlobal()->getName() == StdTerminateFn)
-        return true;
-    }
-  }
-  return false;
-}

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h Tue Jan 29 19:21:57 2019
@@ -30,22 +30,12 @@ bool isChild(const MachineInstr &MI, con
 bool isCallDirect(const MachineInstr &MI);
 bool isCallIndirect(const MachineInstr &MI);
 bool isMarker(const MachineInstr &MI);
-bool isThrow(const MachineInstr &MI);
-bool isRethrow(const MachineInstr &MI);
-bool isCatch(const MachineInstr &MI);
 bool mayThrow(const MachineInstr &MI);
 
 /// Returns the operand number of a callee, assuming the argument is a call
 /// instruction.
 unsigned getCalleeOpNo(const MachineInstr &MI);
 
-/// Returns if the given BB is a single BB terminate pad which starts with a
-/// 'catch' instruction.
-bool isCatchTerminatePad(const MachineBasicBlock &MBB);
-/// Returns if the given BB is a single BB terminate pad which starts with a
-/// 'catch_all' insrtruction.
-bool isCatchAllTerminatePad(const MachineBasicBlock &MBB);
-
 // Exception-related function names
 extern const char *const ClangCallTerminateFn;
 extern const char *const CxaBeginCatchFn;

Removed: llvm/trunk/test/CodeGen/WebAssembly/annotations.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/annotations.mir?rev=352597&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/annotations.mir (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/annotations.mir (removed)
@@ -1,94 +0,0 @@
-# RUN: llc -mtriple=wasm32-unknown-unknown -start-after xray-instrumentation -wasm-keep-registers %s -o - | FileCheck %s
-
----
-# Tests if block/loop/try/catch/end instructions are correctly printed with
-# their annotations.
-
-# CHECK: test0:
-# CHECK:   block
-# CHECK:   try
-# CHECK:   br        0               # 0: down to label1
-# CHECK:   catch_all                 # catch0:
-# CHECK:   block
-# CHECK:   br_if     0, 1            # 0: down to label2
-# CHECK:   loop                      # label3:
-# CHECK:   br_if     0, 1            # 0: up to label3
-# CHECK:   end_loop
-# CHECK:   end_block                 # label2:
-# CHECK:   try
-# CHECK:   rethrow   0               # 0: down to catch1
-# CHECK:   catch_all                 # catch1:
-# CHECK:   block
-# CHECK:   try
-# CHECK:   br        0               # 0: down to label6
-# CHECK:   catch_all                 # catch2:
-# CHECK:   unreachable
-# CHECK:   end_try                   # label6:
-# CHECK:   end_block                 # label5:
-# CHECK:   rethrow   0               # 0: to caller
-# CHECK:   end_try                   # label4:
-# CHECK:   end_try                   # label1:
-# CHECK:   end_block                 # label0:
-
-name: test0
-liveins:
-  - { reg: '$arguments', reg: '$value_stack' }
-body: |
-  bb.0:
-    successors: %bb.7, %bb.1
-    BLOCK 64, implicit-def $value_stack, implicit $value_stack
-    TRY 64, implicit-def $value_stack, implicit $value_stack
-    BR 0, implicit-def $arguments
-
-  bb.1 (landing-pad):
-  ; predecessors: %bb.0
-    successors: %bb.2, %bb.3
-
-    CATCH_ALL implicit-def $arguments
-    BLOCK 64, implicit-def $value_stack, implicit $value_stack
-    BR_IF 0, 1, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
-
-  bb.2:
-  ; predecessors: %bb.1, %bb.2
-    successors: %bb.2, %bb.3
-
-    LOOP 64, implicit-def $value_stack, implicit $value_stack
-    BR_IF 0, 1, implicit-def $arguments
-
-  bb.3:
-  ; predecessors: %bb.1, %bb.2
-    successors: %bb.4
-
-    END_LOOP implicit-def $value_stack, implicit $value_stack
-    END_BLOCK implicit-def $value_stack, implicit $value_stack
-    TRY 64, implicit-def $value_stack, implicit $value_stack
-    RETHROW 0, implicit-def $arguments
-
-  bb.4 (landing-pad):
-  ; predecessors: %bb.3
-    successors: %bb.6, %bb.5
-
-    CATCH_ALL implicit-def $arguments
-    BLOCK 64, implicit-def $value_stack, implicit $value_stack
-    TRY 64, implicit-def $value_stack, implicit $value_stack
-    BR 0, implicit-def $arguments
-
-  bb.5 (landing-pad):
-  ; predecessors: %bb.4
-    CATCH_ALL implicit-def $arguments
-    UNREACHABLE implicit-def dead $arguments
-
-  bb.6:
-  ; predecessors: %bb.4
-    END_TRY implicit-def $value_stack, implicit $value_stack
-    END_BLOCK implicit-def $value_stack, implicit $value_stack
-    RETHROW 0, implicit-def $arguments
-
-  bb.7:
-  ; predecessors: %bb.0
-    END_TRY implicit-def $value_stack, implicit $value_stack
-    END_TRY implicit-def $value_stack, implicit $value_stack
-    END_BLOCK implicit-def $value_stack, implicit $value_stack
-    FALLTHROUGH_RETURN_VOID implicit-def dead $arguments
-    END_FUNCTION implicit-def $value_stack, implicit $value_stack
-...

Modified: llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.ll?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.ll Tue Jan 29 19:21:57 2019
@@ -7,21 +7,25 @@ target triple = "wasm32-unknown-unknown"
 @_ZTId = external constant i8*
 
 ; Simple test case with two catch clauses
+; void test0() {
+;   try {
+;     foo();
+;   } catch (int n) {
+;     bar();
+;   } catch (double d) {
+;   }
+; }
 
 ; CHECK-LABEL: test0
+; CHECK:   try
 ; CHECK:   call      foo at FUNCTION
-; CHECK: .LBB0_1:
-; CHECK:   i32.catch
+; CHECK:   catch     $[[EXCEPT_REF:[0-9]+]]=
+; CHECK:   block i32
+; CHECK:   br_on_exn 0, __cpp_exception at EVENT, $[[EXCEPT_REF]]
+; CHECK:   rethrow
+; CHECK:   end_block
 ; CHECK:   i32.call  $drop=, _Unwind_CallPersonality at FUNCTION
-; CHECK:   i32.call  $drop=, __cxa_begin_catch at FUNCTION
-; CHECK:   call      bar at FUNCTION
-; CHECK:   call      __cxa_end_catch at FUNCTION
-; CHECK: .LBB0_3:
-; CHECK:   i32.call  $drop=, __cxa_begin_catch at FUNCTION
-; CHECK:   call      __cxa_end_catch at FUNCTION
-; CHECK: .LBB0_5:
-; CHECK:   call      __cxa_rethrow at FUNCTION
-; CHECK: .LBB0_6:
+; CHECK:   end_try
 ; CHECK:   return
 define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
 entry:
@@ -68,39 +72,45 @@ try.cont:
 }
 
 ; Nested try-catches within a catch
+; void test1() {
+;   try {
+;     foo();
+;   } catch (int n) {
+;     try {
+;       foo();
+;     } catch (int n) {
+;       foo();
+;     }
+;   }
+; }
 
 ; CHECK-LABEL: test1
+; CHECK:   try
 ; CHECK:   call      foo at FUNCTION
-; CHECK: .LBB1_1:
-; CHECK:   i32.catch     $0=, 0
-; CHECK:   i32.call  $drop=, _Unwind_CallPersonality at FUNCTION, $0
-; CHECK:   i32.call  $drop=, __cxa_begin_catch at FUNCTION, $0
-; CHECK:   call      foo at FUNCTION
-; CHECK: .LBB1_3:
-; CHECK:   i32.catch     $0=, 0
-; CHECK:   i32.call  $drop=, _Unwind_CallPersonality at FUNCTION, $0
-; CHECK:   i32.call  $drop=, __cxa_begin_catch at FUNCTION, $0
+; CHECK:   catch
+; CHECK:   br_on_exn 0, __cpp_exception at EVENT
+; CHECK:   rethrow
+; CHECK:   i32.call  $drop=, _Unwind_CallPersonality at FUNCTION
+; CHECK:   try
 ; CHECK:   call      foo at FUNCTION
-; CHECK: .LBB1_5:
-; CHECK:   catch_all
-; CHECK:   call      __cxa_end_catch at FUNCTION
+; CHECK:   catch
+; CHECK:   br_on_exn   0, __cpp_exception at EVENT
 ; CHECK:   rethrow
-; CHECK: .LBB1_6:
-; CHECK:   call      __cxa_rethrow at FUNCTION
+; CHECK:   i32.call  $drop=, _Unwind_CallPersonality at FUNCTION
+; CHECK:   try
+; CHECK:   i32.call  $drop=, __cxa_begin_catch at FUNCTION
+; CHECK:   try
+; CHECK:   call      foo at FUNCTION
+; CHECK:   catch     $drop=
 ; CHECK:   rethrow
-; CHECK: .LBB1_7:
-; CHECK:   call      __cxa_end_catch at FUNCTION
-; CHECK: .LBB1_8:
-; CHECK:   catch_all
-; CHECK:   call      __cxa_end_catch at FUNCTION
-; CHECK: .LBB1_9:
-; CHECK:   call      __cxa_rethrow at FUNCTION
+; CHECK:   end_try
+; CHECK:   catch     $drop=
 ; CHECK:   rethrow
-; CHECK: .LBB1_10:
-; CHECK:   call      __cxa_end_catch at FUNCTION
-; CHECK: .LBB1_11:
+; CHECK:   end_try
+; CHECK:   end_try
+; CHECK:   end_try
 ; CHECK:   return
-define hidden void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
 entry:
   invoke void @foo()
           to label %try.cont11 unwind label %catch.dispatch
@@ -175,30 +185,38 @@ unreachable:
 }
 
 ; Nested loop within a catch clause
+; void test2() {
+;   try {
+;     foo();
+;   } catch (...) {
+;     for (int i = 0; i < 50; i++)
+;       foo();
+;   }
+; }
 
 ; CHECK-LABEL: test2
+; CHECK:   try
 ; CHECK:   call      foo at FUNCTION
-; CHECK: .LBB2_1:
-; CHECK:   i32.catch
-; CHECK:   i32.call  $drop=, __cxa_begin_catch at FUNCTION
-; CHECK: .LBB2_2:
+; CHECK:   catch
+; CHECK:   br_on_exn   0, __cpp_exception at EVENT
+; CHECK:   rethrow
+; CHECK:   loop
+; CHECK:   try
 ; CHECK:   call      foo at FUNCTION
-; CHECK: .LBB2_4:
-; CHECK:   catch_all
+; CHECK:   catch     $drop=
+; CHECK:   try
 ; CHECK:   call      __cxa_end_catch at FUNCTION
-; CHECK: .LBB2_5:
-; CHECK:   i32.catch
-; CHECK:   call      __clang_call_terminate at FUNCTION
+; CHECK:   catch
+; CHECK:   br_on_exn   0, __cpp_exception at EVENT
+; CHECK:   call      __clang_call_terminate at FUNCTION, 0
 ; CHECK:   unreachable
-; CHECK: .LBB2_6:
-; CHECK:   catch_all
-; CHECK:   call      _ZSt9terminatev at FUNCTION
+; CHECK:   call      __clang_call_terminate at FUNCTION
 ; CHECK:   unreachable
-; CHECK: .LBB2_7:
+; CHECK:   end_try
 ; CHECK:   rethrow
-; CHECK: .LBB2_8:
-; CHECK:   call      __cxa_end_catch at FUNCTION
-; CHECK: .LBB2_10:
+; CHECK:   end_try
+; CHECK:   end_loop
+; CHECK:   end_try
 ; CHECK:   return
 define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
 entry:

Removed: llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.mir?rev=352597&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.mir (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/cfg-stackify-eh.mir (removed)
@@ -1,322 +0,0 @@
-# RUN: llc -mtriple=wasm32-unknown-unknown -exception-model=wasm -run-pass wasm-cfg-stackify %s -o - | FileCheck %s
-
---- |
-  target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-  target triple = "wasm32-unknown-unknown"
-
-  @__wasm_lpad_context = external global { i32, i8*, i32 }
-
-  declare void @may_throw()
-  ; Function Attrs: nounwind
-  declare void @dont_throw() #0
-  declare i8* @__cxa_begin_catch(i8*)
-  declare void @__cxa_end_catch()
-  declare void @__cxa_rethrow()
-  ; Function Attrs: nounwind
-  declare i32 @__gxx_wasm_personality_v0(...)
-  declare i32 @_Unwind_CallPersonality(i8*) #0
-
-  define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
-    unreachable
-  }
-  define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
-    unreachable
-  }
-  define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
-    unreachable
-  }
-  define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
-    unreachable
-  }
-
-  attributes #0 = { nounwind }
-
----
-# Simplest try-catch
-# try {
-#   may_throw();
-# } catch (...) {
-# }
-name: test0
-# CHECK-LABEL: name: test0
-liveins:
-  - { reg: '$arguments', reg: '$value_stack' }
-body: |
-  bb.0:
-    successors: %bb.2, %bb.1
-
-    CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    BR %bb.2, implicit-def $arguments
-  ; CHECK-LABEL: bb.0:
-    ; CHECK: TRY
-    ; CHECK-NEXT: CALL_VOID @may_throw
-
-  bb.1 (landing-pad):
-  ; predecessors: %bb.0
-    successors: %bb.2
-
-    %2:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %3:i32 = CALL_I32 @__cxa_begin_catch, %2:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack
-    DROP_I32 killed %3:i32, implicit-def $arguments
-    CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-
-  bb.2:
-  ; predecessors: %bb.0, %bb.1
-
-    RETURN_VOID implicit-def dead $arguments
-  ; CHECK-LABEL: bb.2:
-    ; CHECK-NEXT: END_TRY
-    ; CHECK: RETURN_VOID
-...
----
-
-# Nested try-catch inside another catch
-#  try {
-#    may_throw();
-#  } catch (int n) {
-#    try {
-#      may_throw();
-#    } catch (int n) {
-#    }
-#  }
-name: test1
-# CHECK-LABEL: name: test1
-liveins:
-  - { reg: '$arguments', reg: '$value_stack' }
-body: |
-  bb.0:
-    successors: %bb.9, %bb.1
-
-    CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    BR %bb.9, implicit-def $arguments
-  ; CHECK-LABEL: bb.0:
-    ; CHECK: TRY
-    ; CHECK-NEXT: CALL_VOID @may_throw
-
-  bb.1 (landing-pad):
-  ; predecessors: %bb.0
-    successors: %bb.2, %bb.7
-
-    %30:i32 = CATCH_I32 0, implicit-def dead $arguments
-    LOCAL_SET_I32 0, %30:i32, implicit-def $arguments
-    %16:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %27:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    STORE_I32 2, @__wasm_lpad_context + 4, %16:i32, %27:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (store 4 into `i8** getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 1)`)
-    %26:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %25:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    STORE_I32 2, @__wasm_lpad_context, %26:i32, %25:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (store 4 into `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 0)`)
-    %32:i32 = LOCAL_GET_I32 0, implicit-def $arguments
-    %31:i32 = CALL_I32 @_Unwind_CallPersonality, %32:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    DROP_I32 killed %31:i32, implicit-def $arguments
-    %24:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %17:i32 = LOAD_I32 2, @__wasm_lpad_context + 8, %24:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (dereferenceable load 4 from `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 2)`)
-    %18:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %19:i32 = NE_I32 %17:i32, %18:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    BR_IF %bb.7, %19:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
-
-  bb.2:
-  ; predecessors: %bb.1
-    successors: %bb.8, %bb.3, %bb.6
-
-    %34:i32 = LOCAL_GET_I32 0, implicit-def $arguments
-    %33:i32 = CALL_I32 @__cxa_begin_catch, %34:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    DROP_I32 killed %33:i32, implicit-def $arguments
-    CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    BR %bb.8, implicit-def $arguments
-  ; CHECK-LABEL: bb.2:
-    ; CHECK: DROP_I32
-    ; CHECK-NEXT: TRY
-    ; CHECK-NEXT: TRY
-    ; CHECK-NEXT: CALL_VOID @may_throw
-
-  bb.3 (landing-pad):
-  ; predecessors: %bb.2
-    successors: %bb.4, %bb.5
-
-    %35:i32 = CATCH_I32 0, implicit-def dead $arguments
-    LOCAL_SET_I32 0, %35:i32, implicit-def $arguments
-    %21:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %20:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    STORE_I32 2, @__wasm_lpad_context, %21:i32, %20:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (store 4 into `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 0)`)
-    %37:i32 = LOCAL_GET_I32 0, implicit-def $arguments
-    %36:i32 = CALL_I32 @_Unwind_CallPersonality, %37:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    DROP_I32 killed %36:i32, implicit-def $arguments
-    %29:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %22:i32 = LOAD_I32 2, @__wasm_lpad_context + 8, %29:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack :: (dereferenceable load 4 from `i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 2)`)
-    %28:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %23:i32 = NE_I32 %22:i32, %28:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    BR_IF %bb.5, %23:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
-
-  bb.4:
-  ; predecessors: %bb.3
-    successors: %bb.8
-
-    %39:i32 = LOCAL_GET_I32 0, implicit-def $arguments
-    %38:i32 = CALL_I32 @__cxa_begin_catch, %39:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    DROP_I32 killed %38:i32, implicit-def $arguments
-    CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    BR %bb.8, implicit-def $arguments
-
-  bb.5:
-  ; predecessors: %bb.3
-    successors: %bb.6
-
-    CALL_VOID @__cxa_rethrow, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    RETHROW %bb.6, implicit-def $arguments
-
-  bb.6 (landing-pad):
-  ; predecessors: %bb.2, %bb.5
-
-    CATCH_ALL implicit-def $arguments
-    CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    RETHROW_TO_CALLER implicit-def $arguments
-  ; CHECK-LABEL: bb.6 (landing-pad):
-    ; CHECK-NEXT: END_TRY
-
-  bb.7:
-  ; predecessors: %bb.1
-
-    CALL_VOID @__cxa_rethrow, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    RETHROW_TO_CALLER implicit-def $arguments
-  ; CHECK-LABEL: bb.7:
-    ; CHECK-NEXT: END_TRY
-    ; CHECK: RETHROW 0
-
-  bb.8:
-  ; predecessors: %bb.2, %bb.4
-    successors: %bb.9
-
-    CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-
-  bb.9:
-  ; predecessors: %bb.0, %bb.8
-
-    RETURN_VOID implicit-def dead $arguments
-  ; CHECK-LABEL: bb.9:
-    ; CHECK-NEXT: END_TRY
-...
----
-
-# A loop within a try.
-#  try {
-#    for (int i = 0; i < n; ++i)
-#      may_throw();
-#  } catch (...) {
-#  }
-name: test2
-# CHECK-LABEL: name: test2
-liveins:
-  - { reg: '$arguments', reg: '$value_stack' }
-body: |
-  bb.0:
-    successors: %bb.1, %bb.4
-
-    %18:i32 = CONST_I32 0, implicit-def dead $arguments
-    LOCAL_SET_I32 1, %18:i32, implicit-def $arguments
-    %14:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %19:i32 = LOCAL_GET_I32 0, implicit-def $arguments
-    %9:i32 = GE_S_I32 %14:i32, %19:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    BR_IF %bb.4, %9:i32, implicit-def $arguments
-
-  bb.1:
-  ; predecessors: %bb.0, %bb.3
-    successors: %bb.3, %bb.2
-
-    CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    BR %bb.3, implicit-def $arguments
-  ; CHECK-LABEL: bb.1:
-    ; CHECK: LOOP
-    ; CHECK: TRY
-    ; CHECK-NEXT: CALL_VOID @may_throw
-
-  bb.2 (landing-pad):
-  ; predecessors: %bb.1
-    successors: %bb.4
-
-    %11:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %22:i32 = CALL_I32 @__cxa_begin_catch, %11:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack
-    DROP_I32 killed %22:i32, implicit-def $arguments
-    CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    BR %bb.4, implicit-def $arguments
-
-  bb.3:
-  ; predecessors: %bb.1
-    successors: %bb.1, %bb.4
-
-    %20:i32 = LOCAL_GET_I32 1, implicit-def $arguments
-    %17:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %16:i32 = ADD_I32 %20:i32, %17:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %15:i32 = LOCAL_TEE_I32 1, %16:i32, implicit-def $arguments
-    %21:i32 = LOCAL_GET_I32 0, implicit-def $arguments
-    %10:i32 = GE_S_I32 %15:i32, %21:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    BR_UNLESS %bb.1, %10:i32, implicit-def $arguments
-  ; CHECK-LABEL: bb.3:
-    ; CHECK: END_TRY
-
-  bb.4:
-  ; predecessors: %bb.2, %bb.0, %bb.3
-
-    RETURN_VOID implicit-def dead $arguments
-...
----
-
-# A loop within a catch
-#  try {
-#    may_throw();
-#  } catch (...) {
-#    for (int i = 0; i < n; ++i)
-#      dont_throw();
-#  }
-name: test3
-# CHECK-LABEL: name: test3
-liveins:
-  - { reg: '$arguments', reg: '$value_stack' }
-body: |
-  bb.0:
-    successors: %bb.4, %bb.1
-
-    CALL_VOID @may_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    BR %bb.4, implicit-def $arguments
-  ; CHECK-LABEL: bb.0:
-    ; CHECK: TRY
-    ; CHECK-NEXT: CALL_VOID @may_throw
-
-  bb.1 (landing-pad):
-  ; predecessors: %bb.0
-    successors: %bb.2, %bb.3
-
-    %9:i32 = CATCH_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %18:i32 = CALL_I32 @__cxa_begin_catch, %9:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64, implicit-def $value_stack, implicit $value_stack
-    DROP_I32 killed %18:i32, implicit-def $arguments
-    %19:i32 = CONST_I32 0, implicit-def dead $arguments
-    LOCAL_SET_I32 1, %19:i32, implicit-def $arguments
-    %14:i32 = CONST_I32 0, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %20:i32 = LOCAL_GET_I32 0, implicit-def $arguments
-    %10:i32 = GE_S_I32 %14:i32, %20:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    BR_IF %bb.3, %10:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
-
-  bb.2:
-  ; predecessors: %bb.1, %bb.2
-    successors: %bb.2, %bb.3
-
-    CALL_VOID @dont_throw, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-    %21:i32 = LOCAL_GET_I32 1, implicit-def $arguments
-    %17:i32 = CONST_I32 1, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %16:i32 = ADD_I32 %21:i32, %17:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    %15:i32 = LOCAL_TEE_I32 1, %16:i32, implicit-def $arguments
-    %22:i32 = LOCAL_GET_I32 0, implicit-def $arguments
-    %11:i32 = GE_S_I32 %15:i32, %22:i32, implicit-def dead $arguments, implicit-def $value_stack, implicit $value_stack
-    BR_UNLESS %bb.2, %11:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
-
-  bb.3:
-  ; predecessors: %bb.1, %bb.2
-    successors: %bb.4
-
-    CALL_VOID @__cxa_end_catch, implicit-def dead $arguments, implicit $sp32, implicit $sp64
-
-  bb.4:
-  ; predecessors: %bb.0, %bb.3
-
-    RETURN_VOID implicit-def dead $arguments
-  ; CHECK-LABEL: bb.4:
-    ; CHECK: END_TRY

Modified: llvm/trunk/test/CodeGen/WebAssembly/exception.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/exception.ll?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/exception.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/exception.ll Tue Jan 29 19:21:57 2019
@@ -1,5 +1,5 @@
 ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck -allow-deprecated-dag-overlap %s
+; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck -allow-deprecated-dag-overlap %s
 ; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
@@ -9,30 +9,39 @@ target triple = "wasm32-unknown-unknown"
 
 @_ZTIi = external constant i8*
 
-declare void @llvm.wasm.throw(i32, i8*)
-
 ; CHECK-LABEL: test_throw:
-; CHECK:      local.get $push0=, 0
-; CHECK-NEXT: throw __cpp_exception at EVENT, $pop0
+; CHECK: throw __cpp_exception at EVENT, $0
 ; CHECK-NOT:  unreachable
 define void @test_throw(i8* %p) {
   call void @llvm.wasm.throw(i32 0, i8* %p)
   ret void
 }
 
+; CHECK-LABEL: test_rethrow:
+; CHECK:      rethrow
+; CHECK-NOT:  unreachable
+define void @test_rethrow(i8* %p) {
+  call void @llvm.wasm.rethrow()
+  ret void
+}
+
 ; CHECK-LABEL: test_catch_rethrow:
-; CHECK:   global.get  $push{{.+}}=, __stack_pointer at GLOBAL
+; CHECK:   global.get  ${{.+}}=, __stack_pointer at GLOBAL
 ; CHECK:   try
 ; CHECK:   call      foo at FUNCTION
-; CHECK:   i32.catch     $push{{.+}}=, 0
+; CHECK:   catch     $[[EXCEPT_REF:[0-9]+]]=
+; CHECK:   block i32
+; CHECK:   br_on_exn 0, __cpp_exception at EVENT, $[[EXCEPT_REF]]
+; CHECK:   rethrow
+; CHECK:   end_block
+; CHECK:   extract_exception $[[EXN:[0-9]+]]=
 ; CHECK:   global.set  __stack_pointer at GLOBAL
 ; CHECK-DAG:   i32.store  __wasm_lpad_context
 ; CHECK-DAG:   i32.store  __wasm_lpad_context+4
-; CHECK:   i32.call  $push{{.+}}=, _Unwind_CallPersonality at FUNCTION
-; CHECK:   i32.call  $push{{.+}}=, __cxa_begin_catch at FUNCTION
+; CHECK:   i32.call  $drop=, _Unwind_CallPersonality at FUNCTION, $[[EXN]]
+; CHECK:   i32.call  $drop=, __cxa_begin_catch at FUNCTION
 ; CHECK:   call      __cxa_end_catch at FUNCTION
 ; CHECK:   call      __cxa_rethrow at FUNCTION
-; CHECK-NEXT:   rethrow
 ; CHECK:   end_try
 define void @test_catch_rethrow() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
 entry:
@@ -66,9 +75,9 @@ try.cont:
 ; CHECK-LABEL: test_cleanup:
 ; CHECK:   try
 ; CHECK:   call      foo at FUNCTION
-; CHECK:   catch_all
+; CHECK:   catch
 ; CHECK:   global.set  __stack_pointer at GLOBAL
-; CHECK:   i32.call  $push{{.+}}=, _ZN7CleanupD1Ev at FUNCTION
+; CHECK:   i32.call  $drop=, _ZN7CleanupD1Ev at FUNCTION
 ; CHECK:   rethrow
 ; CHECK:   end_try
 define void @test_cleanup() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
@@ -87,71 +96,51 @@ ehcleanup:
   cleanupret from %0 unwind to caller
 }
 
-; - Tests multple terminate pads are merged into one
-; - Tests a catch_all terminate pad is created after a catch terminate pad
-
 ; CHECK-LABEL: test_terminatepad
-; CHECK:  i32.catch
-; CHECK:  call      __clang_call_terminate at FUNCTION
-; CHECK:  unreachable
-; CHECK:  catch_all
-; CHECK:  call      _ZSt9terminatev at FUNCTION
-; CHECK-NOT:  call      __clang_call_terminate at FUNCTION
-define hidden i32 @test_terminatepad() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+; CHECK:   catch
+; CHECK:   block     i32
+; CHECK:   br_on_exn   0, __cpp_exception at EVENT
+; CHECK:   call      __clang_call_terminate at FUNCTION, 0
+; CHECK:   unreachable
+; CHECK:   end_block
+; CHECK:   extract_exception
+; CHECK:   call      __clang_call_terminate at FUNCTION
+; CHECK:   unreachable
+define void @test_terminatepad() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
 entry:
-  %c = alloca %struct.Cleanup, align 1
-  %c1 = alloca %struct.Cleanup, align 1
   invoke void @foo()
-          to label %invoke.cont unwind label %ehcleanup
-
-invoke.cont:                                      ; preds = %entry
-  %call = invoke %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c1)
           to label %try.cont unwind label %catch.dispatch
 
-ehcleanup:                                        ; preds = %entry
-  %0 = cleanuppad within none []
-  %call4 = invoke %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c1) [ "funclet"(token %0) ]
-          to label %invoke.cont3 unwind label %terminate
+catch.dispatch:                                   ; preds = %entry
+  %0 = catchswitch within none [label %catch.start] unwind to caller
 
-invoke.cont3:                                     ; preds = %ehcleanup
-  cleanupret from %0 unwind label %catch.dispatch
+catch.start:                                      ; preds = %catch.dispatch
+  %1 = catchpad within %0 [i8* null]
+  %2 = call i8* @llvm.wasm.get.exception(token %1)
+  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
+  %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
+  invoke void @foo() [ "funclet"(token %1) ]
+          to label %invoke.cont1 unwind label %ehcleanup
 
-catch.dispatch:                                   ; preds = %invoke.cont3, %invoke.cont
-  %1 = catchswitch within none [label %catch.start] unwind label %ehcleanup7
+invoke.cont1:                                     ; preds = %catch.start
+  call void @__cxa_end_catch() [ "funclet"(token %1) ]
+  catchret from %1 to label %try.cont
 
-catch.start:                                      ; preds = %catch.dispatch
-  %2 = catchpad within %1 [i8* null]
-  %3 = call i8* @llvm.wasm.get.exception(token %2)
-  %4 = call i32 @llvm.wasm.get.ehselector(token %2)
-  %5 = call i8* @__cxa_begin_catch(i8* %3) [ "funclet"(token %2) ]
-  invoke void @__cxa_end_catch() [ "funclet"(token %2) ]
-          to label %invoke.cont5 unwind label %ehcleanup7
-
-invoke.cont5:                                     ; preds = %catch.start
-  catchret from %2 to label %try.cont
-
-try.cont:                                         ; preds = %invoke.cont5, %invoke.cont
-  %call6 = call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c)
-  ret i32 0
-
-ehcleanup7:                                       ; preds = %catch.start, %catch.dispatch
-  %6 = cleanuppad within none []
-  %call9 = invoke %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c) [ "funclet"(token %6) ]
-          to label %invoke.cont8 unwind label %terminate10
+try.cont:                                         ; preds = %entry, %invoke.cont1
+  ret void
 
-invoke.cont8:                                     ; preds = %ehcleanup7
-  cleanupret from %6 unwind to caller
+ehcleanup:                                        ; preds = %catch.start
+  %5 = cleanuppad within %1 []
+  invoke void @__cxa_end_catch() [ "funclet"(token %5) ]
+          to label %invoke.cont2 unwind label %terminate
 
-terminate:                                        ; preds = %ehcleanup
-  %7 = cleanuppad within %0 []
-  %8 = call i8* @llvm.wasm.get.exception(token %7)
-  call void @__clang_call_terminate(i8* %8) [ "funclet"(token %7) ]
-  unreachable
+invoke.cont2:                                     ; preds = %ehcleanup
+  cleanupret from %5 unwind to caller
 
-terminate10:                                      ; preds = %ehcleanup7
-  %9 = cleanuppad within %6 []
-  %10 = call i8* @llvm.wasm.get.exception(token %9)
-  call void @__clang_call_terminate(i8* %10) [ "funclet"(token %9) ]
+terminate:                                        ; preds = %ehcleanup
+  %6 = cleanuppad within %5 []
+  %7 = call i8* @llvm.wasm.get.exception(token %6)
+  call void @__clang_call_terminate(i8* %7) [ "funclet"(token %6) ]
   unreachable
 }
 
@@ -164,12 +153,12 @@ terminate10:
 ; CHECK-LABEL: test_no_prolog_epilog_in_ehpad
 ; CHECK:  try
 ; CHECK:  call      foo at FUNCTION
-; CHECK:  i32.catch
+; CHECK:  catch
 ; CHECK-NOT:  global.get  $push{{.+}}=, __stack_pointer at GLOBAL
 ; CHECK:  global.set  __stack_pointer at GLOBAL
 ; CHECK:  try
 ; CHECK:  call      foo at FUNCTION
-; CHECK:  catch_all
+; CHECK:  catch
 ; CHECK-NOT:  global.get  $push{{.+}}=, __stack_pointer at GLOBAL
 ; CHECK:  global.set  __stack_pointer at GLOBAL
 ; CHECK:  call      __cxa_end_catch at FUNCTION
@@ -251,6 +240,8 @@ try.cont:
 declare void @foo()
 declare void @bar(i32*)
 declare i32 @__gxx_wasm_personality_v0(...)
+declare void @llvm.wasm.throw(i32, i8*)
+declare void @llvm.wasm.rethrow()
 declare i8* @llvm.wasm.get.exception(token)
 declare i32 @llvm.wasm.get.ehselector(token)
 declare i32 @llvm.eh.typeid.for(i8*)
@@ -258,7 +249,6 @@ declare i8* @__cxa_begin_catch(i8*)
 declare void @__cxa_end_catch()
 declare void @__cxa_rethrow()
 declare void @__clang_call_terminate(i8*)
-declare void @_ZSt9terminatev()
 declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned)
 
 ; CHECK: __cpp_exception:

Modified: llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/wasmehprepare.ll Tue Jan 29 19:21:57 2019
@@ -29,7 +29,7 @@ catch.start:
   br i1 %matches, label %catch, label %rethrow
 ; CHECK: catch.start:
 ; CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad
-; CHECK-NEXT:   %[[EXN:.*]] = call i8* @llvm.wasm.catch(i32 0)
+; CHECK-NEXT:   %[[EXN:.*]] = call i8* @llvm.wasm.extract.exception()
 ; CHECK-NEXT:   call void @llvm.wasm.landingpad.index(token %[[CATCHPAD]], i32 0)
 ; CHECK-NEXT:   store i32 0, i32* getelementptr inbounds ({ i32, i8*, i32 }, { i32, i8*, i32 }* @__wasm_lpad_context, i32 0, i32 0)
 ; CHECK-NEXT:   %[[LSDA:.*]] = call i8* @llvm.wasm.lsda()
@@ -76,7 +76,6 @@ catch.start:
   catchret from %1 to label %try.cont
 ; CHECK: catch.start:
 ; CHECK-NEXT:   catchpad within %0 [i8* null]
-; CHECK-NEXT:   call i8* @llvm.wasm.catch(i32 0)
 ; CHECK-NOT:   call void @llvm.wasm.landingpad.index
 ; CHECK-NOT:   store {{.*}} @__wasm_lpad_context
 ; CHECK-NOT:   call i8* @llvm.wasm.lsda()
@@ -178,7 +177,6 @@ ehcleanup:
   cleanupret from %12 unwind to caller
 ; CHECK: ehcleanup:
 ; CHECK-NEXT:   cleanuppad
-; CHECK-NOT:   call i8* @llvm.wasm.catch(i32 0)
 ; CHECK-NOT:   call void @llvm.wasm.landingpad.index
 ; CHECK-NOT:   store {{.*}} @__wasm_lpad_context
 ; CHECK-NOT:   call i8* @llvm.wasm.lsda()
@@ -191,7 +189,7 @@ unreachable:
 
 ; A cleanuppad with a call to __clang_call_terminate().
 ; A call to wasm.catch() should be generated after the cleanuppad.
-define hidden void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
 ; CHECK-LABEL: @test3
 entry:
   invoke void @foo()
@@ -230,14 +228,14 @@ terminate:
   unreachable
 ; CHECK: terminate:
 ; CHECK-NEXT: cleanuppad
-; CHECK-NEXT:   %[[EXN:.*]] = call i8* @llvm.wasm.catch(i32 0)
+; CHECK-NEXT:   %[[EXN:.*]] = call i8* @llvm.wasm.extract.exception
 ; CHECK-NEXT:   call void @__clang_call_terminate(i8* %[[EXN]])
 }
 
 ; PHI demotion test. Only the phi before catchswitch should be demoted; the phi
 ; before cleanuppad should NOT.
-define void @test5() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
-; CHECK-LABEL: @test5
+define void @test4() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+; CHECK-LABEL: @test4
 entry:
   %c = alloca %struct.Cleanup, align 1
   invoke void @foo()
@@ -301,8 +299,8 @@ try.cont10:
 ; Tests if instructions after a call to @llvm.wasm.throw are deleted and the
 ; BB's dead children are deleted.
 
-; CHECK-LABEL: @test6
-define i32 @test6(i1 %b, i8* %p) {
+; CHECK-LABEL: @test5
+define i32 @test5(i1 %b, i8* %p) {
 entry:
   br i1 %b, label %bb.true, label %bb.false
 
@@ -326,6 +324,34 @@ merge:
   ret i32 0
 }
 
+; Tests if instructions after a call to @llvm.wasm.rethrow are deleted and the
+; BB's dead children are deleted.
+
+; CHECK-LABEL: @test6
+define i32 @test6(i1 %b, i8* %p) {
+entry:
+  br i1 %b, label %bb.true, label %bb.false
+
+; CHECK:      bb.true:
+; CHECK-NEXT:   call void @llvm.wasm.rethrow()
+; CHECK-NEXT:   unreachable
+bb.true:                                          ; preds = %entry
+  call void @llvm.wasm.rethrow()
+  br label %bb.true.0
+
+; CHECK-NOT:  bb.true.0
+bb.true.0:                                        ; preds = %bb.true
+  br label %merge
+
+; CHECK:      bb.false
+bb.false:                                         ; preds = %entry
+  br label %merge
+
+; CHECK:      merge
+merge:                                            ; preds = %bb.true.0, %bb.false
+  ret i32 0
+}
+
 declare void @foo()
 declare void @func(i32)
 declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned)
@@ -334,12 +360,12 @@ declare i8* @llvm.wasm.get.exception(tok
 declare i32 @llvm.wasm.get.ehselector(token)
 declare i32 @llvm.eh.typeid.for(i8*)
 declare void @llvm.wasm.throw(i32, i8*)
+declare void @llvm.wasm.rethrow()
 declare i8* @__cxa_begin_catch(i8*)
 declare void @__cxa_end_catch()
 declare void @__cxa_rethrow()
 declare void @__clang_call_terminate(i8*)
 
-; CHECK-DAG: declare i8* @llvm.wasm.catch(i32)
 ; CHECK-DAG: declare void @llvm.wasm.landingpad.index(token, i32)
 ; CHECK-DAG: declare i8* @llvm.wasm.lsda()
 ; CHECK-DAG: declare i32 @_Unwind_CallPersonality(i8*)

Added: llvm/trunk/test/MC/WebAssembly/annotations.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/WebAssembly/annotations.s?rev=352598&view=auto
==============================================================================
--- llvm/trunk/test/MC/WebAssembly/annotations.s (added)
+++ llvm/trunk/test/MC/WebAssembly/annotations.s Tue Jan 29 19:21:57 2019
@@ -0,0 +1,71 @@
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+exception-handling < %s | FileCheck %s
+
+# Tests if block/loop/try/catch/end/branch/rethrow instructions are correctly
+# printed with their annotations.
+
+  .text
+  .section .text.test_annotation,"",@
+  .type    test_annotation, at function
+test_annotation:
+  .functype   test_annotation () -> ()
+  .eventtype  __cpp_exception i32
+  try
+  br        0
+  catch
+  block
+  br_if     0
+  loop
+  br_if     1
+  end_loop
+  end_block
+  try
+  rethrow
+  catch
+  block
+  try
+  br        0
+  catch
+  local.set 0
+  block    i32
+  local.get 0
+  br_on_exn 0, __cpp_exception at EVENT
+  rethrow
+  end_block
+  end_try
+  end_block
+  rethrow
+  end_try
+  end_try
+  end_function
+
+
+# CHECK:      test_annotation:
+# CHECK:        try
+# CHECK-NEXT:   br        0               # 0: down to label0
+# CHECK-NEXT:   catch                     # catch0:
+# CHECK-NEXT:   block
+# CHECK-NEXT:   br_if     0               # 0: down to label1
+# CHECK-NEXT:   loop                      # label2:
+# CHECK-NEXT:   br_if     1               # 1: down to label1
+# CHECK-NEXT:   end_loop
+# CHECK-NEXT:   end_block                 # label1:
+# CHECK-NEXT:   try
+# CHECK-NEXT:   rethrow                   # down to catch1
+# CHECK-NEXT:   catch                     # catch1:
+# CHECK-NEXT:   block
+# CHECK-NEXT:   try
+# CHECK-NEXT:   br        0               # 0: down to label5
+# CHECK-NEXT:   catch                     # catch2:
+# CHECK-NEXT:   local.set 0
+# CHECK-NEXT:   block    i32
+# CHECK-NEXT:   local.get 0
+# CHECK-NEXT:   br_on_exn 0, __cpp_exception at EVENT # 0: down to label6
+# CHECK-NEXT:   rethrow                   # to caller
+# CHECK-NEXT:   end_block                 # label6:
+# CHECK-NEXT:   end_try                   # label5:
+# CHECK-NEXT:   end_block                 # label4:
+# CHECK-NEXT:   rethrow                   # to caller
+# CHECK-NEXT:   end_try                   # label3:
+# CHECK-NEXT:   end_try                   # label0:
+# CHECK-NEXT:   end_function
+

Modified: llvm/trunk/test/MC/WebAssembly/basic-assembly.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/WebAssembly/basic-assembly.s?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/test/MC/WebAssembly/basic-assembly.s (original)
+++ llvm/trunk/test/MC/WebAssembly/basic-assembly.s Tue Jan 29 19:21:57 2019
@@ -71,11 +71,18 @@ test0:
     i32.trunc_f32_s
     try         except_ref
 .LBB0_3:
-    i32.catch   0
+    catch
+    local.set 0
+    block       i32
+    local.get 0
+    br_on_exn 0, __cpp_exception at EVENT
+    rethrow
 .LBB0_4:
-    catch_all
-.LBB0_5:
+    end_block
     end_try
+    i32.const 0
+    throw 0
+.LBB0_5:
     #i32.trunc_sat_f32_s
     global.get  __stack_pointer at GLOBAL
     end_function
@@ -143,11 +150,18 @@ test0:
 # CHECK-NEXT:      i32.trunc_f32_s
 # CHECK-NEXT:      try         except_ref
 # CHECK-NEXT:  .LBB0_3:
-# CHECK-NEXT:      i32.catch   0
+# CHECK-NEXT:      catch
+# CHECK-NEXT:      local.set 0
+# CHECK-NEXT:      block       i32
+# CHECK-NEXT:      local.get 0
+# CHECK-NEXT:      br_on_exn 0, __cpp_exception at EVENT
+# CHECK-NEXT:      rethrow
 # CHECK-NEXT:  .LBB0_4:
-# CHECK-NEXT:      catch_all
-# CHECK-NEXT:  .LBB0_5:
+# CHECK-NEXT:      end_block
 # CHECK-NEXT:      end_try
+# CHECK-NEXT:      i32.const 0
+# CHECK-NEXT:      throw 0
+# CHECK-NEXT:  .LBB0_5:
 # CHECK-NEXT:      global.get  __stack_pointer at GLOBAL
 # CHECK-NEXT:      end_function
 

Modified: llvm/trunk/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp?rev=352598&r1=352597&r2=352598&view=diff
==============================================================================
--- llvm/trunk/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp (original)
+++ llvm/trunk/unittests/Target/WebAssembly/WebAssemblyExceptionInfoTest.cpp Tue Jan 29 19:21:57 2019
@@ -74,7 +74,7 @@ TEST(WebAssemblyExceptionInfoTest, TEST0
 
   declare i32 @__gxx_wasm_personality_v0(...)
 
-  define hidden void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+  define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
     unreachable
   }
 
@@ -100,14 +100,14 @@ body: |
   ; predecessors: %bb.0
     successors: %bb.3, %bb.9
     liveins: $value_stack
-    CATCH_ALL implicit-def $arguments
+    %0:except_ref = CATCH implicit-def $arguments
     CLEANUPRET implicit-def dead $arguments
 
   bb.3 (landing-pad):
   ; predecessors: %bb.2
     successors: %bb.4, %bb.6
     liveins: $value_stack
-    CATCH_ALL implicit-def $arguments
+    %1:except_ref = CATCH implicit-def $arguments
     BR_IF %bb.4, %58:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
     BR %bb.6, implicit-def $arguments
 
@@ -138,13 +138,13 @@ body: |
   ; predecessors: %bb.4
     successors: %bb.9
     liveins: $value_stack
-    CATCH_ALL implicit-def $arguments
+    %2:except_ref = CATCH implicit-def $arguments
     CLEANUPRET implicit-def dead $arguments
 
   bb.9 (landing-pad):
   ; predecessors: %bb.2, %bb.6, %bb.8
     liveins: $value_stack
-    CATCH_ALL implicit-def $arguments
+    %3:except_ref = CATCH implicit-def $arguments
     CLEANUPRET implicit-def dead $arguments
 
   bb.10:
@@ -237,7 +237,7 @@ TEST(WebAssemblyExceptionInfoTest, TEST1
 
   declare i32 @__gxx_wasm_personality_v0(...)
 
-  define hidden void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+  define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
     unreachable
   }
 
@@ -257,7 +257,7 @@ body: |
   ; predecessors: %bb.0
     successors: %bb.2, %bb.8
     liveins: $value_stack
-    %52:i32 = CATCH_I32 0, implicit-def dead $arguments
+    %0:except_ref = CATCH implicit-def $arguments
     BR_IF %bb.2, %32:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
     BR %bb.8, implicit-def $arguments
 
@@ -271,7 +271,7 @@ body: |
   ; predecessors: %bb.2
     successors: %bb.4, %bb.6
     liveins: $value_stack
-    CATCH_ALL implicit-def $arguments
+    %1:except_ref = CATCH implicit-def $arguments
     BR_IF %bb.4, %43:i32, implicit-def $arguments, implicit-def $value_stack, implicit $value_stack
     BR %bb.6, implicit-def $arguments
 
@@ -313,13 +313,13 @@ body: |
   ; predecessors: %bb.4
     successors: %bb.11
     liveins: $value_stack
-    CATCH_ALL implicit-def $arguments
+    %2:except_ref = CATCH implicit-def $arguments
     CLEANUPRET implicit-def dead $arguments
 
   bb.11 (landing-pad):
   ; predecessors: %bb.2, %bb.6, %bb.10
     liveins: $value_stack
-    CATCH_ALL implicit-def $arguments
+    %3:except_ref = CATCH implicit-def $arguments
     CLEANUPRET implicit-def dead $arguments
 
   bb.12:
@@ -415,135 +415,3 @@ body: |
   EXPECT_EQ(WE0_1->getParentException(), WE0);
   EXPECT_EQ(WE0_1->getExceptionDepth(), (unsigned)2);
 }
-
-// Terminate pad test
-TEST(WebAssemblyExceptionInfoTest, TEST2) {
-  std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
-  ASSERT_TRUE(TM);
-
-  StringRef MIRString = R"MIR(
---- |
-  target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-  target triple = "wasm32-unknown-unknown"
-
-  declare i32 @__gxx_wasm_personality_v0(...)
-  declare void @_ZSt9terminatev()
-  declare void @__clang_call_terminate(i8*)
-
-  define hidden void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
-    unreachable
-  }
-
-...
----
-name: test2
-liveins:
-  - { reg: '$arguments' }
-  - { reg: '$value_stack' }
-body: |
-  bb.0:
-    successors: %bb.3, %bb.1
-    BR %bb.3, implicit-def dead $arguments
-
-  bb.1 (landing-pad):
-  ; predecessors: %bb.0
-    successors: %bb.2, %bb.4
-    %3:i32 = CATCH_I32 0, implicit-def dead $arguments
-    BR %bb.2, implicit-def dead $arguments
-
-  bb.2:
-  ; predecessors: %bb.1
-    successors: %bb.3(0x80000000); %bb.3(200.00%)
-    CATCHRET %bb.3, %bb.0, implicit-def dead $arguments
-
-  bb.3:
-  ; predecessors: %bb.0, %bb.2
-    RETURN_VOID implicit-def $arguments
-
-  bb.4 (landing-pad):
-  ; predecessors: %bb.1
-    successors: %bb.5, %bb.6
-    CATCH_ALL implicit-def $arguments
-    BR %bb.5, implicit-def dead $arguments
-
-  bb.5:
-  ; predecessors: %bb.4
-    CLEANUPRET implicit-def dead $arguments
-
-  bb.6 (landing-pad):
-  ; predecessors: %bb.4
-    successors: %bb.7(0x80000000); %bb.7(200.00%)
-    %6:i32 = CATCH_I32 0, implicit-def dead $arguments
-    CALL_VOID @__clang_call_terminate, %7:i32, implicit-def $arguments
-    UNREACHABLE implicit-def $arguments
-
-  bb.7 (landing-pad):
-  ; predecessors: %bb.6
-    CATCH_ALL implicit-def $arguments
-    CALL_VOID @_ZSt9terminatev, implicit-def $arguments
-    UNREACHABLE implicit-def $arguments
-)MIR";
-
-  LLVMContext Context;
-  std::unique_ptr<MIRParser> MIR;
-  MachineModuleInfo MMI(TM.get());
-  std::unique_ptr<Module> M =
-      parseMIR(Context, MIR, *TM, MIRString, "test2", MMI);
-  ASSERT_TRUE(M);
-
-  Function *F = M->getFunction("test2");
-  auto *MF = MMI.getMachineFunction(*F);
-  ASSERT_TRUE(MF);
-
-  WebAssemblyExceptionInfo WEI;
-  MachineDominatorTree MDT;
-  MachineDominanceFrontier MDF;
-  MDT.runOnMachineFunction(*MF);
-  MDF.getBase().analyze(MDT.getBase());
-  WEI.recalculate(MDT, MDF);
-
-  // Exception info structure:
-  // |- bb1 (ehpad), bb2, bb4, bb5, bb6, bb7
-  //   |- bb4 (ehpad), bb5, bb6, bb7
-  //     |- bb6 (ehpad), bb7
-  //
-  // Here, bb6 is a terminate pad with a 'catch' instruction, and bb7 is a
-  // terminate pad with a 'catch_all' instruction, In this case we put bb6 and
-  // bb7 into one exception.
-
-  auto *MBB1 = MF->getBlockNumbered(1);
-  auto *WE0 = WEI.getExceptionFor(MBB1);
-  ASSERT_TRUE(WE0);
-  EXPECT_EQ(WE0->getEHPad(), MBB1);
-  EXPECT_EQ(WE0->getParentException(), nullptr);
-  EXPECT_EQ(WE0->getExceptionDepth(), (unsigned)1);
-
-  auto *MBB2 = MF->getBlockNumbered(2);
-  WE0 = WEI.getExceptionFor(MBB2);
-  ASSERT_TRUE(WE0);
-  EXPECT_EQ(WE0->getEHPad(), MBB1);
-
-  auto *MBB4 = MF->getBlockNumbered(4);
-  auto *WE0_0 = WEI.getExceptionFor(MBB4);
-  ASSERT_TRUE(WE0_0);
-  EXPECT_EQ(WE0_0->getEHPad(), MBB4);
-  EXPECT_EQ(WE0_0->getParentException(), WE0);
-  EXPECT_EQ(WE0_0->getExceptionDepth(), (unsigned)2);
-
-  auto *MBB5 = MF->getBlockNumbered(5);
-  WE0_0 = WEI.getExceptionFor(MBB5);
-  ASSERT_TRUE(WE0_0);
-  EXPECT_EQ(WE0_0->getEHPad(), MBB4);
-
-  auto *MBB6 = MF->getBlockNumbered(6);
-  auto *WE0_0_0 = WEI.getExceptionFor(MBB6);
-  ASSERT_TRUE(WE0_0_0);
-  EXPECT_EQ(WE0_0_0->getEHPad(), MBB6);
-  EXPECT_EQ(WE0_0_0->getParentException(), WE0_0);
-  EXPECT_EQ(WE0_0_0->getExceptionDepth(), (unsigned)3);
-
-  auto *MBB7 = MF->getBlockNumbered(7);
-  WE0_0_0 = WEI.getExceptionFor(MBB7);
-  ASSERT_TRUE(WE0_0_0);
-  EXPECT_EQ(WE0_0_0->getEHPad(), MBB6);
-}




More information about the llvm-commits mailing list