xref: /llvm-project/llvm/test/CodeGen/WebAssembly/exception.ll (revision 539b2e06542f7c099885533e4472e6fb3084aa96)
1a8e1135bSHeejin Ahn; RUN: llc < %s -asm-verbose=false -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck --implicit-check-not=ehgcr -allow-deprecated-dag-overlap %s
2a8e1135bSHeejin Ahn; RUN: llc < %s -asm-verbose=false -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs -O0
3a8e1135bSHeejin Ahn; RUN: llc < %s -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling
4a8e1135bSHeejin Ahn; RUN: llc < %s -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling -filetype=obj
5*539b2e06SHeejin Ahn; RUN: llc < %s -mtriple=wasm64-unknown-unknown -wasm-enable-eh -wasm-use-legacy-eh=false -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck --implicit-check-not=ehgcr -allow-deprecated-dag-overlap %s --check-prefix=WASM64
66bbf7f06SHeejin Ahn
76bbf7f06SHeejin Ahntarget triple = "wasm32-unknown-unknown"
86bbf7f06SHeejin Ahn
96bbf7f06SHeejin Ahn%struct.Temp = type { i8 }
106bbf7f06SHeejin Ahn
116bbf7f06SHeejin Ahn@_ZTIi = external dso_local constant ptr
126bbf7f06SHeejin Ahn
136bbf7f06SHeejin Ahn; CHECK: .tagtype  __cpp_exception i32
146bbf7f06SHeejin Ahn
156bbf7f06SHeejin Ahn; CHECK-LABEL: throw:
166bbf7f06SHeejin Ahn; CHECK:     throw __cpp_exception
176bbf7f06SHeejin Ahn; CHECK-NOT: unreachable
186bbf7f06SHeejin Ahndefine void @throw(ptr %p) {
196bbf7f06SHeejin Ahn  call void @llvm.wasm.throw(i32 0, ptr %p)
206bbf7f06SHeejin Ahn  ret void
216bbf7f06SHeejin Ahn}
226bbf7f06SHeejin Ahn
236bbf7f06SHeejin Ahn; Simple test with a try-catch
246bbf7f06SHeejin Ahn;
256bbf7f06SHeejin Ahn; void foo();
266bbf7f06SHeejin Ahn; void catch() {
276bbf7f06SHeejin Ahn;   try {
286bbf7f06SHeejin Ahn;     foo();
296bbf7f06SHeejin Ahn;   } catch (int) {
306bbf7f06SHeejin Ahn;   }
316bbf7f06SHeejin Ahn; }
326bbf7f06SHeejin Ahn
336bbf7f06SHeejin Ahn; CHECK-LABEL: catch:
34*539b2e06SHeejin Ahn; WASM64-LABEL: catch:
356bbf7f06SHeejin Ahn; CHECK: global.get  __stack_pointer
366bbf7f06SHeejin Ahn; CHECK: local.set  0
376bbf7f06SHeejin Ahn; CHECK: block
386bbf7f06SHeejin Ahn; CHECK:   block     () -> (i32, exnref)
396bbf7f06SHeejin Ahn; CHECK:     try_table    (catch_ref __cpp_exception 0)
40*539b2e06SHeejin Ahn; WASM64:  block     () -> (i64, exnref)
416bbf7f06SHeejin Ahn; CHECK:       call  foo
426bbf7f06SHeejin Ahn; CHECK:       br        2
436bbf7f06SHeejin Ahn; CHECK:     end_try_table
44c3dfd34eSHeejin Ahn; CHECK:     unreachable
456bbf7f06SHeejin Ahn; CHECK:   end_block
466bbf7f06SHeejin Ahn; CHECK:   local.set  2
476bbf7f06SHeejin Ahn; CHECK:   local.get  0
486bbf7f06SHeejin Ahn; CHECK:   global.set  __stack_pointer
496bbf7f06SHeejin Ahn; CHECK:   i32.store  __wasm_lpad_context
506bbf7f06SHeejin Ahn; CHECK:   call  _Unwind_CallPersonality
516bbf7f06SHeejin Ahn; CHECK:   block
526bbf7f06SHeejin Ahn; CHECK:     br_if     0
536bbf7f06SHeejin Ahn; CHECK:     call  __cxa_begin_catch
546bbf7f06SHeejin Ahn; CHECK:     call  __cxa_end_catch
556bbf7f06SHeejin Ahn; CHECK:     br        1
566bbf7f06SHeejin Ahn; CHECK:   end_block
576bbf7f06SHeejin Ahn; CHECK:   local.get  2
586bbf7f06SHeejin Ahn; CHECK:   throw_ref
596bbf7f06SHeejin Ahn; CHECK: end_block
606bbf7f06SHeejin Ahndefine void @catch() personality ptr @__gxx_wasm_personality_v0 {
616bbf7f06SHeejin Ahnentry:
626bbf7f06SHeejin Ahn  invoke void @foo()
636bbf7f06SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
646bbf7f06SHeejin Ahn
656bbf7f06SHeejin Ahncatch.dispatch:                                   ; preds = %entry
666bbf7f06SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind to caller
676bbf7f06SHeejin Ahn
686bbf7f06SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
696bbf7f06SHeejin Ahn  %1 = catchpad within %0 [ptr @_ZTIi]
706bbf7f06SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
716bbf7f06SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
726bbf7f06SHeejin Ahn  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)
736bbf7f06SHeejin Ahn  %matches = icmp eq i32 %3, %4
746bbf7f06SHeejin Ahn  br i1 %matches, label %catch, label %rethrow
756bbf7f06SHeejin Ahn
766bbf7f06SHeejin Ahncatch:                                            ; preds = %catch.start
776bbf7f06SHeejin Ahn  %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
786bbf7f06SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %1) ]
796bbf7f06SHeejin Ahn  catchret from %1 to label %try.cont
806bbf7f06SHeejin Ahn
816bbf7f06SHeejin Ahnrethrow:                                          ; preds = %catch.start
826bbf7f06SHeejin Ahn  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
836bbf7f06SHeejin Ahn  unreachable
846bbf7f06SHeejin Ahn
856bbf7f06SHeejin Ahntry.cont:                                         ; preds = %catch, %entry
866bbf7f06SHeejin Ahn  ret void
876bbf7f06SHeejin Ahn}
886bbf7f06SHeejin Ahn
896bbf7f06SHeejin Ahn; Destructor (cleanup) test
906bbf7f06SHeejin Ahn;
916bbf7f06SHeejin Ahn; void foo();
926bbf7f06SHeejin Ahn; struct Temp {
936bbf7f06SHeejin Ahn;   ~Temp() {}
946bbf7f06SHeejin Ahn; };
956bbf7f06SHeejin Ahn; void cleanup() {
966bbf7f06SHeejin Ahn;   Temp t;
976bbf7f06SHeejin Ahn;   foo();
986bbf7f06SHeejin Ahn; }
996bbf7f06SHeejin Ahn
1006bbf7f06SHeejin Ahn; CHECK-LABEL: cleanup:
1016bbf7f06SHeejin Ahn; CHECK: block
1026bbf7f06SHeejin Ahn; CHECK:   block     exnref
1036bbf7f06SHeejin Ahn; CHECK:     try_table    (catch_all_ref 0)
1046bbf7f06SHeejin Ahn; CHECK:       call  foo
1056bbf7f06SHeejin Ahn; CHECK:       br        2
1066bbf7f06SHeejin Ahn; CHECK:     end_try_table
1076bbf7f06SHeejin Ahn; CHECK:   end_block
1086bbf7f06SHeejin Ahn; CHECK:   local.set  1
1096bbf7f06SHeejin Ahn; CHECK:   global.set  __stack_pointer
1106bbf7f06SHeejin Ahn; CHECK:   call  _ZN4TempD2Ev
1116bbf7f06SHeejin Ahn; CHECK:   local.get  1
1126bbf7f06SHeejin Ahn; CHECK:   throw_ref
1136bbf7f06SHeejin Ahn; CHECK: end_block
1146bbf7f06SHeejin Ahn; CHECK: call  _ZN4TempD2Ev
1156bbf7f06SHeejin Ahndefine void @cleanup() personality ptr @__gxx_wasm_personality_v0 {
1166bbf7f06SHeejin Ahnentry:
1176bbf7f06SHeejin Ahn  %t = alloca %struct.Temp, align 1
1186bbf7f06SHeejin Ahn  invoke void @foo()
1196bbf7f06SHeejin Ahn          to label %invoke.cont unwind label %ehcleanup
1206bbf7f06SHeejin Ahn
1216bbf7f06SHeejin Ahninvoke.cont:                                      ; preds = %entry
1226bbf7f06SHeejin Ahn  %call = call ptr @_ZN4TempD2Ev(ptr %t)
1236bbf7f06SHeejin Ahn  ret void
1246bbf7f06SHeejin Ahn
1256bbf7f06SHeejin Ahnehcleanup:                                        ; preds = %entry
1266bbf7f06SHeejin Ahn  %0 = cleanuppad within none []
1276bbf7f06SHeejin Ahn  %call1 = call ptr @_ZN4TempD2Ev(ptr %t) [ "funclet"(token %0) ]
1286bbf7f06SHeejin Ahn  cleanupret from %0 unwind to caller
1296bbf7f06SHeejin Ahn}
1306bbf7f06SHeejin Ahn
1316bbf7f06SHeejin Ahn; Calling a function that may throw within a 'catch (...)' generates a
1326bbf7f06SHeejin Ahn; terminatepad, because __cxa_end_catch() also can throw within 'catch (...)'.
1336bbf7f06SHeejin Ahn;
1346bbf7f06SHeejin Ahn; void foo();
1356bbf7f06SHeejin Ahn; void terminatepad() {
1366bbf7f06SHeejin Ahn;   try {
1376bbf7f06SHeejin Ahn;     foo();
1386bbf7f06SHeejin Ahn;   } catch (...) {
1396bbf7f06SHeejin Ahn;     foo();
1406bbf7f06SHeejin Ahn;   }
1416bbf7f06SHeejin Ahn; }
1426bbf7f06SHeejin Ahn
1436bbf7f06SHeejin Ahn; CHECK-LABEL: terminatepad
144*539b2e06SHeejin Ahn; WASM64-LABEL: terminatepad
1456bbf7f06SHeejin Ahn; CHECK: block
1466bbf7f06SHeejin Ahn; CHECK:   block     i32
147*539b2e06SHeejin Ahn; WASM64:  block     i64
1486bbf7f06SHeejin Ahn; CHECK:     try_table    (catch __cpp_exception 0)
1496bbf7f06SHeejin Ahn; CHECK:       call  foo
1506bbf7f06SHeejin Ahn; CHECK:       br        2
1516bbf7f06SHeejin Ahn; CHECK:     end_try_table
1526bbf7f06SHeejin Ahn; CHECK:   end_block
1536bbf7f06SHeejin Ahn; CHECK:   call  __cxa_begin_catch
1546bbf7f06SHeejin Ahn; CHECK:   block
1556bbf7f06SHeejin Ahn; CHECK:     block     exnref
1566bbf7f06SHeejin Ahn; CHECK:       try_table    (catch_all_ref 0)
1576bbf7f06SHeejin Ahn; CHECK:         call  foo
1586bbf7f06SHeejin Ahn; CHECK:         br        2
1596bbf7f06SHeejin Ahn; CHECK:       end_try_table
1606bbf7f06SHeejin Ahn; CHECK:     end_block
1616bbf7f06SHeejin Ahn; CHECK:     local.set  2
1626bbf7f06SHeejin Ahn; CHECK:     block
1636bbf7f06SHeejin Ahn; CHECK:       block
1646bbf7f06SHeejin Ahn; CHECK:         try_table    (catch_all 0)
1656bbf7f06SHeejin Ahn; CHECK:           call  __cxa_end_catch
1666bbf7f06SHeejin Ahn; CHECK:           br        2
1676bbf7f06SHeejin Ahn; CHECK:         end_try_table
1686bbf7f06SHeejin Ahn; CHECK:       end_block
1696bbf7f06SHeejin Ahn; CHECK:       call  _ZSt9terminatev
1706bbf7f06SHeejin Ahn; CHECK:       unreachable
1716bbf7f06SHeejin Ahn; CHECK:     end_block
1726bbf7f06SHeejin Ahn; CHECK:     local.get  2
1736bbf7f06SHeejin Ahn; CHECK:     throw_ref
1746bbf7f06SHeejin Ahn; CHECK:   end_block
1756bbf7f06SHeejin Ahn; CHECK:   call  __cxa_end_catch
1766bbf7f06SHeejin Ahn; CHECK: end_block
1776bbf7f06SHeejin Ahndefine void @terminatepad() personality ptr @__gxx_wasm_personality_v0 {
1786bbf7f06SHeejin Ahnentry:
1796bbf7f06SHeejin Ahn  invoke void @foo()
1806bbf7f06SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
1816bbf7f06SHeejin Ahn
1826bbf7f06SHeejin Ahncatch.dispatch:                                   ; preds = %entry
1836bbf7f06SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind to caller
1846bbf7f06SHeejin Ahn
1856bbf7f06SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
1866bbf7f06SHeejin Ahn  %1 = catchpad within %0 [ptr null]
1876bbf7f06SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
1886bbf7f06SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
1896bbf7f06SHeejin Ahn  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
1906bbf7f06SHeejin Ahn  invoke void @foo() [ "funclet"(token %1) ]
1916bbf7f06SHeejin Ahn          to label %invoke.cont1 unwind label %ehcleanup
1926bbf7f06SHeejin Ahn
1936bbf7f06SHeejin Ahninvoke.cont1:                                     ; preds = %catch.start
1946bbf7f06SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %1) ]
1956bbf7f06SHeejin Ahn  catchret from %1 to label %try.cont
1966bbf7f06SHeejin Ahn
1976bbf7f06SHeejin Ahntry.cont:                                         ; preds = %invoke.cont1, %entry
1986bbf7f06SHeejin Ahn  ret void
1996bbf7f06SHeejin Ahn
2006bbf7f06SHeejin Ahnehcleanup:                                        ; preds = %catch.start
2016bbf7f06SHeejin Ahn  %5 = cleanuppad within %1 []
2026bbf7f06SHeejin Ahn  invoke void @__cxa_end_catch() [ "funclet"(token %5) ]
2036bbf7f06SHeejin Ahn          to label %invoke.cont2 unwind label %terminate
2046bbf7f06SHeejin Ahn
2056bbf7f06SHeejin Ahninvoke.cont2:                                     ; preds = %ehcleanup
2066bbf7f06SHeejin Ahn  cleanupret from %5 unwind to caller
2076bbf7f06SHeejin Ahn
2086bbf7f06SHeejin Ahnterminate:                                        ; preds = %ehcleanup
2096bbf7f06SHeejin Ahn  %6 = cleanuppad within %5 []
2106bbf7f06SHeejin Ahn  call void @_ZSt9terminatev() [ "funclet"(token %6) ]
2116bbf7f06SHeejin Ahn  unreachable
2126bbf7f06SHeejin Ahn}
2136bbf7f06SHeejin Ahn
2146bbf7f06SHeejin Ahn; Tests prologues and epilogues are not generated within EH scopes.
2156bbf7f06SHeejin Ahn; They should not be treated as funclets; BBs starting with a catch instruction
2166bbf7f06SHeejin Ahn; should not have a prologue, and BBs ending with a catchret/cleanupret should
2176bbf7f06SHeejin Ahn; not have an epilogue. This is separate from __stack_pointer restoring
2186bbf7f06SHeejin Ahn; instructions after a catch instruction.
2196bbf7f06SHeejin Ahn;
2206bbf7f06SHeejin Ahn; void bar(int) noexcept;
2216bbf7f06SHeejin Ahn; void no_prolog_epilog_in_ehpad() {
2226bbf7f06SHeejin Ahn;   int stack_var = 0;
2236bbf7f06SHeejin Ahn;   bar(stack_var);
2246bbf7f06SHeejin Ahn;   try {
2256bbf7f06SHeejin Ahn;     foo();
2266bbf7f06SHeejin Ahn;   } catch (int) {
2276bbf7f06SHeejin Ahn;     foo();
2286bbf7f06SHeejin Ahn;   }
2296bbf7f06SHeejin Ahn; }
2306bbf7f06SHeejin Ahn
2316bbf7f06SHeejin Ahn; CHECK-LABEL: no_prolog_epilog_in_ehpad
2326bbf7f06SHeejin Ahn; CHECK:   call  bar
2336bbf7f06SHeejin Ahn; CHECK:   block
2346bbf7f06SHeejin Ahn; CHECK:     block     () -> (i32, exnref)
2356bbf7f06SHeejin Ahn; CHECK:       try_table    (catch_ref __cpp_exception 0)
2366bbf7f06SHeejin Ahn; CHECK:         call  foo
2376bbf7f06SHeejin Ahn; CHECK:         br        2
2386bbf7f06SHeejin Ahn; CHECK:       end_try_table
2396bbf7f06SHeejin Ahn; CHECK:     end_block
2406bbf7f06SHeejin Ahn; CHECK:     local.set  2
2416bbf7f06SHeejin Ahn; CHECK-NOT: global.get  __stack_pointer
2426bbf7f06SHeejin Ahn; CHECK:     global.set  __stack_pointer
2436bbf7f06SHeejin Ahn; CHECK:     block
2446bbf7f06SHeejin Ahn; CHECK:       block
2456bbf7f06SHeejin Ahn; CHECK:         br_if     0
2466bbf7f06SHeejin Ahn; CHECK:         call  __cxa_begin_catch
2476bbf7f06SHeejin Ahn; CHECK:         block     exnref
2486bbf7f06SHeejin Ahn; CHECK:           try_table    (catch_all_ref 0)
2496bbf7f06SHeejin Ahn; CHECK:             call  foo
2506bbf7f06SHeejin Ahn; CHECK:             br        3
2516bbf7f06SHeejin Ahn; CHECK:           end_try_table
2526bbf7f06SHeejin Ahn; CHECK:         end_block
2536bbf7f06SHeejin Ahn; CHECK:         local.set  2
2546bbf7f06SHeejin Ahn; CHECK-NOT:     global.get  __stack_pointer
2556bbf7f06SHeejin Ahn; CHECK:         global.set  __stack_pointer
2566bbf7f06SHeejin Ahn; CHECK:         call  __cxa_end_catch
2576bbf7f06SHeejin Ahn; CHECK:         local.get  2
2586bbf7f06SHeejin Ahn; CHECK:         throw_ref
2596bbf7f06SHeejin Ahn; CHECK-NOT:     global.set  __stack_pointer
2606bbf7f06SHeejin Ahn; CHECK:       end_block
2616bbf7f06SHeejin Ahn; CHECK:       local.get  2
2626bbf7f06SHeejin Ahn; CHECK:       throw_ref
2636bbf7f06SHeejin Ahn; CHECK:     end_block
2646bbf7f06SHeejin Ahn; CHECK-NOT: global.set  __stack_pointer
2656bbf7f06SHeejin Ahn; CHECK:     call  __cxa_end_catch
2666bbf7f06SHeejin Ahn; CHECK:   end_block
2676bbf7f06SHeejin Ahndefine void @no_prolog_epilog_in_ehpad() personality ptr @__gxx_wasm_personality_v0 {
2686bbf7f06SHeejin Ahnentry:
2696bbf7f06SHeejin Ahn  %stack_var = alloca i32, align 4
2706bbf7f06SHeejin Ahn  call void @bar(ptr %stack_var)
2716bbf7f06SHeejin Ahn  invoke void @foo()
2726bbf7f06SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
2736bbf7f06SHeejin Ahn
2746bbf7f06SHeejin Ahncatch.dispatch:                                   ; preds = %entry
2756bbf7f06SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind to caller
2766bbf7f06SHeejin Ahn
2776bbf7f06SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
2786bbf7f06SHeejin Ahn  %1 = catchpad within %0 [ptr @_ZTIi]
2796bbf7f06SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
2806bbf7f06SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
2816bbf7f06SHeejin Ahn  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)
2826bbf7f06SHeejin Ahn  %matches = icmp eq i32 %3, %4
2836bbf7f06SHeejin Ahn  br i1 %matches, label %catch, label %rethrow
2846bbf7f06SHeejin Ahn
2856bbf7f06SHeejin Ahncatch:                                            ; preds = %catch.start
2866bbf7f06SHeejin Ahn  %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
2876bbf7f06SHeejin Ahn  %6 = load float, ptr %5, align 4
2886bbf7f06SHeejin Ahn  invoke void @foo() [ "funclet"(token %1) ]
2896bbf7f06SHeejin Ahn          to label %invoke.cont1 unwind label %ehcleanup
2906bbf7f06SHeejin Ahn
2916bbf7f06SHeejin Ahninvoke.cont1:                                     ; preds = %catch
2926bbf7f06SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %1) ]
2936bbf7f06SHeejin Ahn  catchret from %1 to label %try.cont
2946bbf7f06SHeejin Ahn
2956bbf7f06SHeejin Ahnrethrow:                                          ; preds = %catch.start
2966bbf7f06SHeejin Ahn  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
2976bbf7f06SHeejin Ahn  unreachable
2986bbf7f06SHeejin Ahn
2996bbf7f06SHeejin Ahntry.cont:                                         ; preds = %invoke.cont1, %entry
3006bbf7f06SHeejin Ahn  ret void
3016bbf7f06SHeejin Ahn
3026bbf7f06SHeejin Ahnehcleanup:                                        ; preds = %catch
3036bbf7f06SHeejin Ahn  %7 = cleanuppad within %1 []
3046bbf7f06SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %7) ]
3056bbf7f06SHeejin Ahn  cleanupret from %7 unwind to caller
3066bbf7f06SHeejin Ahn}
3076bbf7f06SHeejin Ahn
3086bbf7f06SHeejin Ahn; When a function does not have stack-allocated objects, it does not need to
3096bbf7f06SHeejin Ahn; store SP back to __stack_pointer global at the epilog.
3106bbf7f06SHeejin Ahn;
3116bbf7f06SHeejin Ahn; void foo();
3126bbf7f06SHeejin Ahn; void no_sp_writeback() {
3136bbf7f06SHeejin Ahn;   try {
3146bbf7f06SHeejin Ahn;     foo();
3156bbf7f06SHeejin Ahn;   } catch (...) {
3166bbf7f06SHeejin Ahn;   }
3176bbf7f06SHeejin Ahn; }
3186bbf7f06SHeejin Ahn
3196bbf7f06SHeejin Ahn; CHECK-LABEL: no_sp_writeback
3206bbf7f06SHeejin Ahn; CHECK:     block
3216bbf7f06SHeejin Ahn; CHECK:       block     i32
3226bbf7f06SHeejin Ahn; CHECK:         try_table    (catch __cpp_exception 0)
3236bbf7f06SHeejin Ahn; CHECK:           call  foo
3246bbf7f06SHeejin Ahn; CHECK:           br        2
3256bbf7f06SHeejin Ahn; CHECK:         end_try_table
3266bbf7f06SHeejin Ahn; CHECK:       end_block
3276bbf7f06SHeejin Ahn; CHECK:       call  __cxa_begin_catch
3286bbf7f06SHeejin Ahn; CHECK:       call  __cxa_end_catch
3296bbf7f06SHeejin Ahn; CHECK:     end_block
3306bbf7f06SHeejin Ahn; CHECK-NOT: global.set  __stack_pointer
3316bbf7f06SHeejin Ahn; CHECK:     end_function
3326bbf7f06SHeejin Ahndefine void @no_sp_writeback() personality ptr @__gxx_wasm_personality_v0 {
3336bbf7f06SHeejin Ahnentry:
3346bbf7f06SHeejin Ahn  invoke void @foo()
3356bbf7f06SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
3366bbf7f06SHeejin Ahn
3376bbf7f06SHeejin Ahncatch.dispatch:                                   ; preds = %entry
3386bbf7f06SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind to caller
3396bbf7f06SHeejin Ahn
3406bbf7f06SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
3416bbf7f06SHeejin Ahn  %1 = catchpad within %0 [ptr null]
3426bbf7f06SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
3436bbf7f06SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
3446bbf7f06SHeejin Ahn  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
3456bbf7f06SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %1) ]
3466bbf7f06SHeejin Ahn  catchret from %1 to label %try.cont
3476bbf7f06SHeejin Ahn
3486bbf7f06SHeejin Ahntry.cont:                                         ; preds = %catch.start, %entry
3496bbf7f06SHeejin Ahn  ret void
3506bbf7f06SHeejin Ahn}
3516bbf7f06SHeejin Ahn
3526bbf7f06SHeejin Ahn; When the result of @llvm.wasm.get.exception is not used. This is created to
3536bbf7f06SHeejin Ahn; fix a bug in LateEHPrepare and this should not crash.
3546bbf7f06SHeejin Ahndefine void @get_exception_wo_use() personality ptr @__gxx_wasm_personality_v0 {
3556bbf7f06SHeejin Ahnentry:
3566bbf7f06SHeejin Ahn  invoke void @foo()
3576bbf7f06SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
3586bbf7f06SHeejin Ahn
3596bbf7f06SHeejin Ahncatch.dispatch:                                   ; preds = %entry
3606bbf7f06SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind to caller
3616bbf7f06SHeejin Ahn
3626bbf7f06SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
3636bbf7f06SHeejin Ahn  %1 = catchpad within %0 [ptr null]
3646bbf7f06SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
3656bbf7f06SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
3666bbf7f06SHeejin Ahn  catchret from %1 to label %try.cont
3676bbf7f06SHeejin Ahn
3686bbf7f06SHeejin Ahntry.cont:                                         ; preds = %catch.start, %entry
3696bbf7f06SHeejin Ahn  ret void
3706bbf7f06SHeejin Ahn}
3716bbf7f06SHeejin Ahn
3726bbf7f06SHeejin Ahn; Tests a case when a cleanup region (cleanuppad ~ clanupret) contains another
3736bbf7f06SHeejin Ahn; catchpad
3746bbf7f06SHeejin Ahndefine void @complex_cleanup_region() personality ptr @__gxx_wasm_personality_v0 {
3756bbf7f06SHeejin Ahnentry:
3766bbf7f06SHeejin Ahn  invoke void @foo()
3776bbf7f06SHeejin Ahn          to label %invoke.cont unwind label %ehcleanup
3786bbf7f06SHeejin Ahn
3796bbf7f06SHeejin Ahninvoke.cont:                                      ; preds = %entry
3806bbf7f06SHeejin Ahn  ret void
3816bbf7f06SHeejin Ahn
3826bbf7f06SHeejin Ahnehcleanup:                                        ; preds = %entry
3836bbf7f06SHeejin Ahn  %0 = cleanuppad within none []
3846bbf7f06SHeejin Ahn  invoke void @foo() [ "funclet"(token %0) ]
3856bbf7f06SHeejin Ahn          to label %ehcleanupret unwind label %catch.dispatch
3866bbf7f06SHeejin Ahn
3876bbf7f06SHeejin Ahncatch.dispatch:                                   ; preds = %ehcleanup
3886bbf7f06SHeejin Ahn  %1 = catchswitch within %0 [label %catch.start] unwind label %ehcleanup.1
3896bbf7f06SHeejin Ahn
3906bbf7f06SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
3916bbf7f06SHeejin Ahn  %2 = catchpad within %1 [ptr null]
3926bbf7f06SHeejin Ahn  %3 = call ptr @llvm.wasm.get.exception(token %2)
3936bbf7f06SHeejin Ahn  %4 = call i32 @llvm.wasm.get.ehselector(token %2)
3946bbf7f06SHeejin Ahn  catchret from %2 to label %ehcleanupret
3956bbf7f06SHeejin Ahn
3966bbf7f06SHeejin Ahnehcleanup.1:                                      ; preds = %catch.dispatch
3976bbf7f06SHeejin Ahn  %5 = cleanuppad within %0 []
3986bbf7f06SHeejin Ahn  unreachable
3996bbf7f06SHeejin Ahn
4006bbf7f06SHeejin Ahnehcleanupret:                                     ; preds = %catch.start, %ehcleanup
4016bbf7f06SHeejin Ahn  cleanupret from %0 unwind to caller
4026bbf7f06SHeejin Ahn}
4036bbf7f06SHeejin Ahn
4046bbf7f06SHeejin Ahn; Regression test for the bug that 'rethrow' was not treated correctly as a
4056bbf7f06SHeejin Ahn; terminator in isel.
4066bbf7f06SHeejin Ahndefine void @rethrow_terminator() personality ptr @__gxx_wasm_personality_v0 {
4076bbf7f06SHeejin Ahnentry:
4086bbf7f06SHeejin Ahn  invoke void @foo()
4096bbf7f06SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
4106bbf7f06SHeejin Ahn
4116bbf7f06SHeejin Ahncatch.dispatch:                                   ; preds = %entry
4126bbf7f06SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind label %ehcleanup
4136bbf7f06SHeejin Ahn
4146bbf7f06SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
4156bbf7f06SHeejin Ahn  %1 = catchpad within %0 [ptr @_ZTIi]
4166bbf7f06SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
4176bbf7f06SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
4186bbf7f06SHeejin Ahn  %4 = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi)
4196bbf7f06SHeejin Ahn  %matches = icmp eq i32 %3, %4
4206bbf7f06SHeejin Ahn  br i1 %matches, label %catch, label %rethrow
4216bbf7f06SHeejin Ahn
4226bbf7f06SHeejin Ahncatch:                                            ; preds = %catch.start
4236bbf7f06SHeejin Ahn  %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
4246bbf7f06SHeejin Ahn  %6 = load i32, ptr %5, align 4
4256bbf7f06SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %1) ]
4266bbf7f06SHeejin Ahn  catchret from %1 to label %try.cont
4276bbf7f06SHeejin Ahn
4286bbf7f06SHeejin Ahnrethrow:                                          ; preds = %catch.start
4296bbf7f06SHeejin Ahn  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]
4306bbf7f06SHeejin Ahn          to label %unreachable unwind label %ehcleanup
4316bbf7f06SHeejin Ahn
4326bbf7f06SHeejin Ahntry.cont:                                         ; preds = %entry, %catch
4336bbf7f06SHeejin Ahn  ret void
4346bbf7f06SHeejin Ahn
4356bbf7f06SHeejin Ahnehcleanup:                                        ; preds = %rethrow, %catch.dispatch
4366bbf7f06SHeejin Ahn  ; 'rethrow' BB is this BB's predecessor, and its
4376bbf7f06SHeejin Ahn  ; 'invoke void @llvm.wasm.rethrow()' is lowered down to a 'RETHROW' in Wasm
4386bbf7f06SHeejin Ahn  ; MIR. And this 'phi' creates 'CONST_I32' instruction in the predecessor
4396bbf7f06SHeejin Ahn  ; 'rethrow' BB. If 'RETHROW' is not treated correctly as a terminator, it can
4406bbf7f06SHeejin Ahn  ; create a BB like
4416bbf7f06SHeejin Ahn  ; bb.3.rethrow:
4426bbf7f06SHeejin Ahn  ;   RETHROW 0
4436bbf7f06SHeejin Ahn  ;   %0 = CONST_I32 20
4446bbf7f06SHeejin Ahn  ;   BR ...
4456bbf7f06SHeejin Ahn  %tmp = phi i32 [ 10, %catch.dispatch ], [ 20, %rethrow ]
4466bbf7f06SHeejin Ahn  %7 = cleanuppad within none []
4476bbf7f06SHeejin Ahn  call void @take_i32(i32 %tmp) [ "funclet"(token %7) ]
4486bbf7f06SHeejin Ahn  cleanupret from %7 unwind to caller
4496bbf7f06SHeejin Ahn
4506bbf7f06SHeejin Ahnunreachable:                                      ; preds = %rethrow
4516bbf7f06SHeejin Ahn  unreachable
4526bbf7f06SHeejin Ahn}
4536bbf7f06SHeejin Ahn
454492812f6SHeejin Ahn; The bitcode below is generated when the code below is compiled and
455492812f6SHeejin Ahn; Temp::~Temp() is inlined into inlined_cleanupret():
456492812f6SHeejin Ahn;
457492812f6SHeejin Ahn; void inlined_cleanupret() {
458492812f6SHeejin Ahn; try {
459492812f6SHeejin Ahn;   Temp t;
460492812f6SHeejin Ahn;   throw 2;
461492812f6SHeejin Ahn; } catch (...)
462492812f6SHeejin Ahn; }
463492812f6SHeejin Ahn;
464492812f6SHeejin Ahn; Temp::~Temp() {
465492812f6SHeejin Ahn;   try {
466492812f6SHeejin Ahn;     throw 1;
467492812f6SHeejin Ahn;   } catch (...) {
468492812f6SHeejin Ahn;   }
469492812f6SHeejin Ahn; }
470492812f6SHeejin Ahn;
471492812f6SHeejin Ahn; ~Temp() generates cleanupret, which is lowered to a 'throw_ref' later. That
472492812f6SHeejin Ahn; throw_ref's argument should correctly target the top-level cleanuppad
473492812f6SHeejin Ahn; (catch_all_ref). This is a regression test for the bug where we did not
474492812f6SHeejin Ahn; compute throw_ref's argument correctly.
475492812f6SHeejin Ahn
476492812f6SHeejin Ahn; CHECK-LABEL: inlined_cleanupret:
477492812f6SHeejin Ahn; CHECK: block     exnref
478492812f6SHeejin Ahn; CHECK:   block
479492812f6SHeejin Ahn; CHECK:     block     exnref
480492812f6SHeejin Ahn; CHECK:       try_table    (catch_all_ref 0)
481492812f6SHeejin Ahn; CHECK:         call  __cxa_throw
482492812f6SHeejin Ahn; CHECK:       end_try_table
483492812f6SHeejin Ahn; CHECK:     end_block
484492812f6SHeejin Ahn; try_table (catch_all_ref 0)'s caught exception is stored in local 2
485492812f6SHeejin Ahn; CHECK:     local.set  2
486492812f6SHeejin Ahn; CHECK:     block
487492812f6SHeejin Ahn; CHECK:       try_table    (catch_all 0)
488492812f6SHeejin Ahn; CHECK:         block
489492812f6SHeejin Ahn; CHECK:           block     i32
490492812f6SHeejin Ahn; CHECK:             try_table    (catch __cpp_exception 0)
491492812f6SHeejin Ahn; CHECK:               call  __cxa_throw
492492812f6SHeejin Ahn; CHECK:             end_try_table
493492812f6SHeejin Ahn; CHECK:           end_block
494492812f6SHeejin Ahn; CHECK:           call  __cxa_end_catch
495492812f6SHeejin Ahn; CHECK:           block     i32
496492812f6SHeejin Ahn; CHECK:             try_table    (catch_all_ref 5)
497492812f6SHeejin Ahn; CHECK:               try_table    (catch __cpp_exception 1)
498492812f6SHeejin Ahn; Note that the throw_ref below targets the top-level catch_all_ref (local 2)
499492812f6SHeejin Ahn; CHECK:                 local.get  2
500492812f6SHeejin Ahn; CHECK:                 throw_ref
501492812f6SHeejin Ahn; CHECK:               end_try_table
502492812f6SHeejin Ahn; CHECK:             end_try_table
503492812f6SHeejin Ahn; CHECK:           end_block
504492812f6SHeejin Ahn; CHECK:           try_table    (catch_all_ref 4)
505492812f6SHeejin Ahn; CHECK:             call  __cxa_end_catch
506492812f6SHeejin Ahn; CHECK:           end_try_table
507492812f6SHeejin Ahn; CHECK:           return
508492812f6SHeejin Ahn; CHECK:         end_block
509492812f6SHeejin Ahn; CHECK:       end_try_table
510492812f6SHeejin Ahn; CHECK:     end_block
511492812f6SHeejin Ahn; CHECK:     call  _ZSt9terminatev
512492812f6SHeejin Ahn; CHECK:   end_block
513492812f6SHeejin Ahn; CHECK: end_block
514492812f6SHeejin Ahn; CHECK: throw_ref
515492812f6SHeejin Ahndefine void @inlined_cleanupret() personality ptr @__gxx_wasm_personality_v0 {
516492812f6SHeejin Ahnentry:
517492812f6SHeejin Ahn  %exception = tail call ptr @__cxa_allocate_exception(i32 4)
518492812f6SHeejin Ahn  store i32 2, ptr %exception, align 16
519492812f6SHeejin Ahn  invoke void @__cxa_throw(ptr nonnull %exception, ptr nonnull @_ZTIi, ptr null)
520492812f6SHeejin Ahn          to label %unreachable unwind label %ehcleanup
521492812f6SHeejin Ahn
522492812f6SHeejin Ahnehcleanup:                                        ; preds = %entry
523492812f6SHeejin Ahn  %0 = cleanuppad within none []
524492812f6SHeejin Ahn  %exception.i = call ptr @__cxa_allocate_exception(i32 4) [ "funclet"(token %0) ]
525492812f6SHeejin Ahn  store i32 1, ptr %exception.i, align 16
526492812f6SHeejin Ahn  invoke void @__cxa_throw(ptr nonnull %exception.i, ptr nonnull @_ZTIi, ptr null) [ "funclet"(token %0) ]
527492812f6SHeejin Ahn          to label %unreachable unwind label %catch.dispatch.i
528492812f6SHeejin Ahn
529492812f6SHeejin Ahncatch.dispatch.i:                                 ; preds = %ehcleanup
530492812f6SHeejin Ahn  %1 = catchswitch within %0 [label %catch.start.i] unwind label %terminate.i
531492812f6SHeejin Ahn
532492812f6SHeejin Ahncatch.start.i:                                    ; preds = %catch.dispatch.i
533492812f6SHeejin Ahn  %2 = catchpad within %1 [ptr null]
534492812f6SHeejin Ahn  %3 = tail call ptr @llvm.wasm.get.exception(token %2)
535492812f6SHeejin Ahn  %4 = tail call i32 @llvm.wasm.get.ehselector(token %2)
536492812f6SHeejin Ahn  %5 = call ptr @__cxa_begin_catch(ptr %3) [ "funclet"(token %2) ]
537492812f6SHeejin Ahn  invoke void @__cxa_end_catch() [ "funclet"(token %2) ]
538492812f6SHeejin Ahn          to label %invoke.cont.i unwind label %terminate.i
539492812f6SHeejin Ahn
540492812f6SHeejin Ahninvoke.cont.i:                                    ; preds = %catch.start.i
541492812f6SHeejin Ahn  catchret from %2 to label %_ZN4TempD2Ev.exit
542492812f6SHeejin Ahn
543492812f6SHeejin Ahnterminate.i:                                      ; preds = %catch.start.i, %catch.dispatch.i
544492812f6SHeejin Ahn  %6 = cleanuppad within %0 []
545492812f6SHeejin Ahn  call void @_ZSt9terminatev() [ "funclet"(token %6) ]
546492812f6SHeejin Ahn  unreachable
547492812f6SHeejin Ahn
548492812f6SHeejin Ahn_ZN4TempD2Ev.exit:                                ; preds = %invoke.cont.i
549492812f6SHeejin Ahn  cleanupret from %0 unwind label %catch.dispatch
550492812f6SHeejin Ahn
551492812f6SHeejin Ahncatch.dispatch:                                   ; preds = %_ZN4TempD2Ev.exit
552492812f6SHeejin Ahn  %7 = catchswitch within none [label %catch.start] unwind to caller
553492812f6SHeejin Ahn
554492812f6SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
555492812f6SHeejin Ahn  %8 = catchpad within %7 [ptr null]
556492812f6SHeejin Ahn  %9 = tail call ptr @llvm.wasm.get.exception(token %8)
557492812f6SHeejin Ahn  %10 = tail call i32 @llvm.wasm.get.ehselector(token %8)
558492812f6SHeejin Ahn  %11 = call ptr @__cxa_begin_catch(ptr %9) #8 [ "funclet"(token %8) ]
559492812f6SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %8) ]
560492812f6SHeejin Ahn  catchret from %8 to label %try.cont
561492812f6SHeejin Ahn
562492812f6SHeejin Ahntry.cont:                                         ; preds = %catch.start
563492812f6SHeejin Ahn  ret void
564492812f6SHeejin Ahn
565492812f6SHeejin Ahnunreachable:                                      ; preds = %entry
566492812f6SHeejin Ahn  unreachable
567492812f6SHeejin Ahn}
568492812f6SHeejin Ahn
5696bbf7f06SHeejin Ahn
5706bbf7f06SHeejin Ahndeclare void @foo()
5716bbf7f06SHeejin Ahndeclare void @bar(ptr)
5726bbf7f06SHeejin Ahndeclare void @take_i32(i32)
5736bbf7f06SHeejin Ahndeclare i32 @__gxx_wasm_personality_v0(...)
5746bbf7f06SHeejin Ahn; Function Attrs: noreturn
5756bbf7f06SHeejin Ahndeclare void @llvm.wasm.throw(i32, ptr) #1
5766bbf7f06SHeejin Ahn; Function Attrs: nounwind
5776bbf7f06SHeejin Ahndeclare ptr @llvm.wasm.get.exception(token) #0
5786bbf7f06SHeejin Ahn; Function Attrs: nounwind
5796bbf7f06SHeejin Ahndeclare i32 @llvm.wasm.get.ehselector(token) #0
5806bbf7f06SHeejin Ahn; Function Attrs: noreturn
5816bbf7f06SHeejin Ahndeclare void @llvm.wasm.rethrow() #1
5826bbf7f06SHeejin Ahn; Function Attrs: nounwind
5836bbf7f06SHeejin Ahndeclare i32 @llvm.eh.typeid.for(ptr) #0
584492812f6SHeejin Ahn; Function Attrs: nounwind
585492812f6SHeejin Ahndeclare ptr @__cxa_allocate_exception(i32) #0
5866bbf7f06SHeejin Ahndeclare ptr @__cxa_begin_catch(ptr)
5876bbf7f06SHeejin Ahndeclare void @__cxa_end_catch()
588492812f6SHeejin Ahn; Function Attrs: noreturn
589492812f6SHeejin Ahndeclare void @__cxa_throw(ptr, ptr, ptr) #1
5906bbf7f06SHeejin Ahndeclare void @_ZSt9terminatev()
5916bbf7f06SHeejin Ahndeclare ptr @_ZN4TempD2Ev(ptr returned)
5926bbf7f06SHeejin Ahn
5936bbf7f06SHeejin Ahnattributes #0 = { nounwind }
5946bbf7f06SHeejin Ahnattributes #1 = { noreturn }
5956bbf7f06SHeejin Ahn
5966bbf7f06SHeejin Ahn; CHECK: __cpp_exception:
597