xref: /llvm-project/llvm/test/Transforms/Inline/byval-tail-call.ll (revision 151602c7a9935558ca671b35359989b261045db0)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -aa-pipeline=basic-aa -passes='function(tailcallelim),cgscc(inline,function(instcombine,dse))' -S | FileCheck %s
3; PR7272
4
5; Calls that capture byval parameters cannot be marked as tail calls. Other
6; tails that don't capture byval parameters can still be tail calls.
7
8target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
9target triple = "i386-pc-linux-gnu"
10
11declare void @ext(ptr)
12
13define void @bar(ptr byval(i32) %x) {
14; CHECK-LABEL: @bar(
15; CHECK-NEXT:    call void @ext(ptr nonnull [[X:%.*]])
16; CHECK-NEXT:    ret void
17;
18  call void @ext(ptr %x)
19  ret void
20}
21
22define void @foo(ptr %x) {
23; CHECK-LABEL: @foo(
24; CHECK-NEXT:    [[X1:%.*]] = alloca i32, align 4
25; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[X1]])
26; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[X:%.*]], align 1
27; CHECK-NEXT:    store i32 [[TMP2]], ptr [[X1]], align 4
28; CHECK-NEXT:    call void @ext(ptr nonnull [[X1]])
29; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[X1]])
30; CHECK-NEXT:    ret void
31;
32  call void @bar(ptr byval(i32) %x)
33  ret void
34}
35
36define internal void @qux(ptr byval(i32) %x) {
37  call void @ext(ptr %x)
38  tail call void @ext(ptr null)
39  ret void
40}
41
42define void @frob(ptr %x) {
43; CHECK-LABEL: @frob(
44; CHECK-NEXT:    [[X1:%.*]] = alloca i32, align 4
45; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[X1]])
46; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[X:%.*]], align 1
47; CHECK-NEXT:    store i32 [[TMP2]], ptr [[X1]], align 4
48; CHECK-NEXT:    call void @ext(ptr nonnull [[X1]])
49; CHECK-NEXT:    tail call void @ext(ptr null)
50; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[X1]])
51; CHECK-NEXT:    ret void
52;
53  tail call void @qux(ptr byval(i32) %x)
54  ret void
55}
56
57; A byval parameter passed into a function which is passed out as byval does
58; not block the call from being marked as tail.
59
60declare void @ext2(ptr byval(i32))
61
62define void @bar2(ptr byval(i32) %x) {
63; CHECK-LABEL: @bar2(
64; CHECK-NEXT:    tail call void @ext2(ptr nonnull byval(i32) [[X:%.*]])
65; CHECK-NEXT:    ret void
66;
67  call void @ext2(ptr byval(i32) %x)
68  ret void
69}
70
71define void @foobar(ptr %x) {
72; CHECK-LABEL: @foobar(
73; CHECK-NEXT:    [[X1:%.*]] = alloca i32, align 4
74; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[X1]])
75; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[X:%.*]], align 1
76; CHECK-NEXT:    store i32 [[TMP2]], ptr [[X1]], align 4
77; CHECK-NEXT:    tail call void @ext2(ptr nonnull byval(i32) [[X1]])
78; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[X1]])
79; CHECK-NEXT:    ret void
80;
81  tail call void @bar2(ptr byval(i32) %x)
82  ret void
83}
84
85define void @barfoo() {
86; CHECK-LABEL: @barfoo(
87; CHECK-NEXT:    [[X1:%.*]] = alloca i32, align 4
88; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[X1]])
89; CHECK-NEXT:    tail call void @ext2(ptr nonnull byval(i32) [[X1]])
90; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[X1]])
91; CHECK-NEXT:    ret void
92;
93  %x = alloca i32
94  tail call void @bar2(ptr byval(i32) %x)
95  ret void
96}
97