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