forked from OSchip/llvm-project
[WebAssembly] Improve readability of EH tests
Summary: - Indent check lines to easily figure out try-catch-end structure - Add the original C++ code the tests were genereated from - Add a few more lines to make the structure more readable - Rename a couple function / structures - Add label and branch annotations to cfg-stackify-eh.ll - Temporarily delete check lines for `test1` in `cfg-stackify-eh.ll` because it will be updated in a later CL soon and there's no point of making it look better here Reviewers: dschuff Subscribers: sunfish, sbc100, jgravelle-google, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D58562 llvm-svn: 354842
This commit is contained in:
parent
1d5f8632d7
commit
7829763e49
|
@ -1,4 +1,4 @@
|
|||
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling | FileCheck %s
|
||||
; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32-unknown-unknown"
|
||||
|
@ -7,26 +7,37 @@ target triple = "wasm32-unknown-unknown"
|
|||
@_ZTId = external constant i8*
|
||||
|
||||
; Simple test case with two catch clauses
|
||||
;
|
||||
; void foo();
|
||||
; void test0() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int n) {
|
||||
; bar();
|
||||
; } catch (double d) {
|
||||
; } catch (int) {
|
||||
; } catch (double) {
|
||||
; }
|
||||
; }
|
||||
|
||||
; CHECK-LABEL: test0
|
||||
; CHECK: block
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; CHECK: catch $[[EXCEPT_REF:[0-9]+]]=
|
||||
; CHECK: block i32
|
||||
; 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: call foo
|
||||
; CHECK: br 0 # 0: down to label1
|
||||
; CHECK: catch
|
||||
; CHECK: block
|
||||
; CHECK: br_if 0, {{.*}} # 0: down to label3
|
||||
; CHECK: i32.call $drop=, __cxa_begin_catch
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: br 1 # 1: down to label1
|
||||
; CHECK: end_block # label3:
|
||||
; CHECK: block
|
||||
; CHECK: br_if 0, {{.*}} # 0: down to label4
|
||||
; CHECK: i32.call $drop=, __cxa_begin_catch
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: br 1 # 1: down to label1
|
||||
; CHECK: end_block # label4:
|
||||
; CHECK: call __cxa_rethrow
|
||||
; CHECK: end_try # label1:
|
||||
; CHECK: end_block
|
||||
define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
entry:
|
||||
invoke void @foo()
|
||||
|
@ -45,21 +56,16 @@ catch.start: ; preds = %catch.dispatch
|
|||
|
||||
catch2: ; preds = %catch.start
|
||||
%5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
|
||||
%6 = bitcast i8* %5 to i32*
|
||||
%7 = load i32, i32* %6, align 4
|
||||
call void @bar() [ "funclet"(token %1) ]
|
||||
call void @__cxa_end_catch() [ "funclet"(token %1) ]
|
||||
catchret from %1 to label %try.cont
|
||||
|
||||
catch.fallthrough: ; preds = %catch.start
|
||||
%8 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*))
|
||||
%matches1 = icmp eq i32 %3, %8
|
||||
%6 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTId to i8*))
|
||||
%matches1 = icmp eq i32 %3, %6
|
||||
br i1 %matches1, label %catch, label %rethrow
|
||||
|
||||
catch: ; preds = %catch.fallthrough
|
||||
%9 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
|
||||
%10 = bitcast i8* %9 to double*
|
||||
%11 = load double, double* %10, align 8
|
||||
%7 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
|
||||
call void @__cxa_end_catch() [ "funclet"(token %1) ]
|
||||
catchret from %1 to label %try.cont
|
||||
|
||||
|
@ -75,41 +81,17 @@ try.cont: ; preds = %entry, %catch, %cat
|
|||
; 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 once we fix ScopeTops info bug in D58605
|
||||
define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
entry:
|
||||
invoke void @foo()
|
||||
|
@ -195,29 +177,39 @@ unreachable: ; preds = %rethrow5
|
|||
; }
|
||||
|
||||
; CHECK-LABEL: test2
|
||||
; CHECK: block
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; CHECK: call foo
|
||||
; CHECK: br 0 # 0: down to label17
|
||||
; 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
|
||||
; CHECK: i32.call $drop=, __cxa_begin_catch
|
||||
; CHECK: loop # label19:
|
||||
; CHECK: block
|
||||
; CHECK: block
|
||||
; CHECK: br_if 0, {{.*}} # 0: down to label21
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; CHECK: br 2 # 2: down to label20
|
||||
; CHECK: catch
|
||||
; CHECK: block
|
||||
; CHECK: try
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: br 0 # 0: down to label24
|
||||
; CHECK: catch
|
||||
; CHECK: call __clang_call_terminate
|
||||
; CHECK: unreachable
|
||||
; CHECK: end_try # label24:
|
||||
; CHECK: end_block
|
||||
; CHECK: rethrow # to caller
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block # label21:
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: br 2 # 2: down to label17
|
||||
; CHECK: end_block # label20:
|
||||
; CHECK: br 0 # 0: up to label19
|
||||
; CHECK: end_loop
|
||||
; CHECK: end_try # label17:
|
||||
; CHECK: end_block
|
||||
define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
entry:
|
||||
invoke void @foo()
|
||||
|
|
|
@ -5,45 +5,62 @@
|
|||
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]+]]=
|
||||
; 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*) {
|
||||
; Simple test with a try-catch
|
||||
;
|
||||
; void foo();
|
||||
; void test_catch() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; }
|
||||
; }
|
||||
|
||||
; CHECK-LABEL: test_catch:
|
||||
; CHECK: global.get ${{.+}}=, __stack_pointer
|
||||
; CHECK: block
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; CHECK: br 0
|
||||
; 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: block
|
||||
; CHECK: br_if 0
|
||||
; CHECK: i32.call $drop=, __cxa_begin_catch
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: br 1
|
||||
; CHECK: end_block
|
||||
; CHECK: call __cxa_rethrow
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block
|
||||
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 +89,88 @@ try.cont: ; preds = %entry, %catch
|
|||
ret void
|
||||
}
|
||||
|
||||
; Destructor (cleanup) test
|
||||
;
|
||||
; void foo();
|
||||
; struct Temp {
|
||||
; ~Temp() {}
|
||||
; };
|
||||
; void test_cleanup() {
|
||||
; Temp t;
|
||||
; foo();
|
||||
; }
|
||||
|
||||
; CHECK-LABEL: test_cleanup:
|
||||
; CHECK: block
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; CHECK: call foo
|
||||
; CHECK: br 0
|
||||
; CHECK: catch
|
||||
; CHECK: global.set __stack_pointer
|
||||
; CHECK: i32.call $drop=, _ZN7CleanupD1Ev
|
||||
; CHECK: rethrow
|
||||
; CHECK: global.set __stack_pointer
|
||||
; CHECK: i32.call $drop=, _ZN4TempD2Ev
|
||||
; CHECK: rethrow
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block
|
||||
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 foo();
|
||||
; void test_terminatepad() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (...) {
|
||||
; foo();
|
||||
; }
|
||||
; }
|
||||
|
||||
; CHECK-LABEL: test_terminatepad
|
||||
; CHECK: block
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; CHECK: br 0
|
||||
; 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: i32.call $drop=, __cxa_begin_catch
|
||||
; CHECK: block
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; CHECK: br 0
|
||||
; CHECK: catch
|
||||
; CHECK: block
|
||||
; CHECK: try
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: br 0
|
||||
; CHECK: catch
|
||||
; CHECK: block i32
|
||||
; CHECK: br_on_exn 0, __cpp_exception
|
||||
; CHECK: call __clang_call_terminate, 0
|
||||
; CHECK: unreachable
|
||||
; CHECK: end_block
|
||||
; CHECK: call __clang_call_terminate
|
||||
; CHECK: unreachable
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block
|
||||
; CHECK: rethrow
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block
|
||||
define void @test_terminatepad() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
entry:
|
||||
invoke void @foo()
|
||||
|
@ -149,23 +214,47 @@ terminate: ; preds = %ehcleanup
|
|||
; should not have a prologue, and BBs ending with a catchret/cleanupret should
|
||||
; not have an epilogue. This is separate from __stack_pointer restoring
|
||||
; instructions after a catch instruction.
|
||||
;
|
||||
; void bar(int) noexcept;
|
||||
; void test_no_prolog_epilog_in_ehpad() {
|
||||
; int stack_var = 0;
|
||||
; bar(stack_var);
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; foo();
|
||||
; }
|
||||
; }
|
||||
|
||||
; 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: block
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; CHECK: br 0
|
||||
; CHECK: catch
|
||||
; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer
|
||||
; CHECK: global.set __stack_pointer
|
||||
; CHECK: block
|
||||
; CHECK: block
|
||||
; CHECK: br_if 0
|
||||
; CHECK: i32.call $drop=, __cxa_begin_catch
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; CHECK: br 2
|
||||
; CHECK: catch
|
||||
; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer
|
||||
; CHECK: global.set __stack_pointer
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: rethrow
|
||||
; CHECK-NOT: global.set __stack_pointer, $pop{{.+}}
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block
|
||||
; CHECK: call __cxa_rethrow
|
||||
; CHECK: end_block
|
||||
; CHECK-NOT: global.set __stack_pointer, $pop{{.+}}
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block
|
||||
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
|
||||
|
@ -210,14 +299,28 @@ ehcleanup: ; preds = %catch
|
|||
|
||||
; When a function does not have stack-allocated objects, it does not need to
|
||||
; store SP back to __stack_pointer global at the epilog.
|
||||
;
|
||||
; void foo();
|
||||
; void test_no_sp_writeback() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (...) {
|
||||
; }
|
||||
; }
|
||||
|
||||
; CHECK-LABEL: no_sp_writeback
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; 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*) {
|
||||
; CHECK-LABEL: test_no_sp_writeback
|
||||
; CHECK: block
|
||||
; CHECK: try
|
||||
; CHECK: call foo
|
||||
; CHECK: br 0
|
||||
; CHECK: catch
|
||||
; CHECK: i32.call $drop=, __cxa_begin_catch
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block
|
||||
; CHECK-NOT: global.set __stack_pointer
|
||||
; CHECK: return
|
||||
define void @test_no_sp_writeback() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
entry:
|
||||
invoke void @foo()
|
||||
to label %try.cont unwind label %catch.dispatch
|
||||
|
@ -249,7 +352,7 @@ declare i8* @__cxa_begin_catch(i8*)
|
|||
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
|
||||
|
|
|
@ -6,11 +6,19 @@ target triple = "wasm32-unknown-unknown"
|
|||
; CHECK: @__wasm_lpad_context = external global { i32, i8*, i32 }
|
||||
|
||||
@_ZTIi = external constant i8*
|
||||
%struct.Cleanup = type { i8 }
|
||||
%struct.Temp = type { i8 }
|
||||
|
||||
; A single 'catch (int)' clause.
|
||||
; A wasm.catch() call, wasm.lsda() call, and personality call to generate a
|
||||
; selector should all be genereated after the catchpad.
|
||||
;
|
||||
; void foo();
|
||||
; void test0() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; }
|
||||
; }
|
||||
define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test0()
|
||||
entry:
|
||||
|
@ -53,11 +61,23 @@ try.cont: ; preds = %entry, %catch
|
|||
ret void
|
||||
}
|
||||
|
||||
; Two try-catches, one of them is with a single 'catch (...)' clause.
|
||||
; Two try-catches.
|
||||
; For the catchpad with a single 'catch (...)', only a wasm.catch() call should
|
||||
; be generated after the catchpad; wasm.landingpad.index() and personality call
|
||||
; should NOT be generated. For the other catchpad, the argument of
|
||||
; wasm.landingpad.index() should be not 1 but 0.
|
||||
;
|
||||
; void foo();
|
||||
; void test1() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (...) {
|
||||
; }
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; }
|
||||
; }
|
||||
define void @test1() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test1()
|
||||
entry:
|
||||
|
@ -112,8 +132,20 @@ try.cont7: ; preds = %try.cont, %catch4
|
|||
ret void
|
||||
}
|
||||
|
||||
; A nested try-catch within a catch. Within the nested catchpad, wasm.lsda()
|
||||
; call should NOT be generated.
|
||||
; A nested try-catch within a catch.
|
||||
;
|
||||
; void foo();
|
||||
; void test2() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (int) {
|
||||
; }
|
||||
; }
|
||||
; }
|
||||
; Within the nested catchpad, wasm.lsda() call should NOT be generated.
|
||||
define void @test2() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test2()
|
||||
entry:
|
||||
|
@ -189,6 +221,15 @@ unreachable: ; preds = %rethrow5
|
|||
|
||||
; A cleanuppad with a call to __clang_call_terminate().
|
||||
; A call to wasm.catch() should be generated after the cleanuppad.
|
||||
;
|
||||
; void foo();
|
||||
; void test3() {
|
||||
; try {
|
||||
; foo();
|
||||
; } catch (...) {
|
||||
; foo();
|
||||
; }
|
||||
; }
|
||||
define void @test3() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test3
|
||||
entry:
|
||||
|
@ -234,10 +275,37 @@ terminate: ; preds = %ehcleanup
|
|||
|
||||
; PHI demotion test. Only the phi before catchswitch should be demoted; the phi
|
||||
; before cleanuppad should NOT.
|
||||
;
|
||||
; void foo();
|
||||
; int bar(int) noexcept;
|
||||
; struct Temp {
|
||||
; ~Temp() {}
|
||||
; };
|
||||
;
|
||||
; void test4() {
|
||||
; int num;
|
||||
; try {
|
||||
; Temp t;
|
||||
; num = 1;
|
||||
; foo();
|
||||
; num = 2;
|
||||
; foo();
|
||||
; } catch (...) {
|
||||
; bar(num);
|
||||
; }
|
||||
; try {
|
||||
; foo();
|
||||
; num = 1;
|
||||
; foo();
|
||||
; num = 2;
|
||||
; } catch (...) {
|
||||
; bar(num);
|
||||
; }
|
||||
; }
|
||||
define void @test4() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
; CHECK-LABEL: @test4
|
||||
entry:
|
||||
%c = alloca %struct.Cleanup, align 1
|
||||
%t = alloca %struct.Temp, align 1
|
||||
invoke void @foo()
|
||||
to label %invoke.cont unwind label %ehcleanup
|
||||
|
||||
|
@ -246,13 +314,13 @@ invoke.cont: ; preds = %entry
|
|||
to label %invoke.cont1 unwind label %ehcleanup
|
||||
|
||||
invoke.cont1: ; preds = %invoke.cont
|
||||
%call = call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c)
|
||||
%call = call %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* %t)
|
||||
br label %try.cont
|
||||
|
||||
ehcleanup: ; preds = %invoke.cont, %entry
|
||||
%num.0 = phi i32 [ 2, %invoke.cont ], [ 1, %entry ]
|
||||
%0 = cleanuppad within none []
|
||||
%call2 = call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c) [ "funclet"(token %0) ]
|
||||
%call2 = call %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* %t) [ "funclet"(token %0) ]
|
||||
cleanupret from %0 unwind label %catch.dispatch
|
||||
; CHECK: ehcleanup:
|
||||
; CHECK-NEXT: = phi
|
||||
|
@ -265,7 +333,7 @@ catch.start: ; preds = %catch.dispatch
|
|||
%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) ]
|
||||
call void @func(i32 %num.0) [ "funclet"(token %2) ]
|
||||
call void @bar(i32 %num.0) [ "funclet"(token %2) ]
|
||||
call void @__cxa_end_catch() [ "funclet"(token %2) ]
|
||||
catchret from %2 to label %try.cont
|
||||
|
||||
|
@ -288,7 +356,7 @@ catch.start6: ; preds = %catch.dispatch5
|
|||
%8 = call i8* @llvm.wasm.get.exception(token %7)
|
||||
%9 = call i32 @llvm.wasm.get.ehselector(token %7)
|
||||
%10 = call i8* @__cxa_begin_catch(i8* %8) [ "funclet"(token %7) ]
|
||||
call void @func(i32 %num.1) [ "funclet"(token %7) ]
|
||||
call void @bar(i32 %num.1) [ "funclet"(token %7) ]
|
||||
call void @__cxa_end_catch() [ "funclet"(token %7) ]
|
||||
catchret from %7 to label %try.cont10
|
||||
|
||||
|
@ -353,8 +421,8 @@ merge: ; preds = %bb.true.0, %bb.fals
|
|||
}
|
||||
|
||||
declare void @foo()
|
||||
declare void @func(i32)
|
||||
declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned)
|
||||
declare void @bar(i32)
|
||||
declare %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* returned)
|
||||
declare i32 @__gxx_wasm_personality_v0(...)
|
||||
declare i8* @llvm.wasm.get.exception(token)
|
||||
declare i32 @llvm.wasm.get.ehselector(token)
|
||||
|
|
Loading…
Reference in New Issue