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