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