xref: /llvm-project/llvm/test/Analysis/BasicAA/recphi.ll (revision 243acd5dcbc637e477062877185ad76d8ff63d9d)
1; RUN: opt < %s -aa-pipeline=basic-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
2
3; CHECK-LABEL: Function: simple: 5 pointers, 0 call sites
4; CHECK:         NoAlias:      float* %src1, float* %src2
5; CHECK:         NoAlias:      float* %phi, float* %src1
6; CHECK:         MayAlias:     float* %phi, float* %src2
7; CHECK:         NoAlias:      float* %next, float* %src1
8; CHECK:         MayAlias:     float* %next, float* %src2
9; CHECK:         NoAlias:      float* %next, float* %phi
10; CHECK:         NoAlias:      float* %g, float* %src1
11; CHECK:         NoAlias:      float* %g, float* %src2
12; CHECK:         NoAlias:      float* %g, float* %phi
13; CHECK:         NoAlias:      float* %g, float* %next
14define void @simple(ptr %src1, ptr noalias %src2, i32 %n) nounwind {
15entry:
16  load float, ptr %src1
17  load float, ptr %src2
18  br label %loop
19
20loop:
21  %phi = phi ptr [ %src2, %entry ], [ %next, %loop ]
22  %idx = phi i32 [ 0, %entry ], [ %idxn, %loop ]
23  %next = getelementptr inbounds float, ptr %phi, i32 1
24  %g = getelementptr inbounds float, ptr %src1, i32 3
25  %l = load float, ptr %phi
26  load float, ptr %next
27  %a = fadd float %l, 1.0
28  store float %a, ptr %g
29  %idxn = add nsw nuw i32 %idx, 1
30  %cmp5 = icmp eq i32 %idxn, %n
31  br i1 %cmp5, label %end, label %loop
32
33end:
34  ret void
35}
36
37; CHECK-LABEL: Function: notmust: 6 pointers, 0 call sites
38; CHECK: MustAlias:	i8* %tab, [2 x i32]* %tab
39; CHECK: PartialAlias (off -4):	i32* %arrayidx, [2 x i32]* %tab
40; CHECK: NoAlias:	i32* %arrayidx, i8* %tab
41; CHECK: MustAlias:	i32* %tab, [2 x i32]* %tab
42; CHECK: MustAlias:	i32* %tab, i8* %tab
43; CHECK: NoAlias:	i32* %arrayidx, i32* %tab
44; CHECK: MayAlias:	i32* %incdec.ptr.i, [2 x i32]* %tab
45; CHECK: NoAlias:	i32* %incdec.ptr.i, i8* %tab
46; CHECK: MayAlias:	i32* %arrayidx, i32* %incdec.ptr.i
47; CHECK: NoAlias:	i32* %incdec.ptr.i, i32* %tab
48; CHECK: MayAlias:	i32* %p.addr.05.i, [2 x i32]* %tab
49; CHECK: MayAlias:	i32* %p.addr.05.i, i8* %tab
50; CHECK: MayAlias:	i32* %arrayidx, i32* %p.addr.05.i
51; CHECK: MayAlias:	i32* %p.addr.05.i, i32* %tab
52; CHECK: NoAlias:	i32* %incdec.ptr.i, i32* %p.addr.05.i
53define i32 @notmust() nounwind {
54entry:
55  %tab = alloca [2 x i32], align 4
56  %ignore1 = load [2 x i32], ptr %tab
57  %ignore2 = load i8, ptr %tab
58  %arrayidx = getelementptr inbounds [2 x i32], ptr %tab, i32 0, i32 1
59  store i32 0, ptr %arrayidx, align 4
60  store i32 0, ptr %tab, align 4
61  %0 = add i32 1, 1
62  %cmp4.i = icmp slt i32 %0, 2
63  br i1 %cmp4.i, label %while.body.i, label %f.exit
64
65while.body.i: ; preds = %while.body.i, %entry
66  %1 = phi i32 [ 1, %while.body.i ], [ %0, %entry ]
67  %foo.06.i = phi i32 [ %sub.i, %while.body.i ], [ 2, %entry ]
68  %p.addr.05.i = phi ptr [ %incdec.ptr.i, %while.body.i ], [ %tab, %entry ]
69  %sub.i = sub nsw i32 %foo.06.i, %1
70  %incdec.ptr.i = getelementptr inbounds i32, ptr %p.addr.05.i, i32 1
71  %ignore3 = load i32, ptr %incdec.ptr.i
72  store i32 %sub.i, ptr %p.addr.05.i, align 4
73  %cmp.i = icmp sgt i32 %sub.i, 1
74  br i1 %cmp.i, label %while.body.i, label %f.exit
75
76f.exit: ; preds = %entry, %while.body.i
77  %2 = load i32, ptr %tab, align 4
78  %cmp = icmp eq i32 %2, 2
79  %3 = load i32, ptr %arrayidx, align 4
80  %cmp4 = icmp eq i32 %3, 1
81  %or.cond = and i1 %cmp, %cmp4
82  br i1 %or.cond, label %if.end, label %if.then
83
84if.then: ; preds = %f.exit
85  unreachable
86
87if.end: ; preds = %f.exit
88  ret i32 0
89}
90
91; CHECK-LABEL: Function: reverse: 6 pointers, 0 call sites
92; CHECK: MustAlias:	i8* %tab, [10 x i32]* %tab
93; CHECK: MustAlias:	i32* %tab, [10 x i32]* %tab
94; CHECK: MustAlias:	i32* %tab, i8* %tab
95; CHECK: PartialAlias (off -36):	i32* %arrayidx1, [10 x i32]* %tab
96; CHECK: NoAlias:	i32* %arrayidx1, i8* %tab
97; CHECK: NoAlias:	i32* %arrayidx1, i32* %tab
98; CHECK: MayAlias:	i32* %incdec.ptr.i, [10 x i32]* %tab
99; CHECK: MayAlias:	i32* %incdec.ptr.i, i8* %tab
100; CHECK: MayAlias:	i32* %incdec.ptr.i, i32* %tab
101; CHECK: MayAlias:	i32* %arrayidx1, i32* %incdec.ptr.i
102; CHECK: MayAlias:	i32* %p.addr.05.i, [10 x i32]* %tab
103; CHECK: MayAlias:	i32* %p.addr.05.i, i8* %tab
104; CHECK: MayAlias:	i32* %p.addr.05.i, i32* %tab
105; CHECK: MayAlias:	i32* %arrayidx1, i32* %p.addr.05.i
106; CHECK: NoAlias:	i32* %incdec.ptr.i, i32* %p.addr.05.i
107define i32 @reverse() nounwind {
108entry:
109  %tab = alloca [10 x i32], align 4
110  %ignore1 = load [10 x i32], ptr %tab
111  %ignore2 = load i8, ptr %tab
112  store i32 0, ptr %tab, align 4
113  %arrayidx1 = getelementptr inbounds [10 x i32], ptr %tab, i32 0, i32 9
114  store i32 0, ptr %arrayidx1, align 4
115  %0 = add i32 1, 1
116  %cmp4.i = icmp slt i32 %0, 2
117  br i1 %cmp4.i, label %while.body.i, label %f.exit
118
119while.body.i: ; preds = %while.body.i, %entry
120  %1 = phi i32 [ 1, %while.body.i ], [ %0, %entry ]
121  %foo.06.i = phi i32 [ %sub.i, %while.body.i ], [ 2, %entry ]
122  %p.addr.05.i = phi ptr [ %incdec.ptr.i, %while.body.i ], [ %arrayidx1, %entry ]
123  %sub.i = sub nsw i32 %foo.06.i, %1
124  %incdec.ptr.i = getelementptr inbounds i32, ptr %p.addr.05.i, i32 -1
125  %ignore3 = load i32, ptr %incdec.ptr.i
126  store i32 %sub.i, ptr %p.addr.05.i, align 4
127  %cmp.i = icmp sgt i32 %sub.i, 1
128  br i1 %cmp.i, label %while.body.i, label %f.exit
129
130f.exit: ; preds = %entry, %while.body.i
131  %2 = load i32, ptr %arrayidx1, align 4
132  %cmp = icmp eq i32 %2, 2
133  %3 = load i32, ptr %tab, align 4
134  %cmp4 = icmp eq i32 %3, 1
135  %or.cond = and i1 %cmp, %cmp4
136  br i1 %or.cond, label %if.end, label %if.then
137
138if.then: ; preds = %f.exit
139  unreachable
140
141if.end: ; preds = %f.exit
142  ret i32 0
143}
144
145; CHECK-LABEL: Function: negative: 5 pointers, 1 call sites
146; CHECK: PartialAlias (off -4):	i16* %_tmp1, [3 x i16]* %int_arr.10
147; CHECK: MayAlias:	[3 x i16]* %int_arr.10, i16* %ls1.9.0
148; CHECK: MayAlias:	i16* %_tmp1, i16* %ls1.9.0
149; CHECK: MayAlias:	i16* %_tmp7, [3 x i16]* %int_arr.10
150; CHECK: MayAlias:	i16* %_tmp1, i16* %_tmp7
151; CHECK: NoAlias:	i16* %_tmp7, i16* %ls1.9.0
152; CHECK: PartialAlias (off -2):	i16* %_tmp11, [3 x i16]* %int_arr.10
153; CHECK: NoAlias:	i16* %_tmp1, i16* %_tmp11
154; CHECK: MayAlias:	i16* %_tmp11, i16* %ls1.9.0
155; CHECK: MayAlias:	i16* %_tmp11, i16* %_tmp7
156; CHECK: NoModRef:  Ptr: [3 x i16]* %int_arr.10	<->  %_tmp16 = call i16 @call(i32 %_tmp13)
157; CHECK: NoModRef:  Ptr: i16* %_tmp1	<->  %_tmp16 = call i16 @call(i32 %_tmp13)
158; CHECK: Both ModRef:  Ptr: i16* %ls1.9.0	<->  %_tmp16 = call i16 @call(i32 %_tmp13)
159; CHECK: Both ModRef:  Ptr: i16* %_tmp7	<->  %_tmp16 = call i16 @call(i32 %_tmp13)
160; CHECK: NoModRef:  Ptr: i16* %_tmp11	<->  %_tmp16 = call i16 @call(i32 %_tmp13)
161define i16 @negative(i16 %argc.5.par) {
162  %int_arr.10 = alloca [3 x i16], align 1
163  load [3 x i16], ptr %int_arr.10
164  %_tmp1 = getelementptr inbounds [3 x i16], ptr %int_arr.10, i16 0, i16 2
165  load i16, ptr %_tmp1
166  br label %bb1
167
168bb1:                                              ; preds = %bb1, %0
169  %i.7.0 = phi i16 [ 2, %0 ], [ %_tmp5, %bb1 ]
170  %ls1.9.0 = phi ptr [ %_tmp1, %0 ], [ %_tmp7, %bb1 ]
171  store i16 %i.7.0, ptr %ls1.9.0, align 1
172  %_tmp5 = add nsw i16 %i.7.0, -1
173  %_tmp7 = getelementptr i16, ptr %ls1.9.0, i16 -1
174  load i16, ptr %_tmp7
175  %_tmp9 = icmp sgt i16 %i.7.0, 0
176  br i1 %_tmp9, label %bb1, label %bb3
177
178bb3:                                              ; preds = %bb1
179  %_tmp11 = getelementptr inbounds [3 x i16], ptr %int_arr.10, i16 0, i16 1
180  %_tmp12 = load i16, ptr %_tmp11, align 1
181  %_tmp13 = sext i16 %_tmp12 to i32
182  %_tmp16 = call i16 @call(i32 %_tmp13)
183  %_tmp18.not = icmp eq i16 %_tmp12, 1
184  br i1 %_tmp18.not, label %bb5, label %bb4
185
186bb4:                                              ; preds = %bb3
187  ret i16 1
188
189bb5:                                              ; preds = %bb3, %bb4
190  ret i16 0
191}
192
193; CHECK-LABEL: Function: dynamic_offset
194; CHECK: NoAlias:  i8* %a, i8* %p.base
195; CHECK: MayAlias: i8* %p, i8* %p.base
196; CHECK: NoAlias:  i8* %a, i8* %p
197; CHECK: MayAlias: i8* %p.base, i8* %p.next
198; CHECK: NoAlias:  i8* %a, i8* %p.next
199; CHECK: MayAlias: i8* %p, i8* %p.next
200define void @dynamic_offset(i1 %c, ptr noalias %p.base) {
201entry:
202  %a = alloca i8
203  load i8, ptr %p.base
204  load i8, ptr %a
205  br label %loop
206
207loop:
208  %p = phi ptr [ %p.base, %entry ], [ %p.next, %loop ]
209  %offset = call i16 @call(i32 0)
210  %p.next = getelementptr inbounds i8, ptr %p, i16 %offset
211  load i8, ptr %p
212  load i8, ptr %p.next
213  br i1 %c, label %loop, label %exit
214
215exit:
216  ret void
217}
218
219; TODO: Currently yields an asymmetric result.
220; CHECK-LABEL: Function: symmetry
221; CHECK: MayAlias:  i32* %p, i32* %p.base
222; CHECK: MayAlias:  i32* %p.base, i32* %p.next
223; CHECK: NoAlias:   i32* %p, i32* %p.next
224; CHECK: MayAlias:  i32* %p.base, i32* %result
225; CHECK: NoAlias:   i32* %p, i32* %result
226; CHECK: MustAlias: i32* %p.next, i32* %result
227define ptr @symmetry(ptr %p.base, i1 %c) {
228entry:
229  load i32, ptr %p.base
230  br label %loop
231
232loop:
233  %p = phi ptr [ %p.base, %entry ], [ %p.next, %loop ]
234  %p.next = getelementptr inbounds i32, ptr %p, i32 1
235  load i32, ptr %p
236  load i32, ptr %p.next
237  br i1 %c, label %loop, label %exit
238
239exit:
240  %result = phi ptr [ %p.next, %loop ]
241  load i32, ptr %result
242  ret ptr %result
243}
244
245; FIXME: %a and %p.inner do not alias.
246; CHECK-LABEL: Function: nested_loop
247; CHECK: NoAlias:  i8* %a, i8* %p.base
248; CHECK: NoAlias:  i8* %a, i8* %p.outer
249; CHECK: MayAlias: i8* %a, i8* %p.inner
250; CHECK: NoAlias:  i8* %a, i8* %p.inner.next
251; CHECK: NoAlias:  i8* %a, i8* %p.outer.next
252define void @nested_loop(i1 %c, i1 %c2, ptr noalias %p.base) {
253entry:
254  %a = alloca i8
255  load i8, ptr %p.base
256  load i8, ptr %a
257  br label %outer_loop
258
259outer_loop:
260  %p.outer = phi ptr [ %p.base, %entry ], [ %p.outer.next, %outer_loop_latch ]
261  load i8, ptr %p.outer
262  br label %inner_loop
263
264inner_loop:
265  %p.inner = phi ptr [ %p.outer, %outer_loop ], [ %p.inner.next, %inner_loop ]
266  %p.inner.next = getelementptr inbounds i8, ptr %p.inner, i64 1
267  load i8, ptr %p.inner
268  load i8, ptr %p.inner.next
269  br i1 %c, label %inner_loop, label %outer_loop_latch
270
271outer_loop_latch:
272  %p.outer.next = getelementptr inbounds i8, ptr %p.inner, i64 10
273  load i8, ptr %p.outer.next
274  br i1 %c2, label %outer_loop, label %exit
275
276exit:
277  ret void
278}
279
280; Same as the previous test case, but avoiding phi of phi.
281; CHECK-LABEL: Function: nested_loop2
282; CHECK: NoAlias:  i8* %a, i8* %p.base
283; CHECK: NoAlias:  i8* %a, i8* %p.outer
284; CHECK: NoAlias:  i8* %a, i8* %p.outer.next
285; CHECK: MayAlias: i8* %a, i8* %p.inner
286; CHECK: NoAlias:  i8* %a, i8* %p.inner.next
287; TODO: (a, p.inner) could be NoAlias
288define void @nested_loop2(i1 %c, i1 %c2, ptr noalias %p.base) {
289entry:
290  %a = alloca i8
291  load i8, ptr %p.base
292  load i8, ptr %a
293  br label %outer_loop
294
295outer_loop:
296  %p.outer = phi ptr [ %p.base, %entry ], [ %p.outer.next, %outer_loop_latch ]
297  %p.outer.next = getelementptr inbounds i8, ptr %p.outer, i64 10
298  load i8, ptr %p.outer
299  load i8, ptr %p.outer.next
300  br label %inner_loop
301
302inner_loop:
303  %p.inner = phi ptr [ %p.outer.next, %outer_loop ], [ %p.inner.next, %inner_loop ]
304  %p.inner.next = getelementptr inbounds i8, ptr %p.inner, i64 1
305  load i8, ptr %p.inner
306  load i8, ptr %p.inner.next
307  br i1 %c, label %inner_loop, label %outer_loop_latch
308
309outer_loop_latch:
310  br i1 %c2, label %outer_loop, label %exit
311
312exit:
313  ret void
314}
315
316; CHECK-LABEL: Function: nested_loop3
317; CHECK: NoAlias:	i8* %a, i8* %p.base
318; CHECK: NoAlias:	i8* %a, i8* %p.outer
319; CHECK: NoAlias:	i8* %a, i8* %p.outer.next
320; CHECK: NoAlias:	i8* %a, i8* %p.inner
321; CHECK: NoAlias:	i8* %a, i8* %p.inner.next
322define void @nested_loop3(i1 %c, i1 %c2, ptr noalias %p.base) {
323entry:
324  %a = alloca i8
325  load i8, ptr %p.base
326  load i8, ptr %a
327  br label %outer_loop
328
329outer_loop:
330  %p.outer = phi ptr [ %p.base, %entry ], [ %p.outer.next, %outer_loop_latch ]
331  %p.outer.next = getelementptr inbounds i8, ptr %p.outer, i64 10
332  load i8, ptr %p.outer
333  load i8, ptr %p.outer.next
334  br label %inner_loop
335
336inner_loop:
337  %p.inner = phi ptr [ %p.outer, %outer_loop ], [ %p.inner.next, %inner_loop ]
338  %p.inner.next = getelementptr inbounds i8, ptr %p.inner, i64 1
339  load i8, ptr %p.inner
340  load i8, ptr %p.inner.next
341  br i1 %c, label %inner_loop, label %outer_loop_latch
342
343outer_loop_latch:
344  br i1 %c2, label %outer_loop, label %exit
345
346exit:
347  ret void
348}
349
350; CHECK-LABEL: Function: sibling_loop
351; CHECK: NoAlias:	i8* %a, i8* %p.base
352; CHECK: NoAlias:	i8* %a, i8* %p1
353; CHECK: NoAlias:	i8* %a, i8* %p1.next
354; CHECK: MayAlias:	i8* %a, i8* %p2
355; CHECK: NoAlias:	i8* %a, i8* %p2.next
356; TODO: %p2 does not alias %a
357define void @sibling_loop(i1 %c, i1 %c2, ptr noalias %p.base) {
358entry:
359  %a = alloca i8
360  load i8, ptr %p.base
361  load i8, ptr %a
362  br label %loop1
363
364loop1:
365  %p1 = phi ptr [ %p.base, %entry ], [ %p1.next, %loop1 ]
366  %p1.next = getelementptr inbounds i8, ptr %p1, i64 10
367  load i8, ptr %p1
368  load i8, ptr %p1.next
369  br i1 %c, label %loop1, label %loop2
370
371loop2:
372  %p2 = phi ptr [ %p1.next, %loop1 ], [ %p2.next, %loop2 ]
373  %p2.next = getelementptr inbounds i8, ptr %p2, i64 1
374  load i8, ptr %p2
375  load i8, ptr %p2.next
376  br i1 %c2, label %loop2, label %exit
377
378exit:
379  ret void
380}
381
382; CHECK-LABEL: Function: sibling_loop2
383; CHECK: NoAlias:	i8* %a, i8* %p.base
384; CHECK: NoAlias:	i8* %a, i8* %p1
385; CHECK: NoAlias:	i8* %a, i8* %p1.next
386; CHECK: NoAlias:	i8* %a, i8* %p2
387; CHECK: NoAlias:	i8* %a, i8* %p2.next
388define void @sibling_loop2(i1 %c, i1 %c2, ptr noalias %p.base) {
389entry:
390  %a = alloca i8
391  load i8, ptr %p.base
392  load i8, ptr %a
393  br label %loop1
394
395loop1:
396  %p1 = phi ptr [ %p.base, %entry ], [ %p1.next, %loop1 ]
397  %p1.next = getelementptr inbounds i8, ptr %p1, i64 10
398  load i8, ptr %p1
399  load i8, ptr %p1.next
400  br i1 %c, label %loop1, label %loop2
401
402loop2:
403  %p2 = phi ptr [ %p1, %loop1 ], [ %p2.next, %loop2 ]
404  %p2.next = getelementptr inbounds i8, ptr %p2, i64 1
405  load i8, ptr %p2
406  load i8, ptr %p2.next
407  br i1 %c2, label %loop2, label %exit
408
409exit:
410  ret void
411}
412
413; CHECK: MustAlias: i8* %a, i8* %phi
414define void @phi_contains_self() {
415entry:
416  %a = alloca i32
417  load i8, ptr %a
418  br label %loop
419
420loop:
421  %phi = phi ptr [ %phi, %loop ], [ %a, %entry ]
422  load i8, ptr %phi
423  br label %loop
424}
425
426declare i16 @call(i32)
427