xref: /llvm-project/llvm/test/Analysis/BasicAA/range.ll (revision 4a2a6a4111035b4ccd0dce9e6445006f003b88e3)
1; RUN: opt < %s -aa-pipeline=basic-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
2
3%struct.S = type { i32, [2 x i32], i32 }
4%struct.S2 = type { i32, [4 x i32], [4 x i32] }
5@G = global [10 x i32] zeroinitializer, align 4
6
7; CHECK: Function: t1
8; CHECK: NoAlias: i32* %gep1, i32* %gep2
9define void @t1(ptr %s) {
10  %gep1 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 1
11  %gep2 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 0
12  load i32, ptr %gep1
13  load i32, ptr %gep2
14  ret void
15}
16
17; CHECK: Function: t2_fwd
18; CHECK: MayAlias: i32* %gep1, i32* %gep2
19define void @t2_fwd(ptr %s, ptr %q) {
20  %in_array = load i32, ptr %q, !range !0
21  %gep1 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 %in_array
22  %gep2 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 0
23  load i32, ptr %gep1
24  load i32, ptr %gep2
25  ret void
26}
27
28; CHECK: Function: t2_rev
29; CHECK: MayAlias: i32* %gep1, i32* %gep2
30define void @t2_rev(ptr %s, ptr %q) {
31  %in_array = load i32, ptr %q, !range !0
32  %gep1 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 0
33  %gep2 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 %in_array
34  load i32, ptr %gep1
35  load i32, ptr %gep2
36  ret void
37}
38
39; CHECK: Function: t3_fwd
40; CHECK: NoAlias: i32* %gep1, i32* %gep2
41define void @t3_fwd(ptr %s, ptr %q) {
42  %knownzero = load i32, ptr %q, !range !1
43  %gep1 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 %knownzero
44  %gep2 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 1
45  load i32, ptr %gep1
46  load i32, ptr %gep2
47  ret void
48}
49
50; CHECK: Function: t3_rev
51; CHECK: NoAlias: i32* %gep1, i32* %gep2
52define void @t3_rev(ptr %s, ptr %q) {
53  %knownzero = load i32, ptr %q, !range !1
54  %gep1 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 1
55  %gep2 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 %knownzero
56  load i32, ptr %gep1
57  load i32, ptr %gep2
58  ret void
59}
60
61; CHECK: Function: member_after
62; CHECK: NoAlias: i32* %gep1, i32* %gep2
63define void @member_after(ptr %s, ptr %q) {
64  %in_array = load i32, ptr %q, !range !0
65  %gep1 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 %in_array
66  %gep2 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 2
67  load i32, ptr %gep1
68  load i32, ptr %gep2
69  ret void
70}
71
72; CHECK: Function: member_after_rev
73; CHECK: NoAlias: i32* %gep1, i32* %gep2
74define void @member_after_rev(ptr %s, ptr %q) {
75  %in_array = load i32, ptr %q, !range !0
76  %gep2 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 2
77  %gep1 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 %in_array
78  load i32, ptr %gep1
79  load i32, ptr %gep2
80  ret void
81}
82
83; CHECK: Function: member_before
84; CHECK: NoAlias: i32* %gep1, i32* %s
85define void @member_before(ptr %s, ptr %q) {
86  %in_array = load i32, ptr %q, !range !0
87  %gep1 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 %in_array
88  load i32, ptr %gep1
89  load i32, ptr %s
90  ret void
91}
92
93; CHECK: Function: member_before_rev
94; CHECK: NoAlias: i32* %gep1, i32* %s
95define void @member_before_rev(ptr %s, ptr %q) {
96  %in_array = load i32, ptr %q, !range !0
97  %gep1 = getelementptr inbounds %struct.S, ptr %s, i64 0, i32 1, i32 %in_array
98  load i32, ptr %gep1
99  load i32, ptr %s
100  ret void
101}
102
103; CHECK-LABEL: Function: t5
104; CHECK: MayAlias: i32* %gep1, %struct.S2* %s
105; CHECK: PartialAlias (off -4): i32* %gep2, %struct.S2* %s
106; CHECK: NoAlias: i32* %gep1, i32* %gep2
107define void @t5(ptr %s, ptr %q) {
108  %in_array = load i32, ptr %q, !range !3
109  %gep1 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 2, i32 %in_array
110  %gep2 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 1, i32 0
111  load %struct.S2, ptr %s
112  load i32, ptr %gep1
113  load i32, ptr %gep2
114  ret void
115}
116
117; CHECK-LABEL: Function: t6
118; CHECK: MayAlias: i32* %gep1, %struct.S2* %s
119; CHECK: PartialAlias (off -16): i32* %gep2, %struct.S2* %s
120; CHECK: MayAlias: i32* %gep1, i32* %gep2
121define void @t6(ptr %s, ptr %q) {
122  %in_array = load i32, ptr %q, !range !3
123  %gep1 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 2, i32 %in_array
124  %gep2 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 1, i32 3
125  load %struct.S2, ptr %s
126  load i32, ptr %gep1
127  load i32, ptr %gep2
128  ret void
129}
130
131; CHECK-LABEL: Function: t7
132; CHECK: MayAlias: i32* %gep1, %struct.S2* %s
133; CHECK: PartialAlias (off -20): i32* %gep2, %struct.S2* %s
134; CHECK: NoAlias: i32* %gep1, i32* %gep2
135define void @t7(ptr %s, ptr %q) {
136  %in_array = load i32, ptr %q, !range !4
137  %gep1 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 2, i32 %in_array
138  %gep2 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 2, i32 0
139  load %struct.S2, ptr %s
140  load i32, ptr %gep1
141  load i32, ptr %gep2
142  ret void
143}
144
145; CHECK-LABEL: Function: t8
146; CHECK: MayAlias: i32* %gep1, %struct.S2* %s
147; CHECK: PartialAlias (off -24): i32* %gep2, %struct.S2* %s
148; CHECK: MayAlias: i32* %gep1, i32* %gep2
149define void @t8(ptr %s, ptr %q) {
150  %in_array = load i32, ptr %q, !range !4
151  %gep1 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 2, i32 %in_array
152  %gep2 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 2, i32 1
153  load %struct.S2, ptr %s
154  load i32, ptr %q
155  load i32, ptr %gep1
156  load i32, ptr %gep2
157  ret void
158}
159
160; CHECK-LABEL: Function: t9
161; CHECK: MayAlias: i32* %gep1, %struct.S2* %s
162; CHECK: PartialAlias (off -20): i32* %gep2, %struct.S2* %s
163; CHECK: NoAlias: i32* %gep1, i32* %gep2
164define void @t9(ptr %s, ptr %q) {
165  %in_array = load i32, ptr %q, !range !5
166  %gep1 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 1, i32 %in_array
167  %gep2 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 2, i32 0
168  load %struct.S2, ptr %s
169  load i32, ptr %gep1
170  load i32, ptr %gep2
171  ret void
172}
173
174; CHECK-LABEL: Function: t10
175; CHECK: MayAlias: i32* %gep1, %struct.S2* %s
176; CHECK: PartialAlias (off -4): i32* %gep2, %struct.S2* %s
177; CHECK: MayAlias: i32* %gep1, i32* %gep2
178define void @t10(ptr %s, ptr %q) {
179  %in_array = load i32, ptr %q, !range !5
180  %gep1 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 2, i32 %in_array
181  %gep2 = getelementptr inbounds %struct.S2, ptr %s, i64 0, i32 1, i32 0
182  load %struct.S2, ptr %s
183  load i32, ptr %gep1
184  load i32, ptr %gep2
185  ret void
186}
187
188; CHECK-LABEL: Function: zeroext_index
189; CHECK:  MayAlias:     i32* %gep, [256 x i32]* %s
190define void @zeroext_index(ptr %s, ptr %q) {
191  %a = load i8, ptr %q, !range !6
192  %in_array = zext i8 %a to i32
193  %gep = getelementptr inbounds [256 x i32], ptr %s, i64 0, i32 %in_array
194  load [256 x i32], ptr %s
195  load i32, ptr %gep
196  ret void
197}
198
199; CHECK-LABEL: Function: multiple
200; CHECK: MayAlias: i32* %p, i32* %p.01
201; CHECK: MayAlias: i32* %p, i32* %p.02
202; CHECK: MayAlias: i32* %p.01, i32* %p.02
203; CHECK: NoAlias:  i32* %p.01, i32* %p.2
204; CHECK: MayAlias: i32* %p.02, i32* %p.2
205; CHECK: NoAlias:  i32* %p.01, i32* %p.3
206; CHECK: NoAlias:  i32* %p.02, i32* %p.3
207define void @multiple(ptr %p, ptr %o1_ptr, ptr %o2_ptr) {
208  %o1 = load i32, ptr %o1_ptr, !range !0
209  %o2 = load i32, ptr %o2_ptr, !range !0
210  %p.01 = getelementptr i32, ptr %p, i32 %o1  ; p + [0, 1]
211  %p.02 = getelementptr i32, ptr %p.01, i32 %o2 ; p + [0, 2]
212  %p.2 = getelementptr i32, ptr %p, i32 2
213  %p.3 = getelementptr i32, ptr %p, i32 3
214  load i32, ptr %p
215  load i32, ptr %p.01
216  load i32, ptr %p.02
217  load i32, ptr %p.2
218  load i32, ptr %p.3
219  ret void
220}
221
222; p.neg1 and p.o.1 don't alias, even though the addition o+1 may overflow.
223; While it makes INT_MIN a possible offset, offset -1 is not possible.
224; CHECK-LABEL: Function: benign_overflow
225; CHECK: MayAlias: i8* %p, i8* %p.o
226; CHECK: MayAlias: i8* %p.neg1, i8* %p.o
227; CHECK: MayAlias: i8* %p, i8* %p.o.1
228; CHECK: NoAlias: i8* %p.neg1, i8* %p.o.1
229; CHECK: NoAlias:  i8* %p.o, i8* %p.o.1
230define void @benign_overflow(ptr %p, i64 %o) {
231  %c = icmp sge i64 %o, -1
232  call void @llvm.assume(i1 %c)
233  %p.neg1 = getelementptr i8, ptr %p, i64 -1
234  %p.o = getelementptr i8, ptr %p, i64 %o
235  %p.o.1 = getelementptr i8, ptr %p.o, i64 1
236  load i8, ptr %p
237  load i8, ptr %p.neg1
238  load i8, ptr %p.o
239  load i8, ptr %p.o.1
240  ret void
241}
242
243; CHECK-LABEL: pr63266
244; CHECK: MayAlias:	i8* %gep2, i8* %offset16
245define void @pr63266(i1 %c, ptr %base) {
246entry:
247  %offset16 = getelementptr inbounds i8, ptr %base, i64 16
248  %gep1 = getelementptr i8, ptr %base, i64 -9223372036854775792
249  br i1 %c, label %if, label %join
250
251if:
252  br label %join
253
254join:
255  %phi = phi i64 [ -9223372036854775808, %if ], [ 0, %entry ]
256  %gep2 = getelementptr i8, ptr %gep1, i64 %phi
257  store i8 0, ptr %gep2
258  load i8, ptr %offset16
259  ret void
260}
261
262
263; CHECK-LABEL: Function: select_in_gep
264; CHECK: NoAlias: i32* %arrayidx, i32* getelementptr inbounds ([10 x i32], ptr @G, i64 0, i64 3)
265define i32 @select_in_gep(i1 %c)  {
266entry:
267  %select_ = select i1 %c, i64 2, i64 1
268  %arrayidx = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select_
269  store i32 42, ptr %arrayidx, align 4
270  %load_ = load i32, ptr getelementptr inbounds ([10 x i32], ptr @G, i64 0, i64 3), align 4
271  ret i32 %load_
272}
273
274declare void @llvm.assume(i1)
275
276!0 = !{ i32 0, i32 2 }
277!1 = !{ i32 0, i32 1 }
278!2 = !{ i32 1, i32 2 }
279!3 = !{ i32 -2, i32 0 }
280!4 = !{ i32 1, i32 536870911 }
281!5 = !{ i32 -536870911, i32 4 }
282!6 = !{ i8 -2, i8 0 }
283