diff options
author | John McCall <rjmccall@apple.com> | 2011-05-27 18:34:38 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-05-27 18:34:38 +0000 |
commit | a3de16bc8f36638d5444e3e7b0112998af54f826 (patch) | |
tree | 347a748b21b29f74599252689782c948b28362ea /test/Transforms/Inline | |
parent | 11f6cc96bf794c7ede7bf8e24805f4187b24c549 (diff) |
Fix the inliner to maintain the current de facto invoke semantics:
- the selector for the landing pad must provide all available information
about the handlers, filters, and cleanups within that landing pad
- calls to _Unwind_Resume must be converted to branches to the enclosing
lpad so as to avoid re-entering the unwinder when the lpad claimed it
was going to handle the exception in some way
This is quite specific to libUnwind-based unwinding. In an effort to not
interfere too badly with other unwinders, and with existing hacks in frontends,
this only triggers on _Unwind_Resume (not _Unwind_Resume_or_Rethrow) and does
nothing with selectors if it cannot find a selector call for either lpad.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@132200 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Transforms/Inline')
-rw-r--r-- | test/Transforms/Inline/inline_invoke.ll | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/test/Transforms/Inline/inline_invoke.ll b/test/Transforms/Inline/inline_invoke.ll new file mode 100644 index 0000000000..bd955e3bc9 --- /dev/null +++ b/test/Transforms/Inline/inline_invoke.ll @@ -0,0 +1,103 @@ +; RUN: opt < %s -inline -S | FileCheck %s + +; Test that the inliner correctly handles inlining into invoke sites +; by appending selectors and forwarding _Unwind_Resume directly to the +; enclosing landing pad. + +%struct.A = type { i8 } + +@_ZTIi = external constant i8* + +declare void @_ZN1AC1Ev(%struct.A*) + +declare void @_ZN1AD1Ev(%struct.A*) + +declare i8* @llvm.eh.exception() nounwind readonly + +declare i32 @llvm.eh.selector(i8*, i8*, ...) nounwind + +declare i32 @llvm.eh.typeid.for(i8*) nounwind + +declare void @_Unwind_Resume(i8*) + +declare i32 @__gxx_personality_v0(...) + +declare i8* @__cxa_begin_catch(i8*) + +declare void @__cxa_end_catch() + +declare void @_ZSt9terminatev() + +define internal void @test0_in() alwaysinline uwtable ssp { +entry: + %a = alloca %struct.A, align 1 + %b = alloca %struct.A, align 1 + call void @_ZN1AC1Ev(%struct.A* %a) + invoke void @_ZN1AC1Ev(%struct.A* %b) + to label %invoke.cont unwind label %lpad + +invoke.cont: + invoke void @_ZN1AD1Ev(%struct.A* %b) + to label %invoke.cont1 unwind label %lpad + +invoke.cont1: + call void @_ZN1AD1Ev(%struct.A* %a) + ret void + +lpad: + %exn = call i8* @llvm.eh.exception() nounwind + %eh.selector = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exn, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 0) nounwind + invoke void @_ZN1AD1Ev(%struct.A* %a) + to label %invoke.cont2 unwind label %terminate.lpad + +invoke.cont2: + call void @_Unwind_Resume(i8* %exn) noreturn + unreachable + +terminate.lpad: + %exn3 = call i8* @llvm.eh.exception() nounwind + %eh.selector4 = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exn3, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null) nounwind + call void @_ZSt9terminatev() noreturn nounwind + unreachable +} + +define void @test0_out() uwtable ssp { +entry: + invoke void @test0_in() + to label %ret unwind label %lpad + +ret: + ret void + +lpad: ; preds = %entry + %exn = call i8* @llvm.eh.exception() nounwind + %eh.selector = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* %exn, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*)) nounwind + %0 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) nounwind + %1 = icmp eq i32 %eh.selector, %0 + br i1 %1, label %catch, label %eh.resume + +catch: + %ignored = call i8* @__cxa_begin_catch(i8* %exn) nounwind + call void @__cxa_end_catch() nounwind + br label %ret + +eh.resume: + call void @_Unwind_Resume(i8* %exn) noreturn + unreachable +} + +; CHECK: define void @test0_out() +; CHECK: [[A:%.*]] = alloca %struct.A, +; CHECK: [[B:%.*]] = alloca %struct.A, +; CHECK: invoke void @_ZN1AC1Ev(%struct.A* [[A]]) +; CHECK: invoke void @_ZN1AC1Ev(%struct.A* [[B]]) +; CHECK: invoke void @_ZN1AD1Ev(%struct.A* [[B]]) +; CHECK: invoke void @_ZN1AD1Ev(%struct.A* [[A]]) +; CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{%.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 0, i8* bitcast (i8** @_ZTIi to i8*)) +; CHECK-NEXT: invoke void @_ZN1AD1Ev(%struct.A* [[A]]) +; CHECK-NEXT: to label %[[LBL:[^\s]+]] unwind +; CHECK: [[LBL]]: +; CHECK-NEXT: br label %[[LPAD:[^\s]+]] +; CHECK: [[LPAD]]: +; CHECK-NEXT: call i8* @llvm.eh.exception() +; CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{%.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*)) |