Index: test/CodeGen/WebAssembly/cfg-stackify-eh.ll =================================================================== --- test/CodeGen/WebAssembly/cfg-stackify-eh.ll +++ test/CodeGen/WebAssembly/cfg-stackify-eh.ll @@ -10,23 +10,22 @@ ; void test0() { ; try { ; foo(); -; } catch (int n) { +; } catch (int) { ; bar(); -; } catch (double d) { +; } catch (double) { ; } ; } ; CHECK-LABEL: test0 -; CHECK: try +; CHECK: try ; CHECK: call foo -; CHECK: catch $[[EXCEPT_REF:[0-9]+]]= +; CHECK: catch $[[EXCEPT_REF:[0-9]+]]= ; CHECK: block i32 -; CHECK: br_on_exn 0, __cpp_exception, $[[EXCEPT_REF]] -; CHECK: rethrow +; CHECK: br_on_exn 0, __cpp_exception, $[[EXCEPT_REF]] +; CHECK: rethrow ; CHECK: end_block ; CHECK: i32.call $drop=, _Unwind_CallPersonality -; CHECK: end_try -; CHECK: return +; CHECK: end_try define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { entry: invoke void @foo() @@ -75,41 +74,17 @@ ; void test1() { ; try { ; foo(); -; } catch (int n) { +; } catch (int) { ; try { ; foo(); -; } catch (int n) { +; } catch (int) { ; foo(); ; } ; } ; } ; CHECK-LABEL: test1 -; CHECK: try -; CHECK: call foo -; CHECK: catch -; CHECK: br_on_exn 0, __cpp_exception -; CHECK: rethrow -; CHECK: i32.call $drop=, _Unwind_CallPersonality -; CHECK: try -; CHECK: call foo -; CHECK: catch -; CHECK: br_on_exn 0, __cpp_exception -; CHECK: rethrow -; CHECK: i32.call $drop=, _Unwind_CallPersonality -; CHECK: try -; CHECK: i32.call $drop=, __cxa_begin_catch -; CHECK: try -; CHECK: call foo -; CHECK: catch $drop= -; CHECK: rethrow -; CHECK: end_try -; CHECK: catch $drop= -; CHECK: rethrow -; CHECK: end_try -; CHECK: end_try -; CHECK: end_try -; CHECK: return +; TODO Fill in check lines define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { entry: invoke void @foo() @@ -195,29 +170,7 @@ ; } ; CHECK-LABEL: test2 -; CHECK: try -; CHECK: call foo -; CHECK: catch -; CHECK: br_on_exn 0, __cpp_exception -; CHECK: rethrow -; CHECK: loop -; CHECK: try -; CHECK: call foo -; CHECK: catch $drop= -; CHECK: try -; CHECK: call __cxa_end_catch -; CHECK: catch -; CHECK: br_on_exn 0, __cpp_exception -; CHECK: call __clang_call_terminate, 0 -; CHECK: unreachable -; CHECK: call __clang_call_terminate -; CHECK: unreachable -; CHECK: end_try -; CHECK: rethrow -; CHECK: end_try -; CHECK: end_loop -; CHECK: end_try -; CHECK: return +; TODO Fill in check lines define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { entry: invoke void @foo() Index: test/CodeGen/WebAssembly/exception.ll =================================================================== --- test/CodeGen/WebAssembly/exception.ll +++ test/CodeGen/WebAssembly/exception.ll @@ -5,45 +5,53 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" -%struct.Cleanup = type { i8 } +%struct.Temp = type { i8 } @_ZTIi = external constant i8* ; CHECK-LABEL: test_throw: -; CHECK: throw __cpp_exception, $0 -; CHECK-NOT: unreachable +; CHECK: throw __cpp_exception, $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 +; 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 ${{.+}}=, __stack_pointer -; CHECK: try -; CHECK: call foo -; CHECK: catch $[[EXCEPT_REF:[0-9]+]]= -; CHECK: global.set __stack_pointer -; CHECK: block i32 -; CHECK: br_on_exn 0, __cpp_exception, $[[EXCEPT_REF]] -; CHECK: rethrow -; CHECK: end_block -; CHECK: extract_exception $[[EXN:[0-9]+]]= +; Simple test with a try-catch +; void test_catch() { +; try { +; foo(); +; } catch (int) { +; } +; } + +; CHECK-LABEL: test_catch: +; CHECK: global.get ${{.+}}=, __stack_pointer +; CHECK: try +; CHECK: call foo +; CHECK: catch $[[EXCEPT_REF:[0-9]+]]= +; CHECK: global.set __stack_pointer +; CHECK: block i32 +; CHECK: br_on_exn 0, __cpp_exception, $[[EXCEPT_REF]] +; CHECK: rethrow +; CHECK: end_block +; CHECK: extract_exception $[[EXN:[0-9]+]]= ; CHECK-DAG: i32.store __wasm_lpad_context ; CHECK-DAG: i32.store __wasm_lpad_context+4 -; CHECK: i32.call $drop=, _Unwind_CallPersonality, $[[EXN]] -; CHECK: i32.call $drop=, __cxa_begin_catch -; CHECK: call __cxa_end_catch -; CHECK: call __cxa_rethrow -; CHECK: end_try -define void @test_catch_rethrow() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { +; CHECK: i32.call $drop=, _Unwind_CallPersonality, $[[EXN]] +; CHECK: i32.call $drop=, __cxa_begin_catch +; CHECK: call __cxa_end_catch +; CHECK: call __cxa_rethrow +; CHECK: end_try +define void @test_catch() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { entry: invoke void @foo() to label %try.cont unwind label %catch.dispatch @@ -72,40 +80,68 @@ ret void } +; Destructor (cleanup) test +; struct Temp { +; ~Temp() {} +; }; +; void test_cleanup() { +; Temp t; +; foo(); +; } + ; CHECK-LABEL: test_cleanup: -; CHECK: try +; CHECK: try ; CHECK: call foo -; CHECK: catch +; CHECK: catch ; CHECK: global.set __stack_pointer -; CHECK: i32.call $drop=, _ZN7CleanupD1Ev +; CHECK: i32.call $drop=, _ZN4TempD2Ev ; CHECK: rethrow -; CHECK: end_try +; CHECK: end_try define void @test_cleanup() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { entry: - %c = alloca %struct.Cleanup, align 1 + %t = alloca %struct.Temp, align 1 invoke void @foo() to label %invoke.cont unwind label %ehcleanup invoke.cont: ; preds = %entry - %call = call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c) + %call = call %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* %t) ret void ehcleanup: ; preds = %entry %0 = cleanuppad within none [] - %call1 = call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c) [ "funclet"(token %0) ] + %call1 = call %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* %t) [ "funclet"(token %0) ] cleanupret from %0 unwind to caller } +; Calling a function that may throw within a 'catch (...)' generates a +; temrinatepad, because __cxa_end_catch() also can throw within 'catch (...)'. +; void test_terminatepad() { +; try { +; foo(); +; } catch (...) { +; foo(); +; } +; } + ; CHECK-LABEL: test_terminatepad +; CHECK: try +; CHECK: call foo +; CHECK: catch +; CHECK: try +; CHECK: call foo ; CHECK: catch -; CHECK: block i32 -; CHECK: br_on_exn 0, __cpp_exception -; CHECK: call __clang_call_terminate, 0 -; CHECK: unreachable -; CHECK: end_block -; CHECK: extract_exception -; CHECK: call __clang_call_terminate -; CHECK: unreachable +; CHECK: try +; CHECK: call __cxa_end_catch +; CHECK: catch +; CHECK: block i32 +; CHECK: br_on_exn 0, __cpp_exception +; CHECK: call __clang_call_terminate, 0 +; CHECK: end_block +; CHECK: call __clang_call_terminate +; CHECK: end_try +; CHECK: rethrow +; CHECK: end_try +; CHECK: end_try define void @test_terminatepad() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { entry: invoke void @foo() @@ -151,21 +187,21 @@ ; instructions after a catch instruction. ; CHECK-LABEL: test_no_prolog_epilog_in_ehpad -; CHECK: try -; CHECK: call foo -; CHECK: catch -; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer -; CHECK: global.set __stack_pointer -; CHECK: try -; CHECK: call foo -; CHECK: catch -; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer -; CHECK: global.set __stack_pointer -; CHECK: call __cxa_end_catch -; CHECK-NOT: global.set __stack_pointer, $pop{{.+}} -; CHECK: end_try -; CHECK-NOT: global.set __stack_pointer, $pop{{.+}} -; CHECK: end_try +; CHECK: try +; CHECK: call foo +; CHECK: catch +; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer +; CHECK: global.set __stack_pointer +; CHECK: try +; CHECK: call foo +; CHECK: catch +; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer +; CHECK: global.set __stack_pointer +; CHECK: call __cxa_end_catch +; CHECK-NOT: global.set __stack_pointer, $pop{{.+}} +; CHECK: end_try +; CHECK-NOT: global.set __stack_pointer, $pop{{.+}} +; CHECK: end_try define void @test_no_prolog_epilog_in_ehpad() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { entry: %stack_var = alloca i32, align 4 @@ -212,11 +248,12 @@ ; store SP back to __stack_pointer global at the epilog. ; CHECK-LABEL: no_sp_writeback -; CHECK: try -; CHECK: call foo -; CHECK: end_try -; CHECK-NOT: global.set __stack_pointer -; CHECK: return +; CHECK: try +; CHECK: call foo +; CHECK: catch +; CHECK: end_try +; CHECK-NOT: global.set __stack_pointer +; CHECK: return define void @no_sp_writeback() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) { entry: invoke void @foo() @@ -249,7 +286,7 @@ declare void @__cxa_end_catch() declare void @__cxa_rethrow() declare void @__clang_call_terminate(i8*) -declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned) +declare %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* returned) ; CHECK: __cpp_exception: ; CHECK: .eventtype __cpp_exception i32