diff options
Diffstat (limited to 'test/Transforms/Inline/inline-tail.ll')
-rw-r--r-- | test/Transforms/Inline/inline-tail.ll | 185 |
1 files changed, 176 insertions, 9 deletions
diff --git a/test/Transforms/Inline/inline-tail.ll b/test/Transforms/Inline/inline-tail.ll index 8bb059d..b40328e 100644 --- a/test/Transforms/Inline/inline-tail.ll +++ b/test/Transforms/Inline/inline-tail.ll @@ -1,15 +1,182 @@ -; RUN: opt < %s -inline -S | not grep tail +; RUN: opt < %s -inline -S | FileCheck %s -declare void @bar(i32*) +; We have to apply the less restrictive TailCallKind of the call site being +; inlined and any call sites cloned into the caller. -define internal void @foo(i32* %P) { - tail call void @bar( i32* %P ) - ret void +; No tail marker after inlining, since test_capture_c captures an alloca. +; CHECK: define void @test_capture_a( +; CHECK-NOT: tail +; CHECK: call void @test_capture_c( + +declare void @test_capture_c(i32*) +define internal void @test_capture_b(i32* %P) { + tail call void @test_capture_c(i32* %P) + ret void +} +define void @test_capture_a() { + %A = alloca i32 ; captured by test_capture_b + call void @test_capture_b(i32* %A) + ret void +} + +; No musttail marker after inlining, since the prototypes don't match. +; CHECK: define void @test_proto_mismatch_a( +; CHECK-NOT: musttail +; CHECK: call void @test_proto_mismatch_c( + +declare void @test_proto_mismatch_c(i32*) +define internal void @test_proto_mismatch_b(i32* %p) { + musttail call void @test_proto_mismatch_c(i32* %p) + ret void +} +define void @test_proto_mismatch_a() { + call void @test_proto_mismatch_b(i32* null) + ret void +} + +; After inlining through a musttail call site, we need to keep musttail markers +; to prevent unbounded stack growth. +; CHECK: define void @test_musttail_basic_a( +; CHECK: musttail call void @test_musttail_basic_c( + +declare void @test_musttail_basic_c(i32* %p) +define internal void @test_musttail_basic_b(i32* %p) { + musttail call void @test_musttail_basic_c(i32* %p) + ret void +} +define void @test_musttail_basic_a(i32* %p) { + musttail call void @test_musttail_basic_b(i32* %p) + ret void +} + +; Don't insert lifetime end markers here, the lifetime is trivially over due +; the return. +; CHECK: define void @test_byval_a( +; CHECK: musttail call void @test_byval_c( +; CHECK-NEXT: ret void + +declare void @test_byval_c(i32* byval %p) +define internal void @test_byval_b(i32* byval %p) { + musttail call void @test_byval_c(i32* byval %p) + ret void +} +define void @test_byval_a(i32* byval %p) { + musttail call void @test_byval_b(i32* byval %p) + ret void } -define void @caller() { - %A = alloca i32 ; <i32*> [#uses=1] - call void @foo( i32* %A ) - ret void +; Don't insert a stack restore, we're about to return. +; CHECK: define void @test_dynalloca_a( +; CHECK: call i8* @llvm.stacksave( +; CHECK: alloca i8, i32 %n +; CHECK: musttail call void @test_dynalloca_c( +; CHECK-NEXT: ret void + +declare void @escape(i8* %buf) +declare void @test_dynalloca_c(i32* byval %p, i32 %n) +define internal void @test_dynalloca_b(i32* byval %p, i32 %n) alwaysinline { + %buf = alloca i8, i32 %n ; dynamic alloca + call void @escape(i8* %buf) ; escape it + musttail call void @test_dynalloca_c(i32* byval %p, i32 %n) + ret void +} +define void @test_dynalloca_a(i32* byval %p, i32 %n) { + musttail call void @test_dynalloca_b(i32* byval %p, i32 %n) + ret void } +; We can't merge the returns. +; CHECK: define void @test_multiret_a( +; CHECK: musttail call void @test_multiret_c( +; CHECK-NEXT: ret void +; CHECK: musttail call void @test_multiret_d( +; CHECK-NEXT: ret void + +declare void @test_multiret_c(i1 zeroext %b) +declare void @test_multiret_d(i1 zeroext %b) +define internal void @test_multiret_b(i1 zeroext %b) { + br i1 %b, label %c, label %d +c: + musttail call void @test_multiret_c(i1 zeroext %b) + ret void +d: + musttail call void @test_multiret_d(i1 zeroext %b) + ret void +} +define void @test_multiret_a(i1 zeroext %b) { + musttail call void @test_multiret_b(i1 zeroext %b) + ret void +} + +; We have to avoid bitcast chains. +; CHECK: define i32* @test_retptr_a( +; CHECK: musttail call i8* @test_retptr_c( +; CHECK-NEXT: bitcast i8* {{.*}} to i32* +; CHECK-NEXT: ret i32* + +declare i8* @test_retptr_c() +define internal i16* @test_retptr_b() { + %rv = musttail call i8* @test_retptr_c() + %v = bitcast i8* %rv to i16* + ret i16* %v +} +define i32* @test_retptr_a() { + %rv = musttail call i16* @test_retptr_b() + %v = bitcast i16* %rv to i32* + ret i32* %v +} + +; Combine the last two cases: multiple returns with pointer bitcasts. +; CHECK: define i32* @test_multiptrret_a( +; CHECK: musttail call i8* @test_multiptrret_c( +; CHECK-NEXT: bitcast i8* {{.*}} to i32* +; CHECK-NEXT: ret i32* +; CHECK: musttail call i8* @test_multiptrret_d( +; CHECK-NEXT: bitcast i8* {{.*}} to i32* +; CHECK-NEXT: ret i32* + +declare i8* @test_multiptrret_c(i1 zeroext %b) +declare i8* @test_multiptrret_d(i1 zeroext %b) +define internal i16* @test_multiptrret_b(i1 zeroext %b) { + br i1 %b, label %c, label %d +c: + %c_rv = musttail call i8* @test_multiptrret_c(i1 zeroext %b) + %c_v = bitcast i8* %c_rv to i16* + ret i16* %c_v +d: + %d_rv = musttail call i8* @test_multiptrret_d(i1 zeroext %b) + %d_v = bitcast i8* %d_rv to i16* + ret i16* %d_v +} +define i32* @test_multiptrret_a(i1 zeroext %b) { + %rv = musttail call i16* @test_multiptrret_b(i1 zeroext %b) + %v = bitcast i16* %rv to i32* + ret i32* %v +} + +; Inline a musttail call site which contains a normal return and a musttail call. +; CHECK: define i32 @test_mixedret_a( +; CHECK: br i1 %b +; CHECK: musttail call i32 @test_mixedret_c( +; CHECK-NEXT: ret i32 +; CHECK: call i32 @test_mixedret_d(i1 zeroext %b) +; CHECK: add i32 1, +; CHECK-NOT: br +; CHECK: ret i32 + +declare i32 @test_mixedret_c(i1 zeroext %b) +declare i32 @test_mixedret_d(i1 zeroext %b) +define internal i32 @test_mixedret_b(i1 zeroext %b) { + br i1 %b, label %c, label %d +c: + %c_rv = musttail call i32 @test_mixedret_c(i1 zeroext %b) + ret i32 %c_rv +d: + %d_rv = call i32 @test_mixedret_d(i1 zeroext %b) + %d_rv1 = add i32 1, %d_rv + ret i32 %d_rv1 +} +define i32 @test_mixedret_a(i1 zeroext %b) { + %rv = musttail call i32 @test_mixedret_b(i1 zeroext %b) + ret i32 %rv +} |