[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

llvm-svn: 352598
diff --git a/llvm/test/CodeGen/WebAssembly/annotations.mir b/llvm/test/CodeGen/WebAssembly/annotations.mir
deleted file mode 100644
index 1ae2db8..0000000
--- a/llvm/test/CodeGen/WebAssembly/annotations.mir
+++ /dev/null
@@ -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
-...
diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
index e3c34f8..0377301 100644
--- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
+++ b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.ll
@@ -7,21 +7,25 @@
 @_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@FUNCTION
-; CHECK: .LBB0_1:
-; CHECK:   i32.catch
+; CHECK:   catch     $[[EXCEPT_REF:[0-9]+]]=
+; CHECK:   block i32
+; CHECK:   br_on_exn 0, __cpp_exception@EVENT, $[[EXCEPT_REF]]
+; CHECK:   rethrow
+; CHECK:   end_block
 ; CHECK:   i32.call  $drop=, _Unwind_CallPersonality@FUNCTION
-; CHECK:   i32.call  $drop=, __cxa_begin_catch@FUNCTION
-; CHECK:   call      bar@FUNCTION
-; CHECK:   call      __cxa_end_catch@FUNCTION
-; CHECK: .LBB0_3:
-; CHECK:   i32.call  $drop=, __cxa_begin_catch@FUNCTION
-; CHECK:   call      __cxa_end_catch@FUNCTION
-; CHECK: .LBB0_5:
-; CHECK:   call      __cxa_rethrow@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 @@
 }
 
 ; 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@FUNCTION
-; CHECK: .LBB1_1:
-; CHECK:   i32.catch     $0=, 0
-; CHECK:   i32.call  $drop=, _Unwind_CallPersonality@FUNCTION, $0
-; CHECK:   i32.call  $drop=, __cxa_begin_catch@FUNCTION, $0
+; CHECK:   catch
+; CHECK:   br_on_exn 0, __cpp_exception@EVENT
+; CHECK:   rethrow
+; CHECK:   i32.call  $drop=, _Unwind_CallPersonality@FUNCTION
+; CHECK:   try
 ; CHECK:   call      foo@FUNCTION
-; CHECK: .LBB1_3:
-; CHECK:   i32.catch     $0=, 0
-; CHECK:   i32.call  $drop=, _Unwind_CallPersonality@FUNCTION, $0
-; CHECK:   i32.call  $drop=, __cxa_begin_catch@FUNCTION, $0
+; CHECK:   catch
+; CHECK:   br_on_exn   0, __cpp_exception@EVENT
+; CHECK:   rethrow
+; CHECK:   i32.call  $drop=, _Unwind_CallPersonality@FUNCTION
+; CHECK:   try
+; CHECK:   i32.call  $drop=, __cxa_begin_catch@FUNCTION
+; CHECK:   try
 ; CHECK:   call      foo@FUNCTION
-; CHECK: .LBB1_5:
-; CHECK:   catch_all
-; CHECK:   call      __cxa_end_catch@FUNCTION
+; CHECK:   catch     $drop=
 ; CHECK:   rethrow
-; CHECK: .LBB1_6:
-; CHECK:   call      __cxa_rethrow@FUNCTION
+; CHECK:   end_try
+; CHECK:   catch     $drop=
 ; CHECK:   rethrow
-; CHECK: .LBB1_7:
-; CHECK:   call      __cxa_end_catch@FUNCTION
-; CHECK: .LBB1_8:
-; CHECK:   catch_all
-; CHECK:   call      __cxa_end_catch@FUNCTION
-; CHECK: .LBB1_9:
-; CHECK:   call      __cxa_rethrow@FUNCTION
-; CHECK:   rethrow
-; CHECK: .LBB1_10:
-; CHECK:   call      __cxa_end_catch@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 @@
 }
 
 ; 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@FUNCTION
-; CHECK: .LBB2_1:
-; CHECK:   i32.catch
-; CHECK:   i32.call  $drop=, __cxa_begin_catch@FUNCTION
-; CHECK: .LBB2_2:
+; CHECK:   catch
+; CHECK:   br_on_exn   0, __cpp_exception@EVENT
+; CHECK:   rethrow
+; CHECK:   loop
+; CHECK:   try
 ; CHECK:   call      foo@FUNCTION
-; CHECK: .LBB2_4:
-; CHECK:   catch_all
+; CHECK:   catch     $drop=
+; CHECK:   try
 ; CHECK:   call      __cxa_end_catch@FUNCTION
-; CHECK: .LBB2_5:
-; CHECK:   i32.catch
+; CHECK:   catch
+; CHECK:   br_on_exn   0, __cpp_exception@EVENT
+; CHECK:   call      __clang_call_terminate@FUNCTION, 0
+; CHECK:   unreachable
 ; CHECK:   call      __clang_call_terminate@FUNCTION
 ; CHECK:   unreachable
-; CHECK: .LBB2_6:
-; CHECK:   catch_all
-; CHECK:   call      _ZSt9terminatev@FUNCTION
-; CHECK:   unreachable
-; CHECK: .LBB2_7:
+; CHECK:   end_try
 ; CHECK:   rethrow
