| Index: test/Transforms/NaCl/pnacl-sjlj-eh.ll
|
| diff --git a/test/Transforms/NaCl/pnacl-sjlj-eh.ll b/test/Transforms/NaCl/pnacl-sjlj-eh.ll
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3783b08a5edc339c4762ae8710067015b311d7db
|
| --- /dev/null
|
| +++ b/test/Transforms/NaCl/pnacl-sjlj-eh.ll
|
| @@ -0,0 +1,127 @@
|
| +; RUN: opt %s -pnacl-sjlj-eh -S | FileCheck %s
|
| +
|
| +; This must be declared for expanding "invoke" and "landingpad" instructions.
|
| +@__pnacl_eh_stack = external thread_local global i8*
|
| +
|
| +; This must be declared for expanding "resume" instructions.
|
| +declare void @__pnacl_eh_resume(i32* %exception)
|
| +
|
| +declare i32 @external_func(i64 %arg)
|
| +
|
| +
|
| +; CHECK: %ExceptionFrame = type { [1024 x i8], %ExceptionFrame*, i32 }
|
| +
|
| +define i32 @invoke_test(i64 %arg) {
|
| + %result = invoke i32 @external_func(i64 %arg)
|
| + to label %cont unwind label %lpad
|
| +cont:
|
| + ret i32 %result
|
| +lpad:
|
| + %lp = landingpad { i8*, i32 } personality i8* null cleanup
|
| + ret i32 999
|
| +}
|
| +; CHECK: define i32 @invoke_test
|
| +; CHECK-NEXT: %invoke_frame = alloca %ExceptionFrame, align 8
|
| +; CHECK-NEXT: %exc_info_ptr = getelementptr %ExceptionFrame* %invoke_frame, i32 0, i32 2
|
| +; CHECK-NEXT: %invoke_next = getelementptr %ExceptionFrame* %invoke_frame, i32 0, i32 1
|
| +; CHECK-NEXT: %invoke_jmp_buf = getelementptr %ExceptionFrame* %invoke_frame, i32 0, i32 0, i32 0
|
| +; CHECK-NEXT: %pnacl_eh_stack = bitcast i8** @__pnacl_eh_stack to %ExceptionFrame**
|
| +; CHECK-NEXT: %invoke_sj = call i32 @llvm.nacl.setjmp(i8* %invoke_jmp_buf)
|
| +; CHECK-NEXT: %invoke_sj_is_zero = icmp eq i32 %invoke_sj, 0
|
| +; CHECK-NEXT: br i1 %invoke_sj_is_zero, label %invoke_do_call, label %lpad
|
| +; CHECK: invoke_do_call:
|
| +; CHECK-NEXT: %old_eh_stack = load %ExceptionFrame** %pnacl_eh_stack
|
| +; CHECK-NEXT: store %ExceptionFrame* %old_eh_stack, %ExceptionFrame** %invoke_next
|
| +; CHECK-NEXT: store i32 {{[0-9]+}}, i32* %exc_info_ptr
|
| +; CHECK-NEXT: store %ExceptionFrame* %invoke_frame, %ExceptionFrame** %pnacl_eh_stack
|
| +; CHECK-NEXT: %result = call i32 @external_func(i64 %arg)
|
| +; CHECK-NEXT: store %ExceptionFrame* %old_eh_stack, %ExceptionFrame** %pnacl_eh_stack
|
| +; CHECK-NEXT: br label %cont
|
| +; CHECK: cont:
|
| +; CHECK-NEXT: ret i32 %result
|
| +; CHECK: lpad:
|
| +; CHECK-NEXT: %landingpad_ptr = bitcast i8* %invoke_jmp_buf to { i8*, i32 }*
|
| +; CHECK-NEXT: %lp = load { i8*, i32 }* %landingpad_ptr
|
| +; CHECK-NEXT: ret i32 999
|
| +
|
| +
|
| +; A landingpad block may be used by multiple "invoke" instructions.
|
| +define i32 @shared_landingpad(i64 %arg) {
|
| + %result1 = invoke i32 @external_func(i64 %arg)
|
| + to label %cont1 unwind label %lpad
|
| +cont1:
|
| + %result2 = invoke i32 @external_func(i64 %arg)
|
| + to label %cont2 unwind label %lpad
|
| +cont2:
|
| + ret i32 %result2
|
| +lpad:
|
| + %lp = landingpad { i8*, i32 } personality i8* null cleanup
|
| + ret i32 999
|
| +}
|
| +; CHECK: define i32 @shared_landingpad
|
| +; CHECK: br i1 %invoke_sj_is_zero, label %invoke_do_call, label %lpad
|
| +; CHECK: br i1 %invoke_sj_is_zero2, label %invoke_do_call3, label %lpad
|
| +
|
| +
|
| +; Check that the pass can handle a landingpad appearing before an invoke.
|
| +define i32 @landingpad_before_invoke() {
|
| + ret i32 123
|
| +
|
| +dead_block:
|
| + %lp = landingpad i32 personality i8* null cleanup
|
| + ret i32 %lp
|
| +}
|
| +; CHECK: define i32 @landingpad_before_invoke
|
| +; CHECK: %lp = load i32* %landingpad_ptr
|
| +
|
| +
|
| +; Test the expansion of the "resume" instruction.
|
| +define void @test_resume({ i8*, i32 } %arg) {
|
| + resume { i8*, i32 } %arg
|
| +}
|
| +; CHECK: define void @test_resume
|
| +; CHECK-NEXT: %resume_exc = extractvalue { i8*, i32 } %arg, 0
|
| +; CHECK-NEXT: %resume_cast = bitcast i8* %resume_exc to i32*
|
| +; CHECK-NEXT: call void @__pnacl_eh_resume(i32* %resume_cast)
|
| +; CHECK-NEXT: unreachable
|
| +
|
| +
|
| +; Check that call attributes are preserved.
|
| +define i32 @call_attrs(i64 %arg) {
|
| + %result = invoke fastcc i32 @external_func(i64 inreg %arg) noreturn
|
| + to label %cont unwind label %lpad
|
| +cont:
|
| + ret i32 %result
|
| +lpad:
|
| + %lp = landingpad { i8*, i32 } personality i8* null cleanup
|
| + ret i32 999
|
| +}
|
| +; CHECK: define i32 @call_attrs
|
| +; CHECK: %result = call fastcc i32 @external_func(i64 inreg %arg) [[NORETURN:#[0-9]+]]
|
| +
|
| +
|
| +; Check that any PHI nodes referring to the result of an "invoke" are
|
| +; updated to refer to the correct basic block.
|
| +define i32 @invoke_with_phi_nodes(i64 %arg) {
|
| +entry:
|
| + %result = invoke i32 @external_func(i64 %arg)
|
| + to label %cont unwind label %lpad
|
| +cont:
|
| + %cont_phi = phi i32 [ 100, %entry ]
|
| + ret i32 %cont_phi
|
| +lpad:
|
| + %lpad_phi = phi i32 [ 200, %entry ]
|
| + %lp = landingpad { i8*, i32 } personality i8* null cleanup
|
| + ret i32 %lpad_phi
|
| +}
|
| +; CHECK: define i32 @invoke_with_phi_nodes
|
| +; CHECK: %result = call i32 @external_func(i64 %arg)
|
| +; CHECK: cont:
|
| +; CHECK-NEXT: %cont_phi = phi i32 [ 100, %invoke_do_call ]
|
| +; CHECK-NEXT: ret i32 %cont_phi
|
| +; CHECK: lpad:
|
| +; CHECK-NEXT: %lpad_phi = phi i32 [ 200, %entry ]
|
| +; CHECK: ret i32 %lpad_phi
|
| +
|
| +
|
| +; CHECK: attributes [[NORETURN]] = { noreturn }
|
|
|