xref: /llvm-project/llvm/test/Transforms/SROA/readonlynocapture.ll (revision 1a56360cc61a3576ab0ad621f72d4299bd5dd0fb)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=sroa -S | FileCheck %s
3
4declare void @callee(ptr nocapture readonly %p)
5
6define i32 @simple() {
7; CHECK-LABEL: @simple(
8; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
9; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
10; CHECK-NEXT:    call void @callee(ptr [[A]])
11; CHECK-NEXT:    ret i32 0
12;
13  %a = alloca i32
14  store i32 0, ptr %a
15  call void @callee(ptr %a)
16  %l1 = load i32, ptr %a
17  ret i32 %l1
18}
19
20define i32 @smallbig() {
21; CHECK-LABEL: @smallbig(
22; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
23; CHECK-NEXT:    store i8 0, ptr [[A]], align 1
24; CHECK-NEXT:    call void @callee(ptr [[A]])
25; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[A]], align 4
26; CHECK-NEXT:    ret i32 [[L1]]
27;
28  %a = alloca i32
29  store i8 0, ptr %a
30  call void @callee(ptr %a)
31  %l1 = load i32, ptr %a
32  ret i32 %l1
33}
34
35define i32 @twoalloc() {
36; CHECK-LABEL: @twoalloc(
37; CHECK-NEXT:    [[A:%.*]] = alloca { i32, i32 }, align 8
38; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
39; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
40; CHECK-NEXT:    store i32 1, ptr [[B]], align 4
41; CHECK-NEXT:    call void @callee(ptr [[A]])
42; CHECK-NEXT:    [[R:%.*]] = add i32 0, 1
43; CHECK-NEXT:    ret i32 [[R]]
44;
45  %a = alloca {i32, i32}
46  store i32 0, ptr %a
47  %b = getelementptr i32, ptr %a, i32 1
48  store i32 1, ptr %b
49  call void @callee(ptr %a)
50  %l1 = load i32, ptr %a
51  %l2 = load i32, ptr %b
52  %r = add i32 %l1, %l2
53  ret i32 %r
54}
55
56define i32 @twostore() {
57; CHECK-LABEL: @twostore(
58; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
59; CHECK-NEXT:    store i32 1, ptr [[A]], align 4
60; CHECK-NEXT:    call void @callee(ptr [[A]])
61; CHECK-NEXT:    store i32 2, ptr [[A]], align 4
62; CHECK-NEXT:    ret i32 2
63;
64  %a = alloca i32
65  store i32 1, ptr %a
66  call void @callee(ptr %a)
67  store i32 2, ptr %a
68  %l = load i32, ptr %a
69  ret i32 %l
70}
71
72define float @differenttype() {
73; CHECK-LABEL: @differenttype(
74; CHECK-NEXT:    [[A:%.*]] = alloca { i32, i32 }, align 8
75; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
76; CHECK-NEXT:    store i32 1, ptr [[B]], align 4
77; CHECK-NEXT:    call void @callee(ptr [[A]])
78; CHECK-NEXT:    [[L2:%.*]] = load float, ptr [[B]], align 4
79; CHECK-NEXT:    ret float [[L2]]
80;
81  %a = alloca {i32, i32}
82  %b = getelementptr i32, ptr %a, i32 1
83  store i32 1, ptr %b
84  call void @callee(ptr %a)
85  %l2 = load float, ptr %b
86  ret float %l2
87}
88
89define i32 @twoalloc_store64(i64 %x) {
90; CHECK-LABEL: @twoalloc_store64(
91; CHECK-NEXT:    [[A:%.*]] = alloca i64, align 8
92; CHECK-NEXT:    store i64 [[X:%.*]], ptr [[A]], align 4
93; CHECK-NEXT:    call void @callee(ptr [[A]])
94; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[A]], align 4
95; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
96; CHECK-NEXT:    [[L2:%.*]] = load i32, ptr [[B]], align 4
97; CHECK-NEXT:    ret i32 [[L2]]
98;
99  %a = alloca i64
100  store i64 %x, ptr %a
101  call void @callee(ptr %a)
102  %l1 = load i32, ptr %a
103  %b = getelementptr i32, ptr %a, i32 1
104  %l2 = load i32, ptr %b
105  ret i32 %l2
106}
107
108define i32 @twocalls() {
109; CHECK-LABEL: @twocalls(
110; CHECK-NEXT:    [[A:%.*]] = alloca { i32, i32 }, align 8
111; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
112; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
113; CHECK-NEXT:    store i32 1, ptr [[B]], align 4
114; CHECK-NEXT:    call void @callee(ptr [[A]])
115; CHECK-NEXT:    call void @callee(ptr [[A]])
116; CHECK-NEXT:    [[R:%.*]] = add i32 0, 1
117; CHECK-NEXT:    ret i32 [[R]]
118;
119  %a = alloca {i32, i32}
120  store i32 0, ptr %a
121  %b = getelementptr i32, ptr %a, i32 1
122  store i32 1, ptr %b
123  call void @callee(ptr %a)
124  %l1 = load i32, ptr %a
125  call void @callee(ptr %a)
126  %l2 = load i32, ptr %b
127  %r = add i32 %l1, %l2
128  ret i32 %r
129}
130
131define i32 @volatile() {
132; CHECK-LABEL: @volatile(
133; CHECK-NEXT:    [[A:%.*]] = alloca { i32, i32 }, align 8
134; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
135; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
136; CHECK-NEXT:    store volatile i32 1, ptr [[B]], align 4
137; CHECK-NEXT:    call void @callee(ptr [[A]])
138; CHECK-NEXT:    [[L1:%.*]] = load volatile i32, ptr [[A]], align 4
139; CHECK-NEXT:    [[L2:%.*]] = load i32, ptr [[B]], align 4
140; CHECK-NEXT:    [[R:%.*]] = add i32 [[L1]], [[L2]]
141; CHECK-NEXT:    ret i32 [[R]]
142;
143  %a = alloca {i32, i32}
144  store i32 0, ptr %a
145  %b = getelementptr i32, ptr %a, i32 1
146  store volatile i32 1, ptr %b
147  call void @callee(ptr %a)
148  %l1 = load volatile i32, ptr %a
149  %l2 = load i32, ptr %b
150  %r = add i32 %l1, %l2
151  ret i32 %r
152}
153
154define i32 @atomic() {
155; CHECK-LABEL: @atomic(
156; CHECK-NEXT:    [[A:%.*]] = alloca { i32, i32 }, align 8
157; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
158; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
159; CHECK-NEXT:    store i32 1, ptr [[B]], align 4
160; CHECK-NEXT:    call void @callee(ptr [[A]])
161; CHECK-NEXT:    [[L1:%.*]] = load atomic i32, ptr [[A]] seq_cst, align 4
162; CHECK-NEXT:    [[R:%.*]] = add i32 [[L1]], 1
163; CHECK-NEXT:    ret i32 [[R]]
164;
165  %a = alloca {i32, i32}
166  store i32 0, ptr %a
167  %b = getelementptr i32, ptr %a, i32 1
168  store i32 1, ptr %b
169  call void @callee(ptr %a)
170  %l1 = load atomic i32, ptr %a seq_cst, align 4
171  %l2 = load i32, ptr %b
172  %r = add i32 %l1, %l2
173  ret i32 %r
174}
175
176define i32 @notdominating() {
177; CHECK-LABEL: @notdominating(
178; CHECK-NEXT:    [[A:%.*]] = alloca { i32, i32 }, align 8
179; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
180; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
181; CHECK-NEXT:    store i32 1, ptr [[B]], align 4
182; CHECK-NEXT:    call void @callee(ptr [[A]])
183; CHECK-NEXT:    [[R:%.*]] = add i32 undef, undef
184; CHECK-NEXT:    ret i32 [[R]]
185;
186  %a = alloca {i32, i32}
187  %b = getelementptr i32, ptr %a, i32 1
188  %l1 = load i32, ptr %a
189  %l2 = load i32, ptr %b
190  store i32 0, ptr %a
191  store i32 1, ptr %b
192  call void @callee(ptr %a)
193  %r = add i32 %l1, %l2
194  ret i32 %r
195}
196
197declare void @callee_notreadonly(ptr %p)
198define i32 @notreadonly() {
199; CHECK-LABEL: @notreadonly(
200; CHECK-NEXT:    [[A:%.*]] = alloca { i32, i32 }, align 8
201; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
202; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
203; CHECK-NEXT:    store i32 1, ptr [[B]], align 4
204; CHECK-NEXT:    call void @callee_notreadonly(ptr [[A]])
205; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[A]], align 4
206; CHECK-NEXT:    [[L2:%.*]] = load i32, ptr [[B]], align 4
207; CHECK-NEXT:    [[R:%.*]] = add i32 [[L1]], [[L2]]
208; CHECK-NEXT:    ret i32 [[R]]
209;
210  %a = alloca {i32, i32}
211  store i32 0, ptr %a
212  %b = getelementptr i32, ptr %a, i32 1
213  store i32 1, ptr %b
214  call void @callee_notreadonly(ptr %a)
215  %l1 = load i32, ptr %a
216  %l2 = load i32, ptr %b
217  %r = add i32 %l1, %l2
218  ret i32 %r
219}
220
221declare void @callee_multiuse(ptr nocapture readonly %p, ptr nocapture readonly %q)
222define i32 @multiuse() {
223; CHECK-LABEL: @multiuse(
224; CHECK-NEXT:    [[A:%.*]] = alloca { i32, i32 }, align 8
225; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
226; CHECK-NEXT:    [[B:%.*]] = getelementptr i32, ptr [[A]], i32 1
227; CHECK-NEXT:    store i32 1, ptr [[B]], align 4
228; CHECK-NEXT:    call void @callee_multiuse(ptr [[A]], ptr [[A]])
229; CHECK-NEXT:    [[R:%.*]] = add i32 0, 1
230; CHECK-NEXT:    ret i32 [[R]]
231;
232  %a = alloca {i32, i32}
233  store i32 0, ptr %a
234  %b = getelementptr i32, ptr %a, i32 1
235  store i32 1, ptr %b
236  call void @callee_multiuse(ptr %a, ptr %a)
237  %l1 = load i32, ptr %a
238  %l2 = load i32, ptr %b
239  %r = add i32 %l1, %l2
240  ret i32 %r
241}
242
243define i32 @memcpyed(ptr %src) {
244; CHECK-LABEL: @memcpyed(
245; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
246; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
247; CHECK-NEXT:    call void @callee(ptr [[A]])
248; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[A]], ptr [[SRC:%.*]], i64 4, i1 false)
249; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[A]], align 4
250; CHECK-NEXT:    ret i32 [[L1]]
251;
252  %a = alloca i32
253  store i32 0, ptr %a
254  call void @callee(ptr %a)
255  call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %src, i64 4, i1 false)
256  %l1 = load i32, ptr %a
257  ret i32 %l1
258}
259
260define ptr @memcpyedsplit(ptr %src) {
261; CHECK-LABEL: @memcpyedsplit(
262; CHECK-NEXT:    [[A:%.*]] = alloca { i64, i64 }, align 8
263; CHECK-NEXT:    store i8 1, ptr [[A]], align 1
264; CHECK-NEXT:    [[B:%.*]] = getelementptr i64, ptr [[A]], i32 1
265; CHECK-NEXT:    store ptr null, ptr [[B]], align 8
266; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[A]], ptr [[SRC:%.*]], i64 16, i1 false)
267; CHECK-NEXT:    call void @callee(ptr [[A]])
268; CHECK-NEXT:    [[L1:%.*]] = load ptr, ptr [[B]], align 8
269; CHECK-NEXT:    ret ptr [[L1]]
270;
271  %a = alloca { i64, i64 }
272  store i8 1, ptr %a
273  %b = getelementptr i64, ptr %a, i32 1
274  store ptr null, ptr %b
275  call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr %src, i64 16, i1 false)
276  call void @callee(ptr %a)
277  %l1 = load ptr, ptr %b
278  ret ptr %l1
279}
280
281; This struct contains padding bits. The load should not be replaced by poison.
282%struct.LoadImmediateInfo = type { i32 }
283define void @incompletestruct(i1 %b, i1 %c) {
284; CHECK-LABEL: @incompletestruct(
285; CHECK-NEXT:  entry:
286; CHECK-NEXT:    [[LII:%.*]] = alloca [[STRUCT_LOADIMMEDIATEINFO:%.*]], align 4
287; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[LII]])
288; CHECK-NEXT:    [[BF_CLEAR4:%.*]] = and i32 undef, -262144
289; CHECK-NEXT:    [[BF_SET5:%.*]] = select i1 [[B:%.*]], i32 196608, i32 131072
290; CHECK-NEXT:    [[BF_SET12:%.*]] = or disjoint i32 [[BF_SET5]], [[BF_CLEAR4]]
291; CHECK-NEXT:    store i32 [[BF_SET12]], ptr [[LII]], align 4
292; CHECK-NEXT:    call void @callee(ptr [[LII]])
293; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[LII]])
294; CHECK-NEXT:    ret void
295;
296entry:
297  %LII = alloca %struct.LoadImmediateInfo, align 4
298  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %LII)
299  %bf.load = load i32, ptr %LII, align 4
300  %bf.clear4 = and i32 %bf.load, -262144
301  %bf.set5 = select i1 %b, i32 196608, i32 131072
302  %bf.set12 = or disjoint i32 %bf.set5, %bf.clear4
303  store i32 %bf.set12, ptr %LII, align 4
304  call void @callee(ptr %LII)
305  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %LII)
306  ret void
307}
308
309define void @incompletestruct_bb(i1 %b, i1 %c) {
310; CHECK-LABEL: @incompletestruct_bb(
311; CHECK-NEXT:  entry:
312; CHECK-NEXT:    [[LII:%.*]] = alloca [[STRUCT_LOADIMMEDIATEINFO:%.*]], align 4
313; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
314; CHECK:       if.then:
315; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[LII]])
316; CHECK-NEXT:    [[BF_CLEAR4:%.*]] = and i32 undef, -262144
317; CHECK-NEXT:    [[BF_SET5:%.*]] = select i1 [[B:%.*]], i32 196608, i32 131072
318; CHECK-NEXT:    [[BF_SET12:%.*]] = or disjoint i32 [[BF_SET5]], [[BF_CLEAR4]]
319; CHECK-NEXT:    store i32 [[BF_SET12]], ptr [[LII]], align 4
320; CHECK-NEXT:    call void @callee(ptr [[LII]])
321; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[LII]])
322; CHECK-NEXT:    br label [[IF_END]]
323; CHECK:       if.end:
324; CHECK-NEXT:    ret void
325;
326entry:
327  %LII = alloca %struct.LoadImmediateInfo, align 4
328  br i1 %c, label %if.then, label %if.end
329
330if.then:                                          ; preds = %entry
331  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %LII)
332  %bf.load = load i32, ptr %LII, align 4
333  %bf.clear4 = and i32 %bf.load, -262144
334  %bf.set5 = select i1 %b, i32 196608, i32 131072
335  %bf.set12 = or disjoint i32 %bf.set5, %bf.clear4
336  store i32 %bf.set12, ptr %LII, align 4
337  call void @callee(ptr %LII)
338  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %LII)
339  br label %if.end
340
341if.end:                                           ; preds = %if.then, %entry
342  ret void
343}
344
345define i32 @sixteenload() {
346; CHECK-LABEL: @sixteenload(
347; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
348; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
349; CHECK-NEXT:    call void @callee(ptr [[A]])
350; CHECK-NEXT:    [[A1:%.*]] = add i32 0, 0
351; CHECK-NEXT:    [[A2:%.*]] = add i32 [[A1]], 0
352; CHECK-NEXT:    ret i32 [[A2]]
353;
354  %a = alloca i32
355  store i32 0, ptr %a
356  call void @callee(ptr %a)
357  %l1 = load i32, ptr %a
358  %l2 = load i32, ptr %a
359  %l3 = load i32, ptr %a
360  %l4 = load i32, ptr %a
361  %l5 = load i32, ptr %a
362  %l6 = load i32, ptr %a
363  %l7 = load i32, ptr %a
364  %l8 = load i32, ptr %a
365  %l9 = load i32, ptr %a
366  %l10 = load i32, ptr %a
367  %l11 = load i32, ptr %a
368  %l12 = load i32, ptr %a
369  %l13 = load i32, ptr %a
370  %l14 = load i32, ptr %a
371  %l15 = load i32, ptr %a
372  %l16 = load i32, ptr %a
373  %a1 = add i32 %l1, %l2
374  %a2 = add i32 %a1, %l3
375  ret i32 %a2
376}
377
378define i32 @testcallalloca() {
379; CHECK-LABEL: @testcallalloca(
380; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
381; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
382; CHECK-NEXT:    call void [[A]]()
383; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[A]], align 4
384; CHECK-NEXT:    ret i32 [[L1]]
385;
386  %a = alloca i32
387  store i32 0, ptr %a
388  call void %a()
389  %l1 = load i32, ptr %a
390  ret i32 %l1
391}
392
393declare void @callee_byval(ptr byval(i32) %p)
394
395define i32 @simple_byval() {
396; CHECK-LABEL: @simple_byval(
397; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
398; CHECK-NEXT:    store i32 0, ptr [[A]], align 4
399; CHECK-NEXT:    call void @callee_byval(ptr [[A]])
400; CHECK-NEXT:    ret i32 0
401;
402  %a = alloca i32
403  store i32 0, ptr %a
404  call void @callee_byval(ptr %a)
405  %l1 = load i32, ptr %a
406  ret i32 %l1
407}
408
409declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
410