-; CHECK: .LBB2_8:
-; CHECK:   call      __cxa_end_catch@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:
diff --git a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.mir b/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.mir
deleted file mode 100644
index 11d9aaf..0000000
--- a/llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.mir
+++ /dev/null
@@ -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
diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll
index de2d061..46ec468 100644
--- a/llvm/test/CodeGen/WebAssembly/exception.ll
+++ b/llvm/test/CodeGen/WebAssembly/exception.ll
@@ -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 @@
 
 @_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@EVENT, $pop0
+; CHECK: throw __cpp_exception@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@GLOBAL
+; CHECK:   global.get  ${{.+}}=, __stack_pointer@GLOBAL
 ; CHECK:   try
 ; CHECK:   call      foo@FUNCTION
-; CHECK:   i32.catch     $push{{.+}}=, 0
+; CHECK:   catch     $[[EXCEPT_REF:[0-9]+]]=
+; CHECK:   block i32
+; CHECK:   br_on_exn 0, __cpp_exception@EVENT, $[[EXCEPT_REF]]
+; CHECK:   rethrow
+; CHECK:   end_block
+; CHECK:   extract_exception $[[EXN:[0-9]+]]=
 ; CHECK:   global.set  __stack_pointer@GLOBAL
 ; CHECK-DAG:   i32.store  __wasm_lpad_context
 ; CHECK-DAG:   i32.store  __wasm_lpad_context+4
-; CHECK:   i32.call  $push{{.+}}=, _Unwind_CallPersonality@FUNCTION
-; CHECK:   i32.call  $push{{.+}}=, __cxa_begin_catch@FUNCTION
+; CHECK:   i32.call  $drop=, _Unwind_CallPersonality@FUNCTION, $[[EXN]]
+; CHECK:   i32.call  $drop=, __cxa_begin_catch@FUNCTION
 ; CHECK:   call      __cxa_end_catch@FUNCTION
 ; CHECK:   call      __cxa_rethrow@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 @@
 ; CHECK-LABEL: test_cleanup:
 ; CHECK:   try
 ; CHECK:   call      foo@FUNCTION
-; CHECK:   catch_all
+; CHECK:   catch
 ; CHECK:   global.set  __stack_pointer@GLOBAL
-; CHECK:   i32.call  $push{{.+}}=, _ZN7CleanupD1Ev@FUNCTION
+; CHECK:   i32.call  $drop=, _ZN7CleanupD1Ev@FUNCTION
 ; CHECK:   rethrow
 ; CHECK:   end_try
 define void @test_cleanup() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
@@ -87,71 +96,51 @@
   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@FUNCTION
-; CHECK:  unreachable
-; CHECK:  catch_all
-; CHECK:  call      _ZSt9terminatev@FUNCTION
-; CHECK-NOT:  call      __clang_call_terminate@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@EVENT
+; CHECK:   call      __clang_call_terminate@FUNCTION, 0
+; CHECK:   unreachable
+; CHECK:   end_block
+; CHECK:   extract_exception
+; CHECK:   call      __clang_call_terminate@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
-
-invoke.cont3:                                     ; preds = %ehcleanup
-  cleanupret from %0 unwind label %catch.dispatch
-
-catch.dispatch:                                   ; preds = %invoke.cont3, %invoke.cont
-  %1 = catchswitch within none [label %catch.start] unwind label %ehcleanup7
+catch.dispatch:                                   ; preds = %entry
+  %0 = catchswitch within none [label %catch.start] unwind to caller
 
 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
+  %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
 
-invoke.cont5:                                     ; preds = %catch.start
-  catchret from %2 to label %try.cont
+invoke.cont1:                                     ; preds = %catch.start
+  call void @__cxa_end_catch() [ "funclet"(token %1) ]
+  catchret from %1 to label %try.cont
 
-try.cont:                                         ; preds = %invoke.cont5, %invoke.cont
-  %call6 = call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c)
-  ret i32 0
+try.cont:                                         ; preds = %entry, %invoke.cont1
+  ret void
 
-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
+ehcleanup:                                        ; preds = %catch.start
+  %5 = cleanuppad within %1 []
+  invoke void @__cxa_end_catch() [ "funclet"(token %5) ]
+          to label %invoke.cont2 unwind label %terminate
 
-invoke.cont8:                                     ; preds = %ehcleanup7
-  cleanupret from %6 unwind to caller
+invoke.cont2:                                     ; preds = %ehcleanup
+  cleanupret from %5 unwind to caller
 
 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
-
-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) ]
+  %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 @@
 ; CHECK-LABEL: test_no_prolog_epilog_in_ehpad
 ; CHECK:  try
 ; CHECK:  call      foo@FUNCTION
-; CHECK:  i32.catch
+; CHECK:  catch
 ; CHECK-NOT:  global.get  $push{{.+}}=, __stack_pointer@GLOBAL
 ; CHECK:  global.set  __stack_pointer@GLOBAL
 ; CHECK:  try
 ; CHECK:  call      foo@FUNCTION
-; CHECK:  catch_all
+; CHECK:  catch
 ; CHECK-NOT:  global.get  $push{{.+}}=, __stack_pointer@GLOBAL
 ; CHECK:  global.set  __stack_pointer@GLOBAL
 ; CHECK:  call      __cxa_end_catch@FUNCTION
@@ -251,6 +240,8 @@
 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 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:
diff --git a/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll b/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll
index 6df7175..09013a0 100644
--- a/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll
+++ b/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll
@@ -29,7 +29,7 @@
   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 @@
   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 @@
   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 @@
 
 ; 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 @@
   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 @@
 ; 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 @@
   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 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*)