| Index: test/Transforms/NaCl/pnacl-sjlj-eh-bug.ll
|
| diff --git a/test/Transforms/NaCl/pnacl-sjlj-eh-bug.ll b/test/Transforms/NaCl/pnacl-sjlj-eh-bug.ll
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e0796881285cc717c710b3ff4ed7024e831c3b43
|
| --- /dev/null
|
| +++ b/test/Transforms/NaCl/pnacl-sjlj-eh-bug.ll
|
| @@ -0,0 +1,81 @@
|
| +; RUN: opt %s -pnacl-sjlj-eh -O2 -S | FileCheck %s
|
| +
|
| +; datalayout must be specified for GVN to work.
|
| +target datalayout = "p:32:32:32"
|
| +
|
| +; This must be declared for expanding "invoke" and "landingpad" instructions.
|
| +@__pnacl_eh_stack = external thread_local global i8*
|
| +
|
| +declare i1 @might_be_setjmp()
|
| +declare void @external_func(i32* %ptr)
|
| +declare void @var_is_nonzero()
|
| +
|
| +
|
| +; Test for a bug in which PNaClSjLjEH would transform
|
| +; @invoke_optimize_test() such that the call to @var_is_nonzero()
|
| +; could get optimized away by a later optimization pass. This
|
| +; happened because PNaClSjLjEH generated code similar to
|
| +; @branch_optimize_test() below.
|
| +
|
| +define void @invoke_optimize_test() {
|
| + %var = alloca i32
|
| + store i32 0, i32* %var
|
| +
|
| + invoke void @external_func(i32* %var)
|
| + to label %exit unwind label %lpad
|
| +
|
| +lpad:
|
| + landingpad i32 personality i8* null
|
| + catch i8* null
|
| + %value = load i32* %var
|
| + %is_zero = icmp eq i32 %value, 0
|
| + br i1 %is_zero, label %exit, label %do_call
|
| +
|
| +do_call:
|
| + call void @var_is_nonzero()
|
| + ret void
|
| +
|
| +exit:
|
| + ret void
|
| +}
|
| +; CHECK: define void @invoke_optimize_test()
|
| +; CHECK: @var_is_nonzero()
|
| +
|
| +
|
| +; In @branch_optimize_test(), the optimizer can optimize away the call
|
| +; to @var_is_nonzero(), because it can assume that %var always
|
| +; contains 0 on the "iffalse" branch.
|
| +;
|
| +; The passes "-gvn -instcombine" are enough to do this.
|
| +;
|
| +; The optimizer can do this regardless of whether @might_be_setjmp()
|
| +; is setjmp() or a normal function. It doesn't need to know that
|
| +; @might_be_setjmp() might return twice, because storing to %var
|
| +; between setjmp() and longjmp() leaves %var pointing to an undefined
|
| +; value.
|
| +
|
| +define void @branch_optimize_test() {
|
| + %var = alloca i32
|
| + store i32 0, i32* %var
|
| +
|
| + %cond = call i1 @might_be_setjmp() returns_twice
|
| + br i1 %cond, label %iftrue, label %iffalse
|
| +
|
| +iftrue:
|
| + call void @external_func(i32* %var)
|
| + ret void
|
| +
|
| +iffalse:
|
| + %value = load i32* %var
|
| + %is_zero = icmp eq i32 %value, 0
|
| + br i1 %is_zero, label %exit, label %do_call
|
| +
|
| +do_call:
|
| + call void @var_is_nonzero()
|
| + ret void
|
| +
|
| +exit:
|
| + ret void
|
| +}
|
| +; CHECK: define void @branch_optimize_test()
|
| +; CHECK-NOT: @var_is_nonzero
|
|
|