1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
2 ; RUN: opt < %s -passes=memcpyopt -verify-memoryssa -S | FileCheck %s
4 %struct.Foo = type { i32, i32, i32 }
6 declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)
7 declare void @llvm.memcpy.p1.p0.i64(ptr addrspace(1) noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)
8 declare void @llvm.memcpy.p2.p1.i64(ptr addrspace(2) noalias nocapture writeonly, ptr addrspace(1) noalias nocapture readonly, i64, i1 immarg)
9 declare void @llvm.memmove.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1 immarg)
10 declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)
12 declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
13 declare void @llvm.lifetime.end.p0(i64, ptr nocapture)
14 declare void @llvm.lifetime.start.p1(i64, ptr addrspace(1) nocapture)
15 declare void @llvm.lifetime.end.p1(i64, ptr addrspace(1) nocapture)
16 declare void @llvm.lifetime.start.p2(i64, ptr addrspace(2) nocapture)
17 declare void @llvm.lifetime.end.p2(i64, ptr addrspace(2) nocapture)
19 declare i32 @use_nocapture(ptr nocapture)
20 declare i32 @use_maycapture(ptr noundef)
21 declare i32 @use_readonly(ptr readonly)
22 declare i32 @use_writeonly(ptr noundef) memory(write)
24 define void @basic_memcpy() {
25 ; CHECK-LABEL: define void @basic_memcpy() {
26 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
27 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
28 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
29 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
30 ; CHECK-NEXT: ret void
32 %src = alloca %struct.Foo, align 4
33 %dest = alloca %struct.Foo, align 4
34 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
35 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
36 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
37 %1 = call i32 @use_nocapture(ptr nocapture %src)
39 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
41 %2 = call i32 @use_nocapture(ptr nocapture %dest)
43 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
44 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
48 define i32 @use_not_dominated_by_src_alloca() {
49 ; CHECK-LABEL: define i32 @use_not_dominated_by_src_alloca() {
50 ; CHECK-NEXT: [[SRC:%.*]] = alloca i8, align 4
51 ; CHECK-NEXT: [[DEST_GEP:%.*]] = getelementptr i64, ptr [[SRC]], i64 -1
52 ; CHECK-NEXT: [[DEST_USE:%.*]] = load i8, ptr [[DEST_GEP]], align 1
53 ; CHECK-NEXT: ret i32 0
55 %dest = alloca i1, align 1
56 ; Replacing the use of dest with src causes no domination uses.
57 %dest.gep = getelementptr i64, ptr %dest, i64 -1
58 %dest.use = load i8, ptr %dest.gep, align 1
59 %src = alloca i8, align 4
60 %src.val = load i1, ptr %src, align 4
62 store i1 %src.val, ptr %dest, align 1
67 define void @basic_memmove() {
68 ; CHECK-LABEL: define void @basic_memmove() {
69 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
70 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
71 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
72 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
73 ; CHECK-NEXT: ret void
75 %src = alloca %struct.Foo, align 4
76 %dest = alloca %struct.Foo, align 4
77 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
78 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
79 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
80 %1 = call i32 @use_nocapture(ptr nocapture %src)
82 call void @llvm.memmove.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
84 %2 = call i32 @use_nocapture(ptr nocapture %dest)
86 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
87 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
91 ; Tests that the optimization succeeds with a load/store pair.
92 define void @load_store() {
93 ; CHECK-LABEL: define void @load_store() {
94 ; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4
95 ; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4
96 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
97 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
98 ; CHECK-NEXT: ret void
100 %src = alloca i32, align 4
101 %dest = alloca i32, align 4
102 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %src)
103 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %dest)
104 store i32 42, ptr %src
105 %1 = call i32 @use_nocapture(ptr nocapture %src)
107 %src.val = load i32, ptr %src
108 store i32 %src.val, ptr %dest
110 %2 = call i32 @use_nocapture(ptr nocapture %dest)
111 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %src)
112 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %dest)
116 ; Test scalable vectors.
117 define void @load_store_scalable(<vscale x 4 x i32> %x) {
118 ; CHECK-LABEL: define void @load_store_scalable
119 ; CHECK-SAME: (<vscale x 4 x i32> [[X:%.*]]) {
120 ; CHECK-NEXT: [[SRC:%.*]] = alloca <vscale x 4 x i32>, align 16
121 ; CHECK-NEXT: store <vscale x 4 x i32> [[X]], ptr [[SRC]], align 16
122 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
123 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
124 ; CHECK-NEXT: ret void
126 %src = alloca <vscale x 4 x i32>
127 %dest = alloca <vscale x 4 x i32>
128 call void @llvm.lifetime.start.p0(i64 -1, ptr nocapture %src)
129 call void @llvm.lifetime.start.p0(i64 -1, ptr nocapture %dest)
130 store <vscale x 4 x i32> %x, ptr %src
131 %1 = call i32 @use_nocapture(ptr nocapture %src)
133 %src.val = load <vscale x 4 x i32>, ptr %src
134 store <vscale x 4 x i32> %src.val, ptr %dest
136 %2 = call i32 @use_nocapture(ptr nocapture %dest)
138 call void @llvm.lifetime.end.p0(i64 -1, ptr nocapture %src)
139 call void @llvm.lifetime.end.p0(i64 -1, ptr nocapture %dest)
143 ; Tests that merging two allocas shouldn't be more poisonous, smaller aligned src is valid.
144 define void @align_up() {
145 ; CHECK-LABEL: define void @align_up() {
146 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8
147 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
148 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
149 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
150 ; CHECK-NEXT: ret void
152 %src = alloca %struct.Foo, align 4
153 %dest = alloca %struct.Foo, align 8
154 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
155 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
156 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
157 %1 = call i32 @use_nocapture(ptr nocapture %src)
159 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
161 %2 = call i32 @use_nocapture(ptr nocapture %dest)
162 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
163 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
167 ; Tests that we correctly remove extra lifetime intrinsics when performing the
169 define void @remove_extra_lifetime_intrinsics() {
170 ; CHECK-LABEL: define void @remove_extra_lifetime_intrinsics() {
171 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
172 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
173 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
174 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
175 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
176 ; CHECK-NEXT: ret void
178 %src = alloca %struct.Foo, align 4
179 %dest = alloca %struct.Foo, align 4
180 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
181 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
182 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
183 %1 = call i32 @use_nocapture(ptr nocapture %src)
185 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
187 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
188 %2 = call i32 @use_nocapture(ptr nocapture %dest)
189 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
190 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
191 %3 = call i32 @use_nocapture(ptr nocapture %dest)
192 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
193 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
194 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
198 ; Tests that we won't insert lifetime markers if they don't exist originally.
199 define void @no_lifetime() {
200 ; CHECK-LABEL: define void @no_lifetime() {
201 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
202 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
203 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
204 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
205 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
206 ; CHECK-NEXT: ret void
208 %src = alloca %struct.Foo, align 4
209 %dest = alloca %struct.Foo, align 4
210 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
211 %1 = call i32 @use_nocapture(ptr nocapture %src)
213 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
215 %2 = call i32 @use_nocapture(ptr nocapture %dest)
216 %3 = call i32 @use_nocapture(ptr nocapture %dest)
220 ; Tests that aliasing src or dest but no modification desn't prevent transformations.
221 define void @alias_no_mod() {
222 ; CHECK-LABEL: define void @alias_no_mod() {
223 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
224 ; CHECK-NEXT: [[DEST_ALIAS:%.*]] = getelementptr [[STRUCT_FOO]], ptr [[SRC]], i32 0, i32 0
225 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
226 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
227 ; CHECK-NEXT: [[SRC_ALIAS:%.*]] = getelementptr [[STRUCT_FOO]], ptr [[SRC]], i32 0, i32 0
228 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
229 ; CHECK-NEXT: ret void
231 %src = alloca %struct.Foo, align 4
232 %dest = alloca %struct.Foo, align 4
233 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
234 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
235 %dest.alias = getelementptr %struct.Foo, ptr %dest, i32 0, i32 0
236 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
237 %1 = call i32 @use_nocapture(ptr nocapture %src)
239 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
241 %src.alias = getelementptr %struct.Foo, ptr %src, i32 0, i32 0
242 %2 = call i32 @use_nocapture(ptr nocapture %dest)
243 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
244 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
250 ; Scope in that domain
257 ; Tests that we remove scoped noalias metadata from a call.
258 define void @remove_scoped_noalias() {
259 ; CHECK-LABEL: define void @remove_scoped_noalias() {
260 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
261 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
262 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]]), !alias.scope !0
263 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
264 ; CHECK-NEXT: ret void
266 %src = alloca %struct.Foo, align 4
267 %dest = alloca %struct.Foo, align 4
268 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
269 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
270 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
271 %1 = call i32 @use_nocapture(ptr nocapture %src), !alias.scope !2
273 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
275 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
276 %2 = call i32 @use_nocapture(ptr nocapture %dest), !noalias !2
277 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
281 ; Tests that we remove metadata on the merged alloca.
282 define void @remove_alloca_metadata() {
283 ; CHECK-LABEL: define void @remove_alloca_metadata() {
284 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
285 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
286 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]]), !alias.scope !0
287 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
288 ; CHECK-NEXT: ret void
290 %src = alloca %struct.Foo, align 4, !annotation !3
291 %dest = alloca %struct.Foo, align 4
292 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
293 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
294 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
295 %1 = call i32 @use_nocapture(ptr nocapture %src), !alias.scope !2
297 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
299 %2 = call i32 @use_nocapture(ptr nocapture %dest), !noalias !2
300 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
301 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
305 ; Tests that we remove scoped noalias metadata from a call.
306 ; And confirm that don't crash on noalias metadata on lifetime markers.
307 define void @noalias_on_lifetime() {
308 ; CHECK-LABEL: define void @noalias_on_lifetime() {
309 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
310 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
311 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]]), !alias.scope !0
312 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
313 ; CHECK-NEXT: ret void
315 %src = alloca %struct.Foo, align 4
316 %dest = alloca %struct.Foo, align 4
317 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
318 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
319 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
320 %1 = call i32 @use_nocapture(ptr nocapture %src), !alias.scope !2
322 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
324 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src), !alias.scope !2
325 %2 = call i32 @use_nocapture(ptr nocapture %dest), !noalias !2
326 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest), !noalias !2
330 ; Tests that we can merge alloca if the dest and src has only refs except lifetime intrinsics.
331 define void @src_ref_dest_ref_after_copy() {
332 ; CHECK-LABEL: define void @src_ref_dest_ref_after_copy() {
333 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
334 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
335 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_readonly(ptr nocapture [[SRC]])
336 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_readonly(ptr nocapture [[SRC]])
337 ; CHECK-NEXT: ret void
339 %src = alloca %struct.Foo, align 4
340 %dest = alloca %struct.Foo, align 4
341 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
342 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
343 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
345 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
347 %1 = call i32 @use_readonly(ptr nocapture %src)
348 %2 = call i32 @use_readonly(ptr nocapture %dest)
349 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
350 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
354 ; Tests that we can merge alloca if the dest and src has only mods.
355 define void @src_mod_dest_mod_after_copy() {
356 ; CHECK-LABEL: define void @src_mod_dest_mod_after_copy() {
357 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
358 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
359 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_writeonly(ptr nocapture [[SRC]])
360 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_writeonly(ptr nocapture [[SRC]])
361 ; CHECK-NEXT: ret void
363 %src = alloca %struct.Foo, align 4
364 %dest = alloca %struct.Foo, align 4
365 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
366 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
367 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
369 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
371 %1 = call i32 @use_writeonly(ptr nocapture %src)
372 %2 = call i32 @use_writeonly(ptr nocapture %dest)
373 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
374 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
378 define void @avoid_memory_use_last_user_crash() {
379 ; CHECK-LABEL: define void @avoid_memory_use_last_user_crash() {
380 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
381 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
382 ; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[SRC]], align 4
383 ; CHECK-NEXT: ret void
385 %src = alloca %struct.Foo, align 4
386 %dest = alloca %struct.Foo, align 4
387 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
388 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
389 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
390 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
391 %v = load i32, ptr %dest
395 ; For multi-bb patch, we will insert it for next immediate post dominator block.
396 define void @terminator_lastuse() personality i32 0 {
397 ; CHECK-LABEL: define void @terminator_lastuse() personality i32 0 {
398 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
399 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
400 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
401 ; CHECK-NEXT: [[RV:%.*]] = invoke i32 @use_nocapture(ptr [[SRC]])
402 ; CHECK-NEXT: to label [[SUC:%.*]] unwind label [[UNW:%.*]]
404 ; CHECK-NEXT: [[LP:%.*]] = landingpad i32
405 ; CHECK-NEXT: cleanup
406 ; CHECK-NEXT: resume i32 0
408 ; CHECK-NEXT: ret void
410 %src = alloca %struct.Foo, align 4
411 %dest = alloca %struct.Foo, align 4
412 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
413 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
414 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
415 %1 = call i32 @use_nocapture(ptr nocapture %src)
417 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
419 call void @llvm.lifetime.end.p0(i64 12, ptr %src)
420 %rv = invoke i32 @use_nocapture(ptr %dest)
421 to label %suc unwind label %unw
423 %lp = landingpad i32 cleanup
429 define void @multi_bb_memcpy(i1 %b) {
430 ; CHECK-LABEL: define void @multi_bb_memcpy
431 ; CHECK-SAME: (i1 [[B:%.*]]) {
432 ; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4
433 ; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4
434 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
435 ; CHECK-NEXT: br label [[BB0:%.*]]
437 ; CHECK-NEXT: br label [[BB1:%.*]]
439 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
440 ; CHECK-NEXT: ret void
442 %src = alloca i32, align 4
443 %dest = alloca i32, align 4
444 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %src)
445 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %dest)
446 store i32 42, ptr %src
447 %1 = call i32 @use_nocapture(ptr nocapture %src)
451 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 4, i1 false)
455 %2 = call i32 @use_nocapture(ptr nocapture %dest)
456 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %src)
457 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %dest)
461 define void @multi_bb_load_store(i1 %b) {
462 ; CHECK-LABEL: define void @multi_bb_load_store
463 ; CHECK-SAME: (i1 [[B:%.*]]) {
464 ; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4
465 ; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4
466 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
467 ; CHECK-NEXT: br label [[BB0:%.*]]
469 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
470 ; CHECK-NEXT: ret void
472 %src = alloca i32, align 4
473 %dest = alloca i32, align 4
474 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %src)
475 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %dest)
476 store i32 42, ptr %src
477 %1 = call i32 @use_nocapture(ptr nocapture %src)
479 %src.val = load i32, ptr %src
480 store i32 %src.val, ptr %dest
484 %2 = call i32 @use_nocapture(ptr nocapture %dest)
485 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %src)
486 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %dest)
490 ; FIXME: merge allocas for bb-separated, but logically straight.
491 ; We might be handle those load/store MemCpyOpt totally
492 define void @multi_bb_separated_load_store(i1 %b) {
493 ; CHECK-LABEL: define void @multi_bb_separated_load_store
494 ; CHECK-SAME: (i1 [[B:%.*]]) {
495 ; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4
496 ; CHECK-NEXT: [[DEST:%.*]] = alloca i32, align 4
497 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nocapture [[SRC]])
498 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nocapture [[DEST]])
499 ; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4
500 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
501 ; CHECK-NEXT: [[SRC_VAL:%.*]] = load i32, ptr [[SRC]], align 4
502 ; CHECK-NEXT: br label [[BB0:%.*]]
504 ; CHECK-NEXT: store i32 [[SRC_VAL]], ptr [[DEST]], align 4
505 ; CHECK-NEXT: br label [[BB1:%.*]]
507 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
508 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nocapture [[SRC]])
509 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nocapture [[DEST]])
510 ; CHECK-NEXT: ret void
512 %src = alloca i32, align 4
513 %dest = alloca i32, align 4
514 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %src)
515 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %dest)
516 store i32 42, ptr %src
517 %1 = call i32 @use_nocapture(ptr nocapture %src)
519 %src.val = load i32, ptr %src
523 store i32 %src.val, ptr %dest
527 %2 = call i32 @use_nocapture(ptr nocapture %dest)
528 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %src)
529 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %dest)
533 define void @multi_bb_simple_br(i1 %b) {
534 ; CHECK-LABEL: define void @multi_bb_simple_br
535 ; CHECK-SAME: (i1 [[B:%.*]]) {
536 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
537 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
538 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
539 ; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]
541 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
542 ; CHECK-NEXT: br label [[BB2:%.*]]
544 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
545 ; CHECK-NEXT: br label [[BB2]]
547 ; CHECK-NEXT: ret void
549 %src = alloca %struct.Foo, align 4
550 %dest = alloca %struct.Foo, align 4
551 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
552 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
553 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
554 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)
555 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
556 br i1 %b, label %bb0, label %bb1
559 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)
563 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)
567 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
568 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
572 ; Test for BasicBlock and Instruction mixed dominator finding.
573 define void @multi_bb_dom_test0(i1 %b) {
574 ; CHECK-LABEL: define void @multi_bb_dom_test0
575 ; CHECK-SAME: (i1 [[B:%.*]]) {
576 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
577 ; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]
579 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
580 ; CHECK-NEXT: br label [[BB2:%.*]]
582 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 40, i32 50, i32 60 }, ptr [[SRC]], align 4
583 ; CHECK-NEXT: br label [[BB2]]
585 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
586 ; CHECK-NEXT: ret void
588 %src = alloca %struct.Foo, align 4
589 %dest = alloca %struct.Foo, align 4
590 br i1 %b, label %bb0, label %bb1
593 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
597 store %struct.Foo { i32 40, i32 50, i32 60 }, ptr %src
601 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
602 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
603 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest)
609 ; Test for BasicBlock and Instruction mixed dominator finding.
610 define void @multi_bb_dom_test1(i1 %b) {
611 ; CHECK-LABEL: define void @multi_bb_dom_test1
612 ; CHECK-SAME: (i1 [[B:%.*]]) {
613 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
614 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
615 ; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]
617 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
618 ; CHECK-NEXT: br label [[BB2:%.*]]
620 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 40, i32 50, i32 60 }, ptr [[SRC]], align 4
621 ; CHECK-NEXT: br label [[BB2]]
623 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
624 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
625 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
626 ; CHECK-NEXT: ret void
628 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
629 ; CHECK-NEXT: br label [[BB2]]
631 %src = alloca %struct.Foo, align 4
632 %dest = alloca %struct.Foo, align 4
633 br i1 %b, label %bb0, label %bb1
636 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
640 store %struct.Foo { i32 40, i32 50, i32 60 }, ptr %src
644 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
645 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1
646 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest)
651 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)
655 ; Test for BasicBlock and Instruction mixed post-dominator finding.
656 define void @multi_bb_pdom_test0(i1 %b) {
657 ; CHECK-LABEL: define void @multi_bb_pdom_test0
658 ; CHECK-SAME: (i1 [[B:%.*]]) {
659 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
660 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
661 ; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]
663 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
664 ; CHECK-NEXT: br label [[BB2:%.*]]
666 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
667 ; CHECK-NEXT: br label [[BB2]]
669 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
670 ; CHECK-NEXT: ret void
672 %src = alloca %struct.Foo, align 4
673 %dest = alloca %struct.Foo, align 4
674 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
675 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
676 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1
677 br i1 %b, label %bb0, label %bb1
680 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest)
684 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)
688 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)
689 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
692 uselistorder ptr %dest, { 2, 3, 0, 1, 4, 5 }
695 ; Test for inserting lifetime.end after the phi-node
696 define void @multi_bb_pdom_test1(i1 %b) {
697 ; CHECK-LABEL: define void @multi_bb_pdom_test1
698 ; CHECK-SAME: (i1 [[B:%.*]]) {
699 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
700 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
701 ; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]
703 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
704 ; CHECK-NEXT: br label [[BB2:%.*]]
706 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
707 ; CHECK-NEXT: br label [[BB2]]
709 ; CHECK-NEXT: [[I:%.*]] = phi i32 [ 42, [[BB0]] ], [ 41, [[BB1]] ]
710 ; CHECK-NEXT: ret void
712 %src = alloca %struct.Foo, align 4
713 %dest = alloca %struct.Foo, align 4
714 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
715 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
716 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1
717 br i1 %b, label %bb0, label %bb1
720 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest)
724 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)
728 %i = phi i32 [ 42, %bb0 ], [ 41, %bb1 ]
733 ; Test for existing unreachable cycle
734 define void @multi_bb_pdom_test2(i1 %b) {
735 ; CHECK-LABEL: define void @multi_bb_pdom_test2
736 ; CHECK-SAME: (i1 [[B:%.*]]) {
737 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
738 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
739 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
740 ; CHECK-NEXT: ret void
742 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
743 ; CHECK-NEXT: br label [[UNR2:%.*]]
745 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
746 ; CHECK-NEXT: br label [[UNR1:%.*]]
748 %src = alloca %struct.Foo, align 4
749 %dest = alloca %struct.Foo, align 4
750 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
751 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
752 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false); 1
753 %1 = call i32 @use_nocapture(ptr noundef nocapture %dest)
757 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)
761 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)
766 define void @multi_bb_loop(i32 %n) {
767 ; CHECK-LABEL: define void @multi_bb_loop
768 ; CHECK-SAME: (i32 [[N:%.*]]) {
770 ; CHECK-NEXT: [[NLT1:%.*]] = icmp slt i32 [[N]], 1
771 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8
772 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 0, i32 1, i32 42 }, ptr [[SRC]], align 4
773 ; CHECK-NEXT: br i1 [[NLT1]], label [[LOOP_EXIT:%.*]], label [[LOOP_BODY:%.*]]
775 ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[NEW_I:%.*]], [[LOOP_BODY]] ], [ 1, [[ENTRY:%.*]] ]
776 ; CHECK-NEXT: [[NEW_I]] = add i32 [[I]], 1
777 ; CHECK-NEXT: store i32 [[NEW_I]], ptr [[SRC]], align 4
778 ; CHECK-NEXT: [[IGTN:%.*]] = icmp sgt i32 [[NEW_I]], [[N]]
779 ; CHECK-NEXT: br i1 [[IGTN]], label [[LOOP_EXIT]], label [[LOOP_BODY]]
781 ; CHECK-NEXT: ret void
784 %nlt1 = icmp slt i32 %n, 1
785 %src = alloca %struct.Foo, align 8
786 %dest = alloca %struct.Foo, align 8
787 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
788 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
789 store %struct.Foo { i32 0, i32 1, i32 42 }, ptr %src
790 br i1 %nlt1, label %loop_exit, label %loop_body
793 %i = phi i32 [ %new_i, %loop_body ], [ 1, %entry ]
794 call void @llvm.memcpy.p0.p0.i64(ptr align 8 %dest, ptr align 8 %src, i64 12, i1 false)
795 %new_i = add i32 %i, 1
796 store i32 %new_i, ptr %src
797 %igtn = icmp sgt i32 %new_i, %n
798 br i1 %igtn, label %loop_exit, label %loop_body
804 define void @multi_bb_unreachable_modref(i1 %b0) {
805 ; CHECK-LABEL: define void @multi_bb_unreachable_modref
806 ; CHECK-SAME: (i1 [[B0:%.*]]) {
807 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
808 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
809 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
810 ; CHECK-NEXT: br i1 [[B0]], label [[BB0:%.*]], label [[EXIT:%.*]]
812 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
813 ; CHECK-NEXT: ret void
815 ; CHECK-NEXT: ret void
817 %src = alloca %struct.Foo, align 4
818 %dest = alloca %struct.Foo, align 4
819 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
820 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
821 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
822 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)
823 br i1 %b0, label %bb0, label %exit
826 %2 = call i32 @use_nocapture(ptr noundef nocapture %src)
830 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
831 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
832 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
836 define void @multi_bb_non_dominated(i1 %b0, i1 %b1) {
837 ; CHECK-LABEL: define void @multi_bb_non_dominated
838 ; CHECK-SAME: (i1 [[B0:%.*]], i1 [[B1:%.*]]) {
839 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
840 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
841 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
842 ; CHECK-NEXT: br i1 [[B0]], label [[BB0:%.*]], label [[BB1:%.*]]
844 ; CHECK-NEXT: br label [[BB2:%.*]]
846 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
847 ; CHECK-NEXT: br label [[BB2]]
849 ; CHECK-NEXT: ret void
851 %src = alloca %struct.Foo, align 4
852 %dest = alloca %struct.Foo, align 4
853 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
854 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
855 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
856 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)
857 br i1 %b0, label %bb0, label %bb1
860 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
864 %2 = call i32 @use_nocapture(ptr noundef nocapture %src)
868 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
869 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
873 ; TODO: to merge following `is_def` cases, we need to do liveness analysis
874 ; or something that distinguish the full-size-Mod as a Def.
875 ; Tests that a memcpy that completely overwrites a stack value is a definition
876 ; for the purposes of liveness analysis.
877 define void @memcpy_is_def() {
878 ; CHECK-LABEL: define void @memcpy_is_def() {
879 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
880 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
881 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
882 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
883 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
884 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
885 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
886 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
887 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[SRC]], ptr align 4 [[DEST]], i64 12, i1 false)
888 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
889 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
890 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
891 ; CHECK-NEXT: ret void
893 %src = alloca %struct.Foo, align 4
894 %dest = alloca %struct.Foo, align 4
895 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
896 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
897 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
898 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)
899 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
900 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)
901 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %src, ptr align 4 %dest, i64 12, i1 false)
902 %3 = call i32 @use_nocapture(ptr noundef nocapture %src)
903 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
904 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
908 ; TODO: merge allocas
909 ; Tests that a memset that completely overwrites a stack value is a definition
910 ; for the purposes of liveness analysis.
911 define void @memset_is_def() {
912 ; CHECK-LABEL: define void @memset_is_def() {
913 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
914 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
915 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
916 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
917 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
918 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
919 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
920 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
921 ; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[SRC]], i8 42, i64 12, i1 false)
922 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
923 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
924 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
925 ; CHECK-NEXT: ret void
927 %src = alloca %struct.Foo, align 4
928 %dest = alloca %struct.Foo, align 4
929 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
930 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
931 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
932 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)
933 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
934 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)
935 call void @llvm.memset.p0.i64(ptr align 4 %src, i8 42, i64 12, i1 false)
936 %3 = call i32 @use_nocapture(ptr noundef nocapture %src)
937 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
938 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
942 ; TODO: merge allocas
943 ; Tests that a store that completely overwrites a stack value is a definition
944 ; for the purposes of liveness analysis.
945 define void @store_is_def() {
946 ; CHECK-LABEL: define void @store_is_def() {
947 ; CHECK-NEXT: [[SRC:%.*]] = alloca i32, align 4
948 ; CHECK-NEXT: [[DEST:%.*]] = alloca i32, align 4
949 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nocapture [[SRC]])
950 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nocapture [[DEST]])
951 ; CHECK-NEXT: store i32 42, ptr [[SRC]], align 4
952 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
953 ; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[SRC]], align 4
954 ; CHECK-NEXT: store i32 [[TMP2]], ptr [[DEST]], align 4
955 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
956 ; CHECK-NEXT: store i32 64, ptr [[SRC]], align 4
957 ; CHECK-NEXT: [[TMP4:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
958 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nocapture [[SRC]])
959 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nocapture [[DEST]])
960 ; CHECK-NEXT: ret void
962 %src = alloca i32, align 4
963 %dest = alloca i32, align 4
964 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %src)
965 call void @llvm.lifetime.start.p0(i64 4, ptr nocapture %dest)
966 store i32 42, ptr %src
967 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)
968 %2 = load i32, ptr %src
969 store i32 %2, ptr %dest
970 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)
971 store i32 64, ptr %src
972 %4 = call i32 @use_nocapture(ptr noundef nocapture %src)
973 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %src)
974 call void @llvm.lifetime.end.p0(i64 4, ptr nocapture %dest)
978 ; TODO: merge src and dest, because any execution path doesn't cause conflicts.
979 ; Tests that exists modref for both src/dest, but it never conflict on the execution.
980 define void @multi_bb_dataflow(i1 %b) {
981 ; CHECK-LABEL: define void @multi_bb_dataflow
982 ; CHECK-SAME: (i1 [[B:%.*]]) {
983 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
984 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
985 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
986 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
987 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
988 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
989 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
990 ; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]
992 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
993 ; CHECK-NEXT: br label [[BB2:%.*]]
995 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
996 ; CHECK-NEXT: br label [[BB2]]
998 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
999 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1000 ; CHECK-NEXT: ret void
1002 %src = alloca %struct.Foo, align 4
1003 %dest = alloca %struct.Foo, align 4
1004 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1005 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1006 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1007 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)
1008 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1009 br i1 %b, label %bb0, label %bb1
1012 %2 = call i32 @use_nocapture(ptr noundef nocapture %src)
1016 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)
1020 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1021 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1026 ; Optimization failures follow:
1028 ; Tests that a memcpy that doesn't completely overwrite a stack value is a use
1029 ; for the purposes of liveness analysis, not a definition.
1030 define void @incomplete_memcpy() {
1031 ; CHECK-LABEL: define void @incomplete_memcpy() {
1032 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1033 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1034 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1035 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1036 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1037 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
1038 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 11, i1 false)
1039 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
1040 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1041 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1042 ; CHECK-NEXT: ret void
1044 %src = alloca %struct.Foo, align 4
1045 %dest = alloca %struct.Foo, align 4
1046 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1047 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1048 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1049 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)
1050 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 11, i1 false)
1051 %2 = call i32 @use_nocapture(ptr noundef nocapture %dest)
1052 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1053 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1057 ; Tests that a store that doesn't completely overwrite a stack value is a use
1058 ; for the purposes of liveness analysis, not a definition.
1059 define void @incomplete_store() {
1060 ; CHECK-LABEL: define void @incomplete_store() {
1061 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1062 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1063 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1064 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1065 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1066 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
1067 ; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[SRC]], align 4
1068 ; CHECK-NEXT: store i32 [[TMP2]], ptr [[DEST]], align 4
1069 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
1070 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1071 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1072 ; CHECK-NEXT: ret void
1074 %src = alloca %struct.Foo, align 4
1075 %dest = alloca %struct.Foo, align 4
1076 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1077 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1078 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1079 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)
1080 %2 = load i32, ptr %src
1081 store i32 %2, ptr %dest
1082 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)
1083 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1084 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1088 ; Tests that dynamically-sized allocas are never merged.
1089 define void @dynamically_sized_alloca(i64 %i) {
1090 ; CHECK-LABEL: define void @dynamically_sized_alloca
1091 ; CHECK-SAME: (i64 [[I:%.*]]) {
1092 ; CHECK-NEXT: [[SRC:%.*]] = alloca i8, i64 [[I]], align 4
1093 ; CHECK-NEXT: [[DEST:%.*]] = alloca i8, i64 [[I]], align 4
1094 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr nocapture [[SRC]])
1095 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr nocapture [[DEST]])
1096 ; CHECK-NEXT: store [[STRUCT_FOO:%.*]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1097 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1098 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1099 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1100 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr nocapture [[SRC]])
1101 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr nocapture [[DEST]])
1102 ; CHECK-NEXT: ret void
1104 %src = alloca i8, i64 %i, align 4
1105 %dest = alloca i8, i64 %i, align 4
1106 call void @llvm.lifetime.start.p0(i64 -1, ptr nocapture %src)
1107 call void @llvm.lifetime.start.p0(i64 -1, ptr nocapture %dest)
1108 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1109 %1 = call i32 @use_nocapture(ptr nocapture %src)
1111 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1113 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1114 call void @llvm.lifetime.end.p0(i64 -1, ptr nocapture %src)
1115 call void @llvm.lifetime.end.p0(i64 -1, ptr nocapture %dest)
1120 ; Tests that inalloca attributed allocas are never merged, to prevent stacksave/stackrestore handling.
1121 define void @inalloca() {
1122 ; CHECK-LABEL: define void @inalloca() {
1123 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1124 ; CHECK-NEXT: [[DEST:%.*]] = alloca inalloca [[STRUCT_FOO]], align 4
1125 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1126 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1127 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1128 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1129 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1130 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1131 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1132 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1133 ; CHECK-NEXT: ret void
1135 %src = alloca %struct.Foo, align 4
1136 %dest = alloca inalloca %struct.Foo, align 4
1137 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1138 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1139 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1140 %1 = call i32 @use_nocapture(ptr nocapture %src)
1142 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1144 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1145 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1146 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1150 ; Tests that a memcpy with a dynamic size is never optimized.
1151 define void @dynamically_sized_memcpy(i64 %size) {
1152 ; CHECK-LABEL: define void @dynamically_sized_memcpy
1153 ; CHECK-SAME: (i64 [[SIZE:%.*]]) {
1154 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1155 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1156 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1157 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1158 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1159 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1160 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 [[SIZE]], i1 false)
1161 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1162 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1163 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1164 ; CHECK-NEXT: ret void
1166 %src = alloca %struct.Foo, align 4
1167 %dest = alloca %struct.Foo, align 4
1168 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1169 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1170 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1171 %1 = call i32 @use_nocapture(ptr nocapture %src)
1173 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 %size, i1 false)
1175 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1176 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1177 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1181 ; Tests that allocas with different sizes aren't merged together.
1182 define void @mismatched_alloca_size() {
1183 ; CHECK-LABEL: define void @mismatched_alloca_size() {
1184 ; CHECK-NEXT: [[SRC:%.*]] = alloca i8, i64 24, align 4
1185 ; CHECK-NEXT: [[DEST:%.*]] = alloca i8, i64 12, align 4
1186 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 24, ptr nocapture [[SRC]])
1187 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1188 ; CHECK-NEXT: store [[STRUCT_FOO:%.*]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1189 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1190 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1191 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1192 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 24, ptr nocapture [[SRC]])
1193 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1194 ; CHECK-NEXT: ret void
1196 %src = alloca i8, i64 24, align 4
1197 %dest = alloca i8, i64 12, align 4
1198 call void @llvm.lifetime.start.p0(i64 24, ptr nocapture %src)
1199 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1200 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1201 %1 = call i32 @use_nocapture(ptr nocapture %src)
1203 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1205 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1206 call void @llvm.lifetime.end.p0(i64 24, ptr nocapture %src)
1207 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1211 ; Tests that allocas with mismatched address spaces aren't combined.
1212 define void @mismatched_alloca_addrspace() {
1213 ; CHECK-LABEL: define void @mismatched_alloca_addrspace() {
1214 ; CHECK-NEXT: [[SRC:%.*]] = alloca i8, i64 24, align 4, addrspace(1)
1215 ; CHECK-NEXT: [[DEST:%.*]] = alloca i8, i64 12, align 4, addrspace(2)
1216 ; CHECK-NEXT: call void @llvm.lifetime.start.p1(i64 24, ptr addrspace(1) nocapture [[SRC]])
1217 ; CHECK-NEXT: call void @llvm.lifetime.start.p2(i64 12, ptr addrspace(2) nocapture [[DEST]])
1218 ; CHECK-NEXT: store [[STRUCT_FOO:%.*]] { i32 10, i32 20, i32 30 }, ptr addrspace(1) [[SRC]], align 4
1219 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr addrspace(1) nocapture [[SRC]])
1220 ; CHECK-NEXT: call void @llvm.memcpy.p2.p1.i64(ptr addrspace(2) align 4 [[DEST]], ptr addrspace(1) align 4 [[SRC]], i64 12, i1 false)
1221 ; CHECK-NEXT: call void @llvm.lifetime.end.p1(i64 24, ptr addrspace(1) nocapture [[SRC]])
1222 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr addrspace(2) nocapture [[DEST]])
1223 ; CHECK-NEXT: call void @llvm.lifetime.end.p2(i64 12, ptr addrspace(2) nocapture [[DEST]])
1224 ; CHECK-NEXT: ret void
1226 %src = alloca i8, i64 24, align 4, addrspace(1)
1227 %dest = alloca i8, i64 12, align 4, addrspace(2)
1228 call void @llvm.lifetime.start.p1(i64 24, ptr addrspace(1) nocapture %src)
1229 call void @llvm.lifetime.start.p2(i64 12, ptr addrspace(2) nocapture %dest)
1230 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr addrspace(1) %src
1231 %1 = call i32 @use_nocapture(ptr addrspace(1) nocapture %src)
1233 call void @llvm.memcpy.p2.p1.i64(ptr addrspace(2) align 4 %dest, ptr addrspace(1) align 4 %src, i64 12, i1 false)
1235 call void @llvm.lifetime.end.p1(i64 24, ptr addrspace(1) nocapture %src)
1236 %2 = call i32 @use_nocapture(ptr addrspace(2) nocapture %dest)
1237 call void @llvm.lifetime.end.p2(i64 12, ptr addrspace(2) nocapture %dest)
1241 ; Tests that volatile memcpys aren't removed.
1242 define void @volatile_memcpy() {
1243 ; CHECK-LABEL: define void @volatile_memcpy() {
1244 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1245 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1246 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1247 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1248 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1249 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1250 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 true)
1251 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1252 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1253 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1254 ; CHECK-NEXT: ret void
1256 %src = alloca %struct.Foo, align 4
1257 %dest = alloca %struct.Foo, align 4
1258 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1259 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1260 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1261 %1 = call i32 @use_nocapture(ptr nocapture %src)
1263 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 true)
1265 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1266 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1267 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1271 ; Tests that the optimization isn't performed when the destination is captured.
1272 define void @dest_captured() {
1273 ; CHECK-LABEL: define void @dest_captured() {
1274 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1275 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1276 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1277 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1278 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1279 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1280 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1281 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_maycapture(ptr [[DEST]])
1282 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1283 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1284 ; CHECK-NEXT: ret void
1286 %src = alloca %struct.Foo, align 4
1287 %dest = alloca %struct.Foo, align 4
1288 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1289 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1290 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1292 %1 = call i32 @use_nocapture(ptr nocapture %src)
1294 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1295 %2 = call i32 @use_maycapture(ptr %dest)
1296 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1297 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1301 ; Tests that the optimization isn't performed when the source is captured.
1302 define void @src_captured() {
1303 ; CHECK-LABEL: define void @src_captured() {
1304 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1305 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1306 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1307 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1308 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1309 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_maycapture(ptr [[SRC]])
1310 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1311 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1312 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1313 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1314 ; CHECK-NEXT: ret void
1316 %src = alloca %struct.Foo, align 4
1317 %dest = alloca %struct.Foo, align 4
1318 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1319 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1320 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1321 %1 = call i32 @use_maycapture(ptr %src)
1323 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1325 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1326 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1327 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1331 ; Tests that failure if any modref exists before the copy,
1332 ; Exactly ref seems safe because no mod say ref would be always undefined, but to make simple and conservative.
1333 define void @mod_ref_before_copy() {
1334 ; CHECK-LABEL: define void @mod_ref_before_copy() {
1335 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1336 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1337 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1338 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1339 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1340 ; CHECK-NEXT: [[R:%.*]] = call i32 @use_readonly(ptr nocapture [[DEST]])
1341 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1342 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1343 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1344 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1345 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1346 ; CHECK-NEXT: ret void
1348 %src = alloca %struct.Foo, align 4
1349 %dest = alloca %struct.Foo, align 4
1350 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1351 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1352 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1353 %r = call i32 @use_readonly(ptr nocapture %dest)
1354 %1 = call i32 @use_nocapture(ptr nocapture %src)
1356 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1358 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1359 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1360 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1364 ; Tests that failure because copy semantics will change if dest is replaced with src.
1365 define void @mod_dest_before_copy() {
1366 ; CHECK-LABEL: define void @mod_dest_before_copy() {
1367 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1368 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1369 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1370 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1371 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1372 ; CHECK-NEXT: store i32 13, ptr [[DEST]], align 4
1373 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1374 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1375 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1376 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1377 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1378 ; CHECK-NEXT: ret void
1380 %src = alloca %struct.Foo, align 4
1381 %dest = alloca %struct.Foo, align 4
1382 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1383 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1384 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1385 store i32 13, ptr %dest
1386 %1 = call i32 @use_nocapture(ptr nocapture %src)
1388 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1390 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1391 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1392 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1396 define void @mod_src_before_store_after_load() {
1397 ; CHECK-LABEL: define void @mod_src_before_store_after_load() {
1398 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1399 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1400 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1401 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1402 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1403 ; CHECK-NEXT: store i32 13, ptr [[DEST]], align 4
1404 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1405 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1406 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 13, i32 13, i32 13 }, ptr [[SRC]], align 4
1407 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1408 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1409 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1410 ; CHECK-NEXT: ret void
1412 %src = alloca %struct.Foo, align 4
1413 %dest = alloca %struct.Foo, align 4
1414 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1415 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1416 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1417 store i32 13, ptr %dest
1418 %1 = call i32 @use_nocapture(ptr nocapture %src)
1420 %src.val = load %struct.Foo, ptr %src
1421 store %struct.Foo { i32 13, i32 13, i32 13 }, ptr %src
1422 store %struct.Foo %src.val, ptr %dest
1424 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1425 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1426 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1430 ; Tests that the optimization isn't performed,
1431 ; when the source may have mod and dest may have ref after the full copy.
1432 define void @src_mod_dest_ref_after_copy() {
1433 ; CHECK-LABEL: define void @src_mod_dest_ref_after_copy() {
1434 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1435 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1436 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1437 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1438 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1439 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1440 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 13, i32 13, i32 13 }, ptr [[SRC]], align 4
1441 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1442 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1443 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1444 ; CHECK-NEXT: ret void
1446 %src = alloca %struct.Foo, align 4
1447 %dest = alloca %struct.Foo, align 4
1448 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1449 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1450 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1452 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1454 store %struct.Foo { i32 13, i32 13, i32 13 }, ptr %src
1455 %1 = call i32 @use_nocapture(ptr nocapture %dest)
1456 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1457 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1461 ; Tests that the optimization isn't performed.
1462 ; Merging dest to src is no longer valid if conflicting Mod/Ref exist.
1463 define void @src_ref_dest_mod_after_copy() {
1464 ; CHECK-LABEL: define void @src_ref_dest_mod_after_copy() {
1465 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1466 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1467 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1468 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1469 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1470 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1471 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 13, i32 13, i32 13 }, ptr [[DEST]], align 4
1472 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1473 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1474 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1475 ; CHECK-NEXT: ret void
1477 %src = alloca %struct.Foo, align 4
1478 %dest = alloca %struct.Foo, align 4
1479 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1480 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1481 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1483 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1485 store %struct.Foo { i32 13, i32 13, i32 13 }, ptr %dest
1486 %1 = call i32 @use_nocapture(ptr nocapture %src)
1487 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1488 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1492 ; Tests that failure because alloca is modified through aliases, which requires recursive user ModRefChecks
1493 define void @dest_alias_mod_before_copy() {
1494 ; CHECK-LABEL: define void @dest_alias_mod_before_copy() {
1495 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1496 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1497 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1498 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1499 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1500 ; CHECK-NEXT: [[DEST_ALIAS:%.*]] = getelementptr inbounds [[STRUCT_FOO]], ptr [[DEST]], i64 0, i32 1
1501 ; CHECK-NEXT: store i32 13, ptr [[DEST_ALIAS]], align 4
1502 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1503 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1504 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1505 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1506 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1507 ; CHECK-NEXT: ret void
1509 %src = alloca %struct.Foo, align 4
1510 %dest = alloca %struct.Foo, align 4
1511 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1512 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1513 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1514 %dest.alias = getelementptr inbounds %struct.Foo, ptr %dest, i64 0, i32 1
1515 store i32 13, ptr %dest.alias
1516 %1 = call i32 @use_nocapture(ptr nocapture %src)
1518 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1520 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1521 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1522 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1526 ; Tests that failure because alloca is modified through aliases, which requires recursive user ModRefChecks
1527 define void @alias_src_ref_dest_mod_after_copy() {
1528 ; CHECK-LABEL: define void @alias_src_ref_dest_mod_after_copy() {
1529 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1530 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1531 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1532 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1533 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1534 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1535 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1536 ; CHECK-NEXT: [[DEST_ALIAS:%.*]] = getelementptr inbounds [[STRUCT_FOO]], ptr [[DEST]], i64 0, i32 1
1537 ; CHECK-NEXT: store i32 13, ptr [[DEST_ALIAS]], align 4
1538 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1539 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1540 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1541 ; CHECK-NEXT: ret void
1543 %src = alloca %struct.Foo, align 4
1544 %dest = alloca %struct.Foo, align 4
1545 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1546 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1547 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1548 %1 = call i32 @use_nocapture(ptr nocapture %src)
1550 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1552 %dest.alias = getelementptr inbounds %struct.Foo, ptr %dest, i64 0, i32 1
1553 store i32 13, ptr %dest.alias
1554 %2 = call i32 @use_nocapture(ptr nocapture %src)
1555 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1556 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1560 ; Tests that the optimization isn't performed when the source and destination
1561 ; have mod ref conflict on bb2.
1562 define void @multi_bb_dataflow_conflict(i1 %b) {
1563 ; CHECK-LABEL: define void @multi_bb_dataflow_conflict
1564 ; CHECK-SAME: (i1 [[B:%.*]]) {
1565 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1566 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1567 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1568 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1569 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1570 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
1571 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1572 ; CHECK-NEXT: br i1 [[B]], label [[BB0:%.*]], label [[BB1:%.*]]
1574 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
1575 ; CHECK-NEXT: br label [[BB2:%.*]]
1577 ; CHECK-NEXT: [[TMP3:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
1578 ; CHECK-NEXT: br label [[BB2]]
1580 ; CHECK-NEXT: [[TMP4:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
1581 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1582 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1583 ; CHECK-NEXT: ret void
1585 %src = alloca %struct.Foo, align 4
1586 %dest = alloca %struct.Foo, align 4
1587 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1588 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1589 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1590 %1 = call i32 @use_nocapture(ptr noundef nocapture %src)
1591 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1592 br i1 %b, label %bb0, label %bb1
1595 %2 = call i32 @use_nocapture(ptr noundef nocapture %src)
1599 %3 = call i32 @use_nocapture(ptr noundef nocapture %dest)
1603 %4 = call i32 @use_nocapture(ptr noundef nocapture %dest)
1604 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1605 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1609 ; Tests that failure because after copy mod could be before copy on loop.
1610 define void @multi_bb_loop_dest_mod_before_copy(i32 %n) {
1611 ; CHECK-LABEL: define void @multi_bb_loop_dest_mod_before_copy
1612 ; CHECK-SAME: (i32 [[N:%.*]]) {
1613 ; CHECK-NEXT: entry:
1614 ; CHECK-NEXT: [[NLT1:%.*]] = icmp slt i32 [[N]], 1
1615 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8
1616 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 8
1617 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1618 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[DEST]])
1619 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 0, i32 1, i32 42 }, ptr [[SRC]], align 4
1620 ; CHECK-NEXT: br i1 [[NLT1]], label [[LOOP_EXIT:%.*]], label [[LOOP_BODY:%.*]]
1622 ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[NEW_I:%.*]], [[LOOP_BODY]] ], [ 1, [[ENTRY:%.*]] ]
1623 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[DEST]], ptr align 8 [[SRC]], i64 12, i1 false)
1624 ; CHECK-NEXT: [[NEW_I]] = add i32 [[I]], 1
1625 ; CHECK-NEXT: store i32 [[NEW_I]], ptr [[DEST]], align 4
1626 ; CHECK-NEXT: [[IGTN:%.*]] = icmp sgt i32 [[NEW_I]], [[N]]
1627 ; CHECK-NEXT: br i1 [[IGTN]], label [[LOOP_EXIT]], label [[LOOP_BODY]]
1629 ; CHECK-NEXT: ret void
1632 %nlt1 = icmp slt i32 %n, 1
1633 %src = alloca %struct.Foo, align 8
1634 %dest = alloca %struct.Foo, align 8
1635 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1636 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %dest)
1637 store %struct.Foo { i32 0, i32 1, i32 42 }, ptr %src
1638 br i1 %nlt1, label %loop_exit, label %loop_body
1641 %i = phi i32 [ %new_i, %loop_body ], [ 1, %entry ]
1642 call void @llvm.memcpy.p0.p0.i64(ptr align 8 %dest, ptr align 8 %src, i64 12, i1 false)
1643 %new_i = add i32 %i, 1
1644 store i32 %new_i, ptr %dest
1645 %igtn = icmp sgt i32 %new_i, %n
1646 br i1 %igtn, label %loop_exit, label %loop_body
1652 ; Tests that failure because partial-sized lifetimes are counted as mod.
1653 define void @partial_lifetime() {
1654 ; CHECK-LABEL: define void @partial_lifetime() {
1655 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO:%.*]], align 4
1656 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO]], align 4
1657 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 12, ptr nocapture [[SRC]])
1658 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 3, ptr nocapture [[DEST]])
1659 ; CHECK-NEXT: store [[STRUCT_FOO]] { i32 10, i32 20, i32 30 }, ptr [[SRC]], align 4
1660 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @use_nocapture(ptr nocapture [[SRC]])
1661 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[DEST]], ptr align 4 [[SRC]], i64 12, i1 false)
1662 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 3, ptr nocapture [[SRC]])
1663 ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @use_nocapture(ptr nocapture [[DEST]])
1664 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[SRC]])
1665 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 12, ptr nocapture [[DEST]])
1666 ; CHECK-NEXT: ret void
1668 %src = alloca %struct.Foo, align 4
1669 %dest = alloca %struct.Foo, align 4
1670 call void @llvm.lifetime.start.p0(i64 12, ptr nocapture %src)
1671 call void @llvm.lifetime.start.p0(i64 3, ptr nocapture %dest)
1672 store %struct.Foo { i32 10, i32 20, i32 30 }, ptr %src
1673 %1 = call i32 @use_nocapture(ptr nocapture %src)
1675 call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %src, i64 12, i1 false)
1677 call void @llvm.lifetime.end.p0(i64 3, ptr nocapture %src)
1678 %2 = call i32 @use_nocapture(ptr nocapture %dest)
1679 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %src)
1680 call void @llvm.lifetime.end.p0(i64 12, ptr nocapture %dest)
1684 ; Do not merge or crash if the different block user comes first.
1685 define void @crash_store63851(i1 %b) {
1686 ; CHECK-LABEL: define void @crash_store63851
1687 ; CHECK-SAME: (i1 [[B:%.*]]) {
1688 ; CHECK-NEXT: [[DEST:%.*]] = alloca [[STRUCT_FOO:%.*]], align 8
1689 ; CHECK-NEXT: [[SRC:%.*]] = alloca [[STRUCT_FOO]], align 8
1690 ; CHECK-NEXT: store i32 0, ptr [[DEST]], align 4
1691 ; CHECK-NEXT: br i1 [[B]], label [[THEN:%.*]], label [[ELSE:%.*]]
1693 ; CHECK-NEXT: [[T:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
1694 ; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[DEST]], ptr [[SRC]], i64 12, i1 false)
1695 ; CHECK-NEXT: [[T3:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[SRC]])
1696 ; CHECK-NEXT: [[T4:%.*]] = call i32 @use_nocapture(ptr nocapture noundef [[DEST]])
1697 ; CHECK-NEXT: br label [[ELSE]]
1699 ; CHECK-NEXT: ret void
1701 %dest = alloca %struct.Foo, align 8
1702 %src = alloca %struct.Foo, align 8
1703 store i32 0, ptr %dest, align 4
1704 br i1 %b, label %then, label %else
1706 then: ; preds = %entry
1707 %t = call i32 @use_nocapture(ptr nocapture noundef %src)
1708 call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 12, i1 false)
1709 %t3 = call i32 @use_nocapture(ptr nocapture noundef %src)
1710 %t4 = call i32 @use_nocapture(ptr nocapture noundef %dest)
1713 else: ; preds = %then, %entry
1716 uselistorder ptr %dest, { 1, 2, 0 }