| # RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+exception-handling < %s | FileCheck %s |
| # Check that it converts to .o without errors, but don't check any output: |
| # RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+exception-handling -o %t.o < %s |
| |
| .tagtype __cpp_exception i32 |
| .tagtype __c_longjmp i32 |
| .functype foo () -> () |
| |
| eh_test: |
| .functype eh_test (exnref) -> () |
| |
| # try_table with all four kinds of catch clauses |
| block exnref |
| block |
| block () -> (i32, exnref) |
| block i32 |
| try_table (catch __cpp_exception 0) (catch_ref __c_longjmp 1) (catch_all 2) (catch_all_ref 3) |
| i32.const 0 |
| throw __cpp_exception |
| end_try_table |
| return |
| end_block |
| drop |
| return |
| end_block |
| throw_ref |
| end_block |
| return |
| end_block |
| drop |
| |
| # You can use the same kind of catch clause more than once |
| block |
| block exnref |
| block |
| try_table (catch_all 0) (catch_all_ref 1) (catch_all 2) |
| call foo |
| end_try_table |
| end_block |
| return |
| end_block |
| drop |
| end_block |
| |
| # Two catch clauses targeting the same block |
| block |
| try_table (catch_all 0) (catch_all 0) |
| end_try_table |
| end_block |
| |
| # try_table with a return type |
| block |
| try_table f32 (catch_all 0) |
| f32.const 0.0 |
| end_try_table |
| drop |
| end_block |
| |
| # try_table with a multivalue type return |
| block |
| try_table () -> (i32, f32) (catch_all 0) |
| i32.const 0 |
| f32.const 0.0 |
| end_try_table |
| drop |
| drop |
| end_block |
| |
| # catch-less try_tables |
| try_table |
| call foo |
| end_try_table |
| |
| try_table i32 |
| i32.const 0 |
| end_try_table |
| drop |
| |
| try_table () -> (i32, f32) |
| i32.const 0 |
| f32.const 0.0 |
| end_try_table |
| drop |
| drop |
| |
| # try_table targeting loops |
| i32.const 0 |
| loop (i32) -> () |
| local.get 0 |
| loop (exnref) -> () |
| try_table (catch __cpp_exception 1) (catch_all_ref 0) |
| end_try_table |
| drop |
| end_loop |
| drop |
| end_loop |
| end_function |
| |
| eh_legacy_test: |
| .functype eh_legacy_test () -> () |
| |
| # try-catch with catch, catch_all, throw, and rethrow |
| try |
| i32.const 3 |
| throw __cpp_exception |
| catch __cpp_exception |
| drop |
| rethrow 0 |
| catch __c_longjmp |
| drop |
| catch_all |
| rethrow 0 |
| end_try |
| |
| # Nested try-catch with a rethrow |
| try |
| call foo |
| catch_all |
| try |
| catch_all |
| rethrow 1 |
| end_try |
| end_try |
| |
| # try-catch with a single return value |
| try i32 |
| i32.const 0 |
| catch __cpp_exception |
| end_try |
| drop |
| |
| # try-catch with a mulvivalue return |
| try () -> (i32, f32) |
| i32.const 0 |
| f32.const 0.0 |
| catch __cpp_exception |
| f32.const 1.0 |
| end_try |
| drop |
| drop |
| |
| # Catch-less try |
| try |
| call foo |
| end_try |
| end_function |
| |
| |
| # CHECK-LABEL: eh_test: |
| # CHECK: block exnref |
| # CHECK-NEXT: block |
| # CHECK-NEXT: block () -> (i32, exnref) |
| # CHECK-NEXT: block i32 |
| # CHECK-NEXT: try_table (catch __cpp_exception 0) (catch_ref __c_longjmp 1) (catch_all 2) (catch_all_ref 3) |
| # CHECK: i32.const 0 |
| # CHECK-NEXT: throw __cpp_exception |
| # CHECK-NEXT: end_try_table |
| # CHECK-NEXT: return |
| # CHECK-NEXT: end_block |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: return |
| # CHECK-NEXT: end_block |
| # CHECK-NEXT: throw_ref |
| # CHECK-NEXT: end_block |
| # CHECK-NEXT: return |
| # CHECK-NEXT: end_block |
| # CHECK-NEXT: drop |
| |
| # CHECK: block |
| # CHECK-NEXT: block exnref |
| # CHECK-NEXT: block |
| # CHECK-NEXT: try_table (catch_all 0) (catch_all_ref 1) (catch_all 2) |
| # CHECK: call foo |
| # CHECK-NEXT: end_try_table |
| # CHECK-NEXT: end_block |
| # CHECK-NEXT: return |
| # CHECK-NEXT: end_block |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: end_block |
| |
| # CHECK: block |
| # CHECK-NEXT: try_table (catch_all 0) (catch_all 0) |
| # CHECK: end_try_table |
| # CHECK-NEXT: end_block |
| |
| # CHECK: block |
| # CHECK-NEXT: try_table f32 (catch_all 0) |
| # CHECK: f32.const 0x0p0 |
| # CHECK-NEXT: end_try_table |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: end_block |
| |
| # CHECK: block |
| # CHECK-NEXT: try_table () -> (i32, f32) (catch_all 0) |
| # CHECK: i32.const 0 |
| # CHECK-NEXT: f32.const 0x0p0 |
| # CHECK-NEXT: end_try_table |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: end_block |
| |
| # CHECK: try_table |
| # CHECK-NEXT: call foo |
| # CHECK-NEXT: end_try_table |
| |
| # CHECK: try_table i32 |
| # CHECK-NEXT: i32.const 0 |
| # CHECK-NEXT: end_try_table |
| # CHECK-NEXT: drop |
| |
| # CHECK: try_table () -> (i32, f32) |
| # CHECK-NEXT: i32.const 0 |
| # CHECK-NEXT: f32.const 0x0p0 |
| # CHECK-NEXT: end_try_table |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: drop |
| |
| # CHECK: i32.const 0 |
| # CHECK-NEXT: loop (i32) -> () |
| # CHECK-NEXT: local.get 0 |
| # CHECK-NEXT: loop (exnref) -> () |
| # CHECK-NEXT: try_table (catch __cpp_exception 1) (catch_all_ref 0) |
| # CHECK: end_try_table |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: end_loop |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: end_loop |
| |
| # CHECK: eh_legacy_test: |
| # CHECK: try |
| # CHECK-NEXT: i32.const 3 |
| # CHECK-NEXT: throw __cpp_exception |
| # CHECK-NEXT: catch __cpp_exception |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: rethrow 0 |
| # CHECK-NEXT: catch __c_longjmp |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: catch_all |
| # CHECK-NEXT: rethrow 0 |
| # CHECK-NEXT: end_try |
| |
| # CHECK: try |
| # CHECK-NEXT: call foo |
| # CHECK-NEXT: catch_all |
| # CHECK-NEXT: try |
| # CHECK-NEXT: catch_all |
| # CHECK-NEXT: rethrow 1 |
| # CHECK-NEXT: end_try |
| # CHECK-NEXT: end_try |
| |
| # CHECK: try i32 |
| # CHECK-NEXT: i32.const 0 |
| # CHECK-NEXT: catch __cpp_exception |
| # CHECK-NEXT: end_try |
| # CHECK-NEXT: drop |
| |
| # CHECK: try () -> (i32, f32) |
| # CHECK-NEXT: i32.const 0 |
| # CHECK-NEXT: f32.const 0x0p0 |
| # CHECK-NEXT: catch __cpp_exception |
| # CHECK-NEXT: f32.const 0x1p0 |
| # CHECK-NEXT: end_try |
| # CHECK-NEXT: drop |
| # CHECK-NEXT: drop |
| |
| # CHECK: try |
| # CHECK-NEXT: call foo |
| # CHECK-NEXT: end_try |