1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
2; RUN: opt < %s -basic-aa -globals-aa -memcpyopt -S -verify-memoryssa | FileCheck %s
3
4target datalayout = "e"
5
6declare void @foo(i8*)
7declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture, i32, i1) nounwind
8declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
9declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
10
11; Check that the transformation isn't applied if the called function can
12; capture the pointer argument (i.e. the nocapture attribute isn't present)
13define void @test() {
14; CHECK-LABEL: define {{[^@]+}}@test() {
15; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
16; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
17; CHECK-NEXT:    call void @foo(i8* [[PTR2]])
18; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[PTR1]], i8* [[PTR2]], i32 1, i1 false)
19; CHECK-NEXT:    call void @foo(i8* [[PTR1]])
20; CHECK-NEXT:    ret void
21;
22  %ptr1 = alloca i8
23  %ptr2 = alloca i8
24  call void @foo(i8* %ptr2)
25  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %ptr1, i8* %ptr2, i32 1, i1 false)
26  call void @foo(i8* %ptr1)
27  ret void
28}
29
30; Same as previous test, but with a bitcasted argument.
31; TODO: Call slot optimization should not be applied here.
32define void @test_bitcast() {
33; CHECK-LABEL: define {{[^@]+}}@test_bitcast() {
34; CHECK-NEXT:    [[PTR1:%.*]] = alloca [2 x i8], align 1
35; CHECK-NEXT:    [[PTR2:%.*]] = alloca [2 x i8], align 1
36; CHECK-NEXT:    [[PTR1_CAST:%.*]] = bitcast [2 x i8]* [[PTR1]] to i8*
37; CHECK-NEXT:    [[PTR2_CAST:%.*]] = bitcast [2 x i8]* [[PTR2]] to i8*
38; CHECK-NEXT:    [[PTR11:%.*]] = bitcast [2 x i8]* [[PTR1]] to i8*
39; CHECK-NEXT:    call void @foo(i8* [[PTR11]])
40; CHECK-NEXT:    call void @foo(i8* [[PTR1_CAST]])
41; CHECK-NEXT:    ret void
42;
43  %ptr1 = alloca [2 x i8]
44  %ptr2 = alloca [2 x i8]
45  %ptr1.cast = bitcast [2 x i8]* %ptr1 to i8*
46  %ptr2.cast = bitcast [2 x i8]* %ptr2 to i8*
47  call void @foo(i8* %ptr2.cast)
48  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %ptr1.cast, i8* %ptr2.cast, i32 2, i1 false)
49  call void @foo(i8* %ptr1.cast)
50  ret void
51}
52
53; Lifetime of %ptr2 ends before the potential use of the capture in the second
54; call.
55define void @test_lifetime_end() {
56; CHECK-LABEL: define {{[^@]+}}@test_lifetime_end() {
57; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
58; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
59; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 1, i8* [[PTR2]])
60; CHECK-NEXT:    call void @foo(i8* [[PTR2]])
61; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[PTR1]], i8* [[PTR2]], i32 1, i1 false)
62; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 1, i8* [[PTR2]])
63; CHECK-NEXT:    call void @foo(i8* [[PTR1]])
64; CHECK-NEXT:    ret void
65;
66  %ptr1 = alloca i8
67  %ptr2 = alloca i8
68  call void @llvm.lifetime.start.p0i8(i64 1, i8* %ptr2)
69  call void @foo(i8* %ptr2)
70  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %ptr1, i8* %ptr2, i32 1, i1 false)
71  call void @llvm.lifetime.end.p0i8(i64 1, i8* %ptr2)
72  call void @foo(i8* %ptr1)
73  ret void
74}
75
76; Lifetime of %ptr2 does not end, because of size mismatch.
77define void @test_lifetime_not_end() {
78; CHECK-LABEL: define {{[^@]+}}@test_lifetime_not_end() {
79; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
80; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
81; CHECK-NEXT:    call void @llvm.lifetime.start.p0i8(i64 1, i8* [[PTR2]])
82; CHECK-NEXT:    call void @foo(i8* [[PTR2]])
83; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[PTR1]], i8* [[PTR2]], i32 1, i1 false)
84; CHECK-NEXT:    call void @llvm.lifetime.end.p0i8(i64 0, i8* [[PTR2]])
85; CHECK-NEXT:    call void @foo(i8* [[PTR1]])
86; CHECK-NEXT:    ret void
87;
88  %ptr1 = alloca i8
89  %ptr2 = alloca i8
90  call void @llvm.lifetime.start.p0i8(i64 1, i8* %ptr2)
91  call void @foo(i8* %ptr2)
92  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %ptr1, i8* %ptr2, i32 1, i1 false)
93  call void @llvm.lifetime.end.p0i8(i64 0, i8* %ptr2)
94  call void @foo(i8* %ptr1)
95  ret void
96}
97
98; Lifetime of %ptr2 ends before any potential use of the capture because we
99; return from the function.
100define void @test_function_end() {
101; CHECK-LABEL: define {{[^@]+}}@test_function_end() {
102; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
103; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
104; CHECK-NEXT:    call void @foo(i8* [[PTR2]])
105; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[PTR1]], i8* [[PTR2]], i32 1, i1 false)
106; CHECK-NEXT:    ret void
107;
108  %ptr1 = alloca i8
109  %ptr2 = alloca i8
110  call void @foo(i8* %ptr2)
111  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %ptr1, i8* %ptr2, i32 1, i1 false)
112  ret void
113}
114
115; A potential use of the capture occurs in a later block, can't be optimized.
116define void @test_terminator() {
117; CHECK-LABEL: define {{[^@]+}}@test_terminator() {
118; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
119; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
120; CHECK-NEXT:    call void @foo(i8* [[PTR2]])
121; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[PTR1]], i8* [[PTR2]], i32 1, i1 false)
122; CHECK-NEXT:    br label [[NEXT:%.*]]
123; CHECK:       next:
124; CHECK-NEXT:    call void @foo(i8* [[PTR1]])
125; CHECK-NEXT:    ret void
126;
127  %ptr1 = alloca i8
128  %ptr2 = alloca i8
129  call void @foo(i8* %ptr2)
130  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %ptr1, i8* %ptr2, i32 1, i1 false)
131  br label %next
132
133next:
134  call void @foo(i8* %ptr1)
135  ret void
136}
137
138; This case can be optimized, but would require a scan across multiple blocks
139; and is currently not performed.
140define void @test_terminator2() {
141; CHECK-LABEL: define {{[^@]+}}@test_terminator2() {
142; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
143; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
144; CHECK-NEXT:    call void @foo(i8* [[PTR2]])
145; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[PTR1]], i8* [[PTR2]], i32 1, i1 false)
146; CHECK-NEXT:    br label [[NEXT:%.*]]
147; CHECK:       next:
148; CHECK-NEXT:    ret void
149;
150  %ptr1 = alloca i8
151  %ptr2 = alloca i8
152  call void @foo(i8* %ptr2)
153  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %ptr1, i8* %ptr2, i32 1, i1 false)
154  br label %next
155
156next:
157  ret void
158}
159
160declare void @capture(i8*)
161
162; This case should not be optimized, because dest is captured before the call.
163define void @test_dest_captured_before_alloca() {
164; CHECK-LABEL: define {{[^@]+}}@test_dest_captured_before_alloca() {
165; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
166; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
167; CHECK-NEXT:    call void @capture(i8* [[PTR1]])
168; CHECK-NEXT:    call void @foo(i8* [[PTR2]]) #[[ATTR2:[0-9]+]]
169; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[PTR1]], i8* [[PTR2]], i32 1, i1 false)
170; CHECK-NEXT:    ret void
171;
172  %ptr1 = alloca i8
173  %ptr2 = alloca i8
174  call void @capture(i8* %ptr1)
175  call void @foo(i8* %ptr2) argmemonly
176  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %ptr1, i8* %ptr2, i32 1, i1 false)
177  ret void
178}
179
180
181@g = internal global i8 0
182
183; This case should not be optimized, because @g is captured before the call
184; (being a global) and @icmp_g might depend on its identity.
185define void @test_dest_captured_before_global() {
186; CHECK-LABEL: define {{[^@]+}}@test_dest_captured_before_global() {
187; CHECK-NEXT:    [[PTR:%.*]] = alloca i8, align 1
188; CHECK-NEXT:    call void @icmp_g(i8* [[PTR]])
189; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* @g, i8* [[PTR]], i32 1, i1 false)
190; CHECK-NEXT:    ret void
191;
192  %ptr = alloca i8
193  call void @icmp_g(i8* %ptr)
194  call void @llvm.memcpy.p0i8.p0i8.i32(i8* @g, i8* %ptr, i32 1, i1 false)
195  ret void
196}
197
198define void @icmp_g(i8* %p) {
199; CHECK-LABEL: define {{[^@]+}}@icmp_g
200; CHECK-SAME: (i8* [[P:%.*]]) {
201; CHECK-NEXT:    [[C:%.*]] = icmp eq i8* [[P]], @g
202; CHECK-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
203; CHECK:       if:
204; CHECK-NEXT:    store i8 1, i8* [[P]], align 1
205; CHECK-NEXT:    ret void
206; CHECK:       else:
207; CHECK-NEXT:    store i8 2, i8* [[P]], align 1
208; CHECK-NEXT:    ret void
209;
210  %c = icmp eq i8* %p, @g
211  br i1 %c, label %if, label %else
212
213if:
214  store i8 1, i8* %p
215  ret void
216
217else:
218  store i8 2, i8* %p
219  ret void
220}
221