xref: /llvm-project/llvm/test/Transforms/InstCombine/memcpy-from-global.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64"
4@C.0.1248 = internal constant [128 x float] [ float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float 0.000000e+00, float -1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float -1.000000e+00, float 1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float -1.000000e+00, float 0.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00 ], align 32		; <ptr> [#uses=1]
5
6define float @test1(i32 %hash, float %x, float %y, float %z, float %w) {
7; CHECK-LABEL: @test1(
8; CHECK-NEXT:  entry:
9; CHECK-NEXT:    [[T3:%.*]] = shl i32 [[HASH:%.*]], 2
10; CHECK-NEXT:    [[T5:%.*]] = and i32 [[T3]], 124
11; CHECK-NEXT:    [[TMP0:%.*]] = zext nneg i32 [[T5]] to i64
12; CHECK-NEXT:    [[T753:%.*]] = getelementptr [128 x float], ptr @C.0.1248, i64 0, i64 [[TMP0]]
13; CHECK-NEXT:    [[T9:%.*]] = load float, ptr [[T753]], align 4
14; CHECK-NEXT:    [[T11:%.*]] = fmul float [[T9]], [[X:%.*]]
15; CHECK-NEXT:    [[T13:%.*]] = fadd float [[T11]], 0.000000e+00
16; CHECK-NEXT:    [[T17_SUM52:%.*]] = or disjoint i32 [[T5]], 1
17; CHECK-NEXT:    [[TMP1:%.*]] = zext nneg i32 [[T17_SUM52]] to i64
18; CHECK-NEXT:    [[T1851:%.*]] = getelementptr [128 x float], ptr @C.0.1248, i64 0, i64 [[TMP1]]
19; CHECK-NEXT:    [[T19:%.*]] = load float, ptr [[T1851]], align 4
20; CHECK-NEXT:    [[T21:%.*]] = fmul float [[T19]], [[Y:%.*]]
21; CHECK-NEXT:    [[T23:%.*]] = fadd float [[T21]], [[T13]]
22; CHECK-NEXT:    [[T27_SUM50:%.*]] = or disjoint i32 [[T5]], 2
23; CHECK-NEXT:    [[TMP2:%.*]] = zext nneg i32 [[T27_SUM50]] to i64
24; CHECK-NEXT:    [[T2849:%.*]] = getelementptr [128 x float], ptr @C.0.1248, i64 0, i64 [[TMP2]]
25; CHECK-NEXT:    [[T29:%.*]] = load float, ptr [[T2849]], align 4
26; CHECK-NEXT:    [[T31:%.*]] = fmul float [[T29]], [[Z:%.*]]
27; CHECK-NEXT:    [[T33:%.*]] = fadd float [[T31]], [[T23]]
28; CHECK-NEXT:    [[T37_SUM48:%.*]] = or disjoint i32 [[T5]], 3
29; CHECK-NEXT:    [[TMP3:%.*]] = zext nneg i32 [[T37_SUM48]] to i64
30; CHECK-NEXT:    [[T3847:%.*]] = getelementptr [128 x float], ptr @C.0.1248, i64 0, i64 [[TMP3]]
31; CHECK-NEXT:    [[T39:%.*]] = load float, ptr [[T3847]], align 4
32; CHECK-NEXT:    [[T41:%.*]] = fmul float [[T39]], [[W:%.*]]
33; CHECK-NEXT:    [[T43:%.*]] = fadd float [[T41]], [[T33]]
34; CHECK-NEXT:    ret float [[T43]]
35;
36entry:
37  %lookupTable = alloca [128 x float], align 16
38  call void @llvm.memcpy.p0.p0.i64(ptr align 16 %lookupTable, ptr align 16 @C.0.1248, i64 512, i1 false)
39
40
41  %t3 = shl i32 %hash, 2
42  %t5 = and i32 %t3, 124
43  %t753 = getelementptr [128 x float], ptr %lookupTable, i32 0, i32 %t5
44  %t9 = load float, ptr %t753
45  %t11 = fmul float %t9, %x
46  %t13 = fadd float %t11, 0.000000e+00
47  %t17.sum52 = or i32 %t5, 1
48  %t1851 = getelementptr [128 x float], ptr %lookupTable, i32 0, i32 %t17.sum52
49  %t19 = load float, ptr %t1851
50  %t21 = fmul float %t19, %y
51  %t23 = fadd float %t21, %t13
52  %t27.sum50 = or i32 %t5, 2
53  %t2849 = getelementptr [128 x float], ptr %lookupTable, i32 0, i32 %t27.sum50
54  %t29 = load float, ptr %t2849
55  %t31 = fmul float %t29, %z
56  %t33 = fadd float %t31, %t23
57  %t37.sum48 = or i32 %t5, 3
58  %t3847 = getelementptr [128 x float], ptr %lookupTable, i32 0, i32 %t37.sum48
59  %t39 = load float, ptr %t3847
60  %t41 = fmul float %t39, %w
61  %t43 = fadd float %t41, %t33
62  ret float %t43
63}
64
65declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1) nounwind
66declare void @llvm.memcpy.p1.p0.i64(ptr addrspace(1) nocapture, ptr nocapture, i64, i1) nounwind
67declare void @llvm.memcpy.p0.p1.i64(ptr nocapture, ptr addrspace(1) nocapture, i64, i1) nounwind
68declare void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) nocapture, ptr addrspace(1) nocapture, i64, i1) nounwind
69
70%T = type { i8, [123 x i8] }
71%U = type { i32, i32, i32, i32, i32 }
72
73@G = constant %T {i8 1, [123 x i8] zeroinitializer }
74@H = constant [2 x %U] zeroinitializer, align 16
75@I = internal addrspace(1) constant [4 x float] zeroinitializer , align 4
76
77define void @test2() {
78; CHECK-LABEL: @test2(
79; CHECK-NEXT:    [[B:%.*]] = alloca [[T:%.*]], align 8
80; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(124) [[B]], ptr noundef nonnull align 16 dereferenceable(124) @G, i64 124, i1 false)
81; CHECK-NEXT:    call void @bar(ptr nonnull [[B]])
82; CHECK-NEXT:    ret void
83;
84  %A = alloca %T
85  %B = alloca %T
86
87
88; %A alloca is deleted
89
90; use @G instead of %A
91  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @G, i64 124, i1 false)
92  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %B, ptr align 4 %A, i64 124, i1 false)
93  call void @bar(ptr %B)
94  ret void
95}
96
97define void @test2_no_null_opt() #0 {
98; CHECK-LABEL: @test2_no_null_opt(
99; CHECK-NEXT:    [[B:%.*]] = alloca [[T:%.*]], align 8
100; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(124) [[B]], ptr noundef nonnull align 16 dereferenceable(124) @G, i64 124, i1 false)
101; CHECK-NEXT:    call void @bar(ptr nonnull [[B]])
102; CHECK-NEXT:    ret void
103;
104  %A = alloca %T
105  %B = alloca %T
106
107
108; %A alloca is deleted
109
110; use @G instead of %A
111  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @G, i64 124, i1 false)
112  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %B, ptr align 4 %A, i64 124, i1 false)
113  call void @bar(ptr %B)
114  ret void
115}
116
117define void @test2_addrspacecast() {
118; CHECK-LABEL: @test2_addrspacecast(
119; CHECK-NEXT:    [[B:%.*]] = alloca [[T:%.*]], align 8
120; CHECK-NEXT:    [[B_CAST:%.*]] = addrspacecast ptr [[B]] to ptr addrspace(1)
121; CHECK-NEXT:    call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) noundef align 4 dereferenceable(124) [[B_CAST]], ptr addrspace(1) noundef align 4 dereferenceable(124) addrspacecast (ptr @G to ptr addrspace(1)), i64 124, i1 false)
122; CHECK-NEXT:    call void @bar_as1(ptr addrspace(1) [[B_CAST]])
123; CHECK-NEXT:    ret void
124;
125  %A = alloca %T
126  %B = alloca %T
127  %a.cast = addrspacecast ptr %A to ptr addrspace(1)
128  %b.cast = addrspacecast ptr %B to ptr addrspace(1)
129
130
131; %A alloca is deleted
132; This doesn't exactly match what test2 does, because folding the type
133; cast into the alloca doesn't work for the addrspacecast yet.
134
135; use @G instead of %A
136  call void @llvm.memcpy.p1.p0.i64(ptr addrspace(1) align 4 %a.cast, ptr align 4 @G, i64 124, i1 false)
137  call void @llvm.memcpy.p1.p1.i64(ptr addrspace(1) align 4 %b.cast, ptr addrspace(1) align 4 %a.cast, i64 124, i1 false)
138  call void @bar_as1(ptr addrspace(1) %b.cast)
139  ret void
140}
141
142declare void @bar(ptr)
143declare void @bar_as1(ptr addrspace(1))
144
145
146;; Should be able to eliminate the alloca.
147define void @test3() {
148; CHECK-LABEL: @test3(
149; CHECK-NEXT:    call void @bar(ptr nonnull @G) #[[ATTR3:[0-9]+]]
150; CHECK-NEXT:    ret void
151;
152  %A = alloca %T
153  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @G, i64 124, i1 false)
154  call void @bar(ptr %A) readonly
155  ret void
156}
157
158define void @test3_addrspacecast() {
159; CHECK-LABEL: @test3_addrspacecast(
160; CHECK-NEXT:    call void @bar(ptr nonnull @G) #[[ATTR3]]
161; CHECK-NEXT:    ret void
162;
163  %A = alloca %T
164  call void @llvm.memcpy.p0.p1.i64(ptr align 4 %A, ptr addrspace(1) align 4 addrspacecast (ptr @G to ptr addrspace(1)), i64 124, i1 false)
165  call void @bar(ptr %A) readonly
166  ret void
167}
168
169
170define void @test4() {
171; CHECK-LABEL: @test4(
172; CHECK-NEXT:    call void @baz(ptr nonnull byval(i8) @G)
173; CHECK-NEXT:    ret void
174;
175  %A = alloca %T
176  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @G, i64 124, i1 false)
177  call void @baz(ptr byval(i8) %A)
178  ret void
179}
180
181declare void @llvm.lifetime.start.p0(i64, ptr)
182define void @test5() {
183; CHECK-LABEL: @test5(
184; CHECK-NEXT:    call void @baz(ptr nonnull byval(i8) @G)
185; CHECK-NEXT:    ret void
186;
187  %A = alloca %T
188  call void @llvm.lifetime.start.p0(i64 -1, ptr %A)
189  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @G, i64 124, i1 false)
190  call void @baz(ptr byval(i8) %A)
191  ret void
192}
193
194
195declare void @baz(ptr byval(i8))
196
197
198define void @test6() {
199; CHECK-LABEL: @test6(
200; CHECK-NEXT:    call void @bar(ptr nonnull @H) #[[ATTR3]]
201; CHECK-NEXT:    ret void
202;
203  %A = alloca %U, align 16
204  call void @llvm.memcpy.p0.p0.i64(ptr align 16 %A, ptr align 16 @H, i64 20, i1 false)
205  call void @bar(ptr %A) readonly
206  ret void
207}
208
209define void @test7() {
210; CHECK-LABEL: @test7(
211; CHECK-NEXT:    call void @bar(ptr nonnull @H) #[[ATTR3]]
212; CHECK-NEXT:    ret void
213;
214  %A = alloca %U, align 16
215  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @H, i64 20, i1 false)
216  call void @bar(ptr %A) readonly
217  ret void
218}
219
220define void @test8() {
221; CHECK-LABEL: @test8(
222; CHECK-NEXT:    [[AL:%.*]] = alloca [[U:%.*]], align 16
223; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(20) [[AL]], ptr noundef nonnull align 4 dereferenceable(20) getelementptr inbounds nuw (i8, ptr @H, i64 20), i64 20, i1 false)
224; CHECK-NEXT:    call void @bar(ptr nonnull [[AL]]) #[[ATTR3]]
225; CHECK-NEXT:    ret void
226;
227  %al = alloca %U, align 16
228  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %al, ptr align 4 getelementptr ([2 x %U], ptr @H, i64 0, i32 1), i64 20, i1 false)
229  call void @bar(ptr %al) readonly
230  ret void
231}
232
233
234define void @test8_addrspacecast() {
235; CHECK-LABEL: @test8_addrspacecast(
236; CHECK-NEXT:    [[AL:%.*]] = alloca [[U:%.*]], align 16
237; CHECK-NEXT:    call void @llvm.memcpy.p0.p1.i64(ptr noundef nonnull align 16 dereferenceable(20) [[AL]], ptr addrspace(1) noundef align 4 dereferenceable(20) addrspacecast (ptr getelementptr inbounds nuw (i8, ptr @H, i64 20) to ptr addrspace(1)), i64 20, i1 false)
238; CHECK-NEXT:    call void @bar(ptr nonnull [[AL]]) #[[ATTR3]]
239; CHECK-NEXT:    ret void
240;
241  %Al = alloca %U, align 16
242  call void @llvm.memcpy.p0.p1.i64(ptr align 4 %Al, ptr addrspace(1) align 4 addrspacecast (ptr getelementptr ([2 x %U], ptr @H, i64 0, i32 1) to ptr addrspace(1)), i64 20, i1 false)
243  call void @bar(ptr %Al) readonly
244  ret void
245}
246
247define void @test9() {
248; CHECK-LABEL: @test9(
249; CHECK-NEXT:    call void @bar(ptr nonnull getelementptr inbounds nuw (i8, ptr @H, i64 20)) #[[ATTR3]]
250; CHECK-NEXT:    ret void
251;
252  %A = alloca %U, align 4
253  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 getelementptr ([2 x %U], ptr @H, i64 0, i32 1), i64 20, i1 false)
254  call void @bar(ptr %A) readonly
255  ret void
256}
257
258define void @test9_addrspacecast() {
259; CHECK-LABEL: @test9_addrspacecast(
260; CHECK-NEXT:    call void @bar(ptr nonnull getelementptr inbounds nuw (i8, ptr @H, i64 20)) #[[ATTR3]]
261; CHECK-NEXT:    ret void
262;
263  %A = alloca %U, align 4
264  call void @llvm.memcpy.p0.p1.i64(ptr align 4 %A, ptr addrspace(1) align 4 addrspacecast (ptr getelementptr ([2 x %U], ptr @H, i64 0, i32 1) to ptr addrspace(1)), i64 20, i1 false)
265  call void @bar(ptr %A) readonly
266  ret void
267}
268
269@bbb = local_unnamed_addr global [1000000 x i8] zeroinitializer, align 16
270@_ZL3KKK = internal unnamed_addr constant [3 x i8] c"\01\01\02", align 1
271
272; Should not replace alloca with global because of size mismatch.
273define void @test9_small_global() {
274; CHECK-LABEL: @test9_small_global(
275; CHECK-NEXT:  entry:
276; CHECK-NEXT:    [[CC:%.*]] = alloca [1000000 x i8], align 16
277; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(3) [[CC]], ptr noundef nonnull align 16 dereferenceable(3) @_ZL3KKK, i64 3, i1 false)
278; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(1000000) @bbb, ptr noundef nonnull align 16 dereferenceable(1000000) [[CC]], i64 1000000, i1 false)
279; CHECK-NEXT:    ret void
280;
281entry:
282  %cc = alloca [1000000 x i8], align 16
283  call void @llvm.memcpy.p0.p0.i64(ptr %cc, ptr @_ZL3KKK, i64 3, i1 false)
284  call void @llvm.memcpy.p0.p0.i64(ptr align 16 @bbb, ptr align 16 %cc, i64 1000000, i1 false)
285  ret void
286}
287
288; Should replace alloca with global as they have exactly the same size.
289define void @test10_same_global() {
290; CHECK-LABEL: @test10_same_global(
291; CHECK-NEXT:  entry:
292; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(3) @bbb, ptr noundef nonnull align 16 dereferenceable(3) @_ZL3KKK, i64 3, i1 false)
293; CHECK-NEXT:    ret void
294;
295entry:
296  %cc = alloca [3 x i8], align 1
297  call void @llvm.memcpy.p0.p0.i64(ptr %cc, ptr @_ZL3KKK, i64 3, i1 false)
298  call void @llvm.memcpy.p0.p0.i64(ptr @bbb, ptr %cc, i64 3, i1 false)
299  ret void
300}
301
302; Should replace alloca with global even when the global is in a different address space
303define float @test11(i64 %i) {
304; CHECK-LABEL: @test11(
305; CHECK-NEXT:  entry:
306; CHECK-NEXT:    ret float 0.000000e+00
307;
308
309entry:
310  %a = alloca [4 x float], align 4
311  call void @llvm.lifetime.start.p0(i64 16, ptr %a)
312  call void @llvm.memcpy.p0.p1.i64(ptr align 4 %a, ptr addrspace(1) align 4 @I, i64 16, i1 false)
313  %g = getelementptr inbounds [4 x float], ptr %a, i64 0, i64 %i
314  %r = load float, ptr %g, align 4
315  ret float %r
316}
317
318; If the memcpy is volatile, it should not be removed
319define float @test11_volatile(i64 %i) {
320; CHECK-LABEL: @test11_volatile(
321; CHECK-NEXT:  entry:
322; CHECK-NEXT:    [[A:%.*]] = alloca [4 x float], align 4
323; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 16, ptr nonnull [[A]])
324; CHECK-NEXT:    call void @llvm.memcpy.p0.p1.i64(ptr align 4 [[A]], ptr addrspace(1) align 4 @I, i64 16, i1 true)
325; CHECK-NEXT:    [[G:%.*]] = getelementptr inbounds [4 x float], ptr [[A]], i64 0, i64 [[I:%.*]]
326; CHECK-NEXT:    [[R:%.*]] = load float, ptr [[G]], align 4
327; CHECK-NEXT:    ret float [[R]]
328;
329
330entry:
331  %a = alloca [4 x float], align 4
332  call void @llvm.lifetime.start.p0(i64 16, ptr %a)
333  call void @llvm.memcpy.p0.p1.i64(ptr align 4 %a, ptr addrspace(1) align 4 @I, i64 16, i1 true)
334  %g = getelementptr inbounds [4 x float], ptr %a, i64 0, i64 %i
335  %r = load float, ptr %g, align 4
336  ret float %r
337}
338
339; Tests that we can eliminate allocas copied from readonly noalias pointers.
340define void @memcpy_from_readonly_noalias(ptr readonly noalias align 8 dereferenceable(124) %arg) {
341; CHECK-LABEL: @memcpy_from_readonly_noalias(
342; CHECK-NEXT:    call void @bar(ptr nonnull [[ARG:%.*]]) #[[ATTR3]]
343; CHECK-NEXT:    ret void
344;
345  %alloca = alloca %T, align 8
346  call void @llvm.memcpy.p0.p0.i64(ptr %alloca, ptr %arg, i64 124, i1 false)
347  call void @bar(ptr %alloca) readonly
348  ret void
349}
350
351; Tests that we don't eliminate allocas copied from readonly pointers without noalias.
352define void @memcpy_from_just_readonly(ptr readonly align 8 dereferenceable(124) %arg) {
353; CHECK-LABEL: @memcpy_from_just_readonly(
354; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca [[T:%.*]], align 8
355; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(124) [[ALLOCA]], ptr noundef nonnull align 8 dereferenceable(124) [[ARG:%.*]], i64 124, i1 false)
356; CHECK-NEXT:    call void @bar(ptr nonnull [[ALLOCA]]) #[[ATTR3]]
357; CHECK-NEXT:    ret void
358;
359  %alloca = alloca %T, align 8
360  call void @llvm.memcpy.p0.p0.i64(ptr %alloca, ptr %arg, i64 124, i1 false)
361  call void @bar(ptr %alloca) readonly
362  ret void
363}
364
365; Test that we don't elide a volatile memcpy.
366define void @volatile_memcpy() {
367; CHECK-LABEL: @volatile_memcpy(
368; CHECK-NEXT:    [[A:%.*]] = alloca [[U:%.*]], align 16
369; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[A]], ptr align 4 @H, i64 20, i1 true)
370; CHECK-NEXT:    call void @bar(ptr nonnull [[A]]) #[[ATTR3]]
371; CHECK-NEXT:    ret void
372;
373  %A = alloca %U, align 16
374  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @H, i64 20, i1 true)
375  call void @bar(ptr %A) readonly
376  ret void
377}
378
379; Test that we can elide a memcpy when copying a constant value onto the stack
380; and then forwarding it by readonly nocapture reference.
381define void @memcpy_to_nocapture_readonly() {
382; CHECK-LABEL: @memcpy_to_nocapture_readonly(
383; CHECK-NEXT:    call void @bar(ptr nonnull readonly captures(none) @H)
384; CHECK-NEXT:    ret void
385;
386  %A = alloca %U, align 16
387  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @H, i64 20, i1 false)
388  call void @bar(ptr nocapture readonly %A)
389  ret void
390}
391
392; Test that we don't elide the memcpy when copying a constant value onto the
393; stack and then forwarding it by readonly, but capturing, reference.
394define void @memcpy_to_capturing_readonly() {
395; CHECK-LABEL: @memcpy_to_capturing_readonly(
396; CHECK-NEXT:    [[A:%.*]] = alloca [[U:%.*]], align 16
397; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(20) [[A]], ptr noundef nonnull align 16 dereferenceable(20) @H, i64 20, i1 false)
398; CHECK-NEXT:    call void @bar(ptr nonnull readonly [[A]])
399; CHECK-NEXT:    ret void
400;
401  %A = alloca %U, align 16
402  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @H, i64 20, i1 false)
403  call void @bar(ptr readonly %A)
404  ret void
405}
406
407; Test that we don't elide the memcpy when copying a constant value onto the
408; stack and then forwarding it by read-write, nocapture reference, even if it's
409; also forwarded by readonly nocapture reference to the same function.
410define void @memcpy_to_aliased_nocapture_readonly() {
411; CHECK-LABEL: @memcpy_to_aliased_nocapture_readonly(
412; CHECK-NEXT:    [[A:%.*]] = alloca [[U:%.*]], align 16
413; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 16 dereferenceable(20) [[A]], ptr noundef nonnull align 16 dereferenceable(20) @H, i64 20, i1 false)
414; CHECK-NEXT:    call void @two_params(ptr nonnull readonly captures(none) [[A]], ptr nonnull captures(none) [[A]])
415; CHECK-NEXT:    ret void
416;
417  %A = alloca %U, align 16
418  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %A, ptr align 4 @H, i64 20, i1 false)
419  call void @two_params(ptr nocapture readonly %A, ptr nocapture %A)
420  ret void
421}
422
423declare void @two_params(ptr nocapture readonly, ptr nocapture)
424
425attributes #0 = { null_pointer_is_valid }
426