Files
clang-p2996/llvm/test/CodeGen/WebAssembly/exception.ll
Heejin Ahn e76fa9ecca [WebAssembly] CFG stackify support for exception handling
Summary:
This adds support for exception handling to CFGStackify pass. This only
adds TRY / END_TRY markers and DOES NOT yet fix unwind mismatches that
can be created by the linearization of the CFG into the structural wasm
format. The mismatch fix will be added by following patches.

In detail, this patch
- Added support for TRY / END_TRY markers to support EH
- Changed many static functions into class member functions as they take
too many arguments now
- Added several more bookeeping data structures
- Refactored routines that decide where to insert markers, because
without refactoring this got too complicated as we added support for new
kinds of markers (TRY/END_TRY).
- Rewrote rethrow instructions' BB arguments to relative depths in EH
pad stack.

Reviewers: dschuff, sunfish

Subscribers: sbc100, jgravelle-google, llvm-commits

Differential Revision: https://reviews.llvm.org/D48273

llvm-svn: 339967
2018-08-16 23:50:59 +00:00

164 lines
6.3 KiB
LLVM

; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -exception-model=wasm
; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -exception-model=wasm -mattr=+exception-handling | FileCheck -allow-deprecated-dag-overlap %s
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"
%struct.Cleanup = type { i8 }
@_ZTIi = external constant i8*
declare void @llvm.wasm.throw(i32, i8*)
; CHECK-LABEL: test_throw:
; CHECK-NEXT: i32.const $push0=, 0
; CHECK-NEXT: throw 0, $pop0
define void @test_throw() {
call void @llvm.wasm.throw(i32 0, i8* null)
ret void
}
; CHECK-LABEL: test_catch_rethrow:
; CHECK: try
; CHECK: call foo@FUNCTION
; CHECK: i32.catch $push{{.+}}=, 0
; CHECK-DAG: i32.store __wasm_lpad_context
; CHECK-DAG: i32.store __wasm_lpad_context+4
; CHECK: i32.call $push{{.+}}=, _Unwind_CallPersonality@FUNCTION
; CHECK: i32.call $push{{.+}}=, __cxa_begin_catch@FUNCTION
; CHECK: call __cxa_end_catch@FUNCTION
; CHECK: call __cxa_rethrow@FUNCTION
; CHECK-NEXT: rethrow
; CHECK: end_try
define void @test_catch_rethrow() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
entry:
invoke void @foo()
to label %try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
%0 = catchswitch within none [label %catch.start] unwind to caller
catch.start: ; preds = %catch.dispatch
%1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
%2 = call i8* @llvm.wasm.get.exception(token %1)
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
%4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
%matches = icmp eq i32 %3, %4
br i1 %matches, label %catch, label %rethrow
catch: ; preds = %catch.start
%5 = 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
rethrow: ; preds = %catch.start
call void @__cxa_rethrow() [ "funclet"(token %1) ]
unreachable
try.cont: ; preds = %entry, %catch
ret void
}
; CHECK-LABEL: test_cleanup:
; CHECK: try
; CHECK: call foo@FUNCTION
; CHECK: catch_all
; CHECK: i32.call $push{{.+}}=, _ZN7CleanupD1Ev@FUNCTION
; CHECK: rethrow
; CHECK: end_try
define void @test_cleanup() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
entry:
%c = alloca %struct.Cleanup, align 1
invoke void @foo()
to label %invoke.cont unwind label %ehcleanup
invoke.cont: ; preds = %entry
%call = call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c)
ret void
ehcleanup: ; preds = %entry
%0 = cleanuppad within none []
%call1 = call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c) [ "funclet"(token %0) ]
cleanupret from %0 unwind to caller
}
; - Tests multple terminate pads are merged into one
; - Tests a catch_all terminate pad is created after a catch terminate pad
; CHECK-LABEL: test_terminatepad
; CHECK: i32.catch
; CHECK: call __clang_call_terminate@FUNCTION
; CHECK: unreachable
; CHECK: catch_all
; CHECK: call _ZSt9terminatev@FUNCTION
; CHECK-NOT: call __clang_call_terminate@FUNCTION
define hidden i32 @test_terminatepad() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
entry:
%c = alloca %struct.Cleanup, align 1
%c1 = alloca %struct.Cleanup, align 1
invoke void @foo()
to label %invoke.cont unwind label %ehcleanup
invoke.cont: ; preds = %entry
%call = invoke %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c1)
to label %try.cont unwind label %catch.dispatch
ehcleanup: ; preds = %entry
%0 = cleanuppad within none []
%call4 = invoke %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c1) [ "funclet"(token %0) ]
to label %invoke.cont3 unwind label %terminate
invoke.cont3: ; preds = %ehcleanup
cleanupret from %0 unwind label %catch.dispatch
catch.dispatch: ; preds = %invoke.cont3, %invoke.cont
%1 = catchswitch within none [label %catch.start] unwind label %ehcleanup7
catch.start: ; preds = %catch.dispatch
%2 = catchpad within %1 [i8* null]
%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) ]
invoke void @__cxa_end_catch() [ "funclet"(token %2) ]
to label %invoke.cont5 unwind label %ehcleanup7
invoke.cont5: ; preds = %catch.start
catchret from %2 to label %try.cont
try.cont: ; preds = %invoke.cont5, %invoke.cont
%call6 = call %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c)
ret i32 0
ehcleanup7: ; preds = %catch.start, %catch.dispatch
%6 = cleanuppad within none []
%call9 = invoke %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* %c) [ "funclet"(token %6) ]
to label %invoke.cont8 unwind label %terminate10
invoke.cont8: ; preds = %ehcleanup7
cleanupret from %6 unwind to caller
terminate: ; preds = %ehcleanup
%7 = cleanuppad within %0 []
%8 = call i8* @llvm.wasm.get.exception(token %7)
call void @__clang_call_terminate(i8* %8) [ "funclet"(token %7) ]
unreachable
terminate10: ; preds = %ehcleanup7
%9 = cleanuppad within %6 []
%10 = call i8* @llvm.wasm.get.exception(token %9)
call void @__clang_call_terminate(i8* %10) [ "funclet"(token %9) ]
unreachable
}
declare void @foo()
declare i32 @__gxx_wasm_personality_v0(...)
declare i8* @llvm.wasm.get.exception(token)
declare i32 @llvm.wasm.get.ehselector(token)
declare i32 @llvm.eh.typeid.for(i8*)
declare i8* @__cxa_begin_catch(i8*)
declare void @__cxa_end_catch()
declare void @__cxa_rethrow()
declare void @__clang_call_terminate(i8*)
declare void @_ZSt9terminatev()
declare %struct.Cleanup* @_ZN7CleanupD1Ev(%struct.Cleanup* returned)