[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/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: