[gn build] Port 077cc3deeebe
[llvm-project.git] / llvm / test / Transforms / InstSimplify / cmp-alloca-offsets.ll
blobc0b25800a68e59201cb09931d6d9d1c25c28352a
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
3 target datalayout = "p:32:32-p1:64:64"
5 ; This is a collection of tests checking whether we can prove pointers
6 ; derived from two allocas as inequal *via offset checks*.  Note that
7 ; instcombine has alternate approaches (one cmp rule, and compare
8 ; bases of common offset) that also handles these, but with different
9 ; logic.
11 ; %a follows %b, derived equal
12 define i1 @adjacent_alloca() {
13 ; CHECK-LABEL: @adjacent_alloca(
14 ; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
15 ; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
16 ; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 4
17 ; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A]], [[B_OFF]]
18 ; CHECK-NEXT:    ret i1 [[RES]]
20   %a = alloca i8, i32 4
21   %b = alloca i8, i32 4
22   %b.off = getelementptr i8, ptr %b, i64 4
23   %res = icmp ne ptr %a, %b.off
24   ret i1 %res
27 ; %b follows %a, derived equal
28 define i1 @adjacent_alloca2() {
29 ; CHECK-LABEL: @adjacent_alloca2(
30 ; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
31 ; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
32 ; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 4
33 ; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B]]
34 ; CHECK-NEXT:    ret i1 [[RES]]
36   %a = alloca i8, i32 4
37   %b = alloca i8, i32 4
38   %a.off = getelementptr i8, ptr %a, i64 4
39   %res = icmp ne ptr %a.off, %b
40   ret i1 %res
43 define i1 @positive_non_equal_end() {
44 ; CHECK-LABEL: @positive_non_equal_end(
45 ; CHECK-NEXT:    ret i1 true
47   %a = alloca i8, i32 4
48   %b = alloca i8, i32 4
49   %a.off = getelementptr i8, ptr %a, i64 4
50   %b.off = getelementptr i8, ptr %b, i64 4
51   %res = icmp ne ptr %a.off, %b.off
52   ret i1 %res
55 ; %b follows %a, derived equal
56 define i1 @positive_equal_past_end() {
57 ; CHECK-LABEL: @positive_equal_past_end(
58 ; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
59 ; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
60 ; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 8
61 ; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 12
62 ; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
63 ; CHECK-NEXT:    ret i1 [[RES]]
65   %a = alloca i8, i32 4
66   %b = alloca i8, i32 4
67   %a.off = getelementptr i8, ptr %a, i64 8
68   %b.off = getelementptr i8, ptr %b, i64 12
69   %res = icmp ne ptr %a.off, %b.off
70   ret i1 %res
73 define i1 @positive_non_equal() {
74 ; CHECK-LABEL: @positive_non_equal(
75 ; CHECK-NEXT:    ret i1 true
77   %a = alloca i8, i32 4
78   %b = alloca i8, i32 4
79   %a.off = getelementptr i8, ptr %a, i64 3
80   %b.off = getelementptr i8, ptr %b, i64 3
81   %res = icmp ne ptr %a.off, %b.off
82   ret i1 %res
85 ; %a follows %b, derived equal
86 define i1 @one_neg_equal1() {
87 ; CHECK-LABEL: @one_neg_equal1(
88 ; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
89 ; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
90 ; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 -1
91 ; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 3
92 ; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
93 ; CHECK-NEXT:    ret i1 [[RES]]
95   %a = alloca i8, i32 4
96   %b = alloca i8, i32 4
97   %a.off = getelementptr i8, ptr %a, i64 -1
98   %b.off = getelementptr i8, ptr %b, i64 3
99   %res = icmp ne ptr %a.off, %b.off
100   ret i1 %res
103 ; %b follows %a, derived equal
104 define i1 @one_neg_equal2() {
105 ; CHECK-LABEL: @one_neg_equal2(
106 ; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
107 ; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
108 ; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 3
109 ; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 -1
110 ; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
111 ; CHECK-NEXT:    ret i1 [[RES]]
113   %a = alloca i8, i32 4
114   %b = alloca i8, i32 4
115   %a.off = getelementptr i8, ptr %a, i64 3
116   %b.off = getelementptr i8, ptr %b, i64 -1
117   %res = icmp ne ptr %a.off, %b.off
118   ret i1 %res
121 ; %b follows %a, derived equal
122 define i1 @both_neg_equal() {
123 ; CHECK-LABEL: @both_neg_equal(
124 ; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
125 ; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
126 ; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 -4
127 ; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 -8
128 ; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
129 ; CHECK-NEXT:    ret i1 [[RES]]
131   %a = alloca i8, i32 4
132   %b = alloca i8, i32 4
133   %a.off = getelementptr i8, ptr %a, i64 -4
134   %b.off = getelementptr i8, ptr %b, i64 -8
135   %res = icmp ne ptr %a.off, %b.off
136   ret i1 %res
139 define i1 @mixed_offsets1() {
140 ; CHECK-LABEL: @mixed_offsets1(
141 ; CHECK-NEXT:    ret i1 true
143   %a = alloca i8, i32 4
144   %b = alloca i8, i32 4
145   %a.off = getelementptr i8, ptr %a, i64 -1
146   %b.off = getelementptr i8, ptr %b, i64 2
147   %res = icmp ne ptr %a.off, %b.off
148   ret i1 %res
151 define i1 @mixed_offsets2() {
152 ; CHECK-LABEL: @mixed_offsets2(
153 ; CHECK-NEXT:    ret i1 true
155   %a = alloca i8, i32 4
156   %b = alloca i8, i32 4
157   %a.off = getelementptr i8, ptr %a, i64 1
158   %b.off = getelementptr i8, ptr %b, i64 -2
159   %res = icmp ne ptr %a.off, %b.off
160   ret i1 %res
163 define i1 @negative_in_other() {
164 ; CHECK-LABEL: @negative_in_other(
165 ; CHECK-NEXT:    ret i1 true
167   %a = alloca i8, i32 4
168   %b = alloca i8, i32 4
169   %a.off = getelementptr i8, ptr %a, i64 -3
170   %b.off = getelementptr i8, ptr %b, i64 -2
171   %res = icmp ne ptr %a.off, %b.off
172   ret i1 %res
175 define i1 @mixed_alloca_size1() {
176 ; CHECK-LABEL: @mixed_alloca_size1(
177 ; CHECK-NEXT:    ret i1 true
179   %a = alloca i8, i32 2
180   %b = alloca i8, i32 4
181   %a.off = getelementptr i8, ptr %a, i64 1
182   %b.off = getelementptr i8, ptr %b, i64 3
183   %res = icmp ne ptr %a.off, %b.off
184   ret i1 %res
187 define i1 @mixed_alloca_size2() {
188 ; CHECK-LABEL: @mixed_alloca_size2(
189 ; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
190 ; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 2, align 1
191 ; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 1
192 ; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 3
193 ; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
194 ; CHECK-NEXT:    ret i1 [[RES]]
196   %a = alloca i8, i32 4
197   %b = alloca i8, i32 2
198   %a.off = getelementptr i8, ptr %a, i64 1
199   %b.off = getelementptr i8, ptr %b, i64 3
200   %res = icmp ne ptr %a.off, %b.off
201   ret i1 %res
204 define i1 @mixed_alloca_size3() {
205 ; CHECK-LABEL: @mixed_alloca_size3(
206 ; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 2, align 1
207 ; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
208 ; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 -1
209 ; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 -3
210 ; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
211 ; CHECK-NEXT:    ret i1 [[RES]]
213   %a = alloca i8, i32 2
214   %b = alloca i8, i32 4
215   %a.off = getelementptr i8, ptr %a, i64 -1
216   %b.off = getelementptr i8, ptr %b, i64 -3
217   %res = icmp ne ptr %a.off, %b.off
218   ret i1 %res
221 define i1 @mixed_alloca_size4() {
222 ; CHECK-LABEL: @mixed_alloca_size4(
223 ; CHECK-NEXT:    ret i1 true
225   %a = alloca i8, i32 4
226   %b = alloca i8, i32 2
227   %a.off = getelementptr i8, ptr %a, i64 -1
228   %b.off = getelementptr i8, ptr %b, i64 -3
229   %res = icmp ne ptr %a.off, %b.off
230   ret i1 %res
233 define i1 @zst_alloca_start() {
234 ; CHECK-LABEL: @zst_alloca_start(
235 ; CHECK-NEXT:    [[A:%.*]] = alloca i64, align 8
236 ; CHECK-NEXT:    [[A2:%.*]] = alloca {}, align 1
237 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[A]], [[A2]]
238 ; CHECK-NEXT:    call void @escape(ptr [[A]], ptr [[A2]])
239 ; CHECK-NEXT:    ret i1 [[CMP]]
241   %a = alloca i64
242   %a2 = alloca {}, align 1
243   %gep = getelementptr i8, ptr %a, i64 0
244   %cmp = icmp eq ptr %gep, %a2
245   call void @escape(ptr %a, ptr %a2)
246   ret i1 %cmp
249 define i1 @zst_alloca_middle() {
250 ; CHECK-LABEL: @zst_alloca_middle(
251 ; CHECK-NEXT:    [[A:%.*]] = alloca i64, align 8
252 ; CHECK-NEXT:    [[A2:%.*]] = alloca {}, align 1
253 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[A]], i64 4
254 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[GEP]], [[A2]]
255 ; CHECK-NEXT:    call void @escape(ptr [[A]], ptr [[A2]])
256 ; CHECK-NEXT:    ret i1 [[CMP]]
258   %a = alloca i64
259   %a2 = alloca {}, align 1
260   %gep = getelementptr i8, ptr %a, i64 4
261   %cmp = icmp eq ptr %gep, %a2
262   call void @escape(ptr %a, ptr %a2)
263   ret i1 %cmp
266 define i1 @zst_alloca_end() {
267 ; CHECK-LABEL: @zst_alloca_end(
268 ; CHECK-NEXT:    [[A:%.*]] = alloca i64, align 8
269 ; CHECK-NEXT:    [[A2:%.*]] = alloca {}, align 1
270 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[A]], i64 8
271 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[GEP]], [[A2]]
272 ; CHECK-NEXT:    call void @escape(ptr [[A]], ptr [[A2]])
273 ; CHECK-NEXT:    ret i1 [[CMP]]
275   %a = alloca i64
276   %a2 = alloca {}, align 1
277   %gep = getelementptr i8, ptr %a, i64 8
278   %cmp = icmp eq ptr %gep, %a2
279   call void @escape(ptr %a, ptr %a2)
280   ret i1 %cmp
283 @gz = external global {}, align 1
285 define i1 @zst_global_start() {
286 ; CHECK-LABEL: @zst_global_start(
287 ; CHECK-NEXT:    [[A:%.*]] = alloca i64, align 8
288 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[A]], @gz
289 ; CHECK-NEXT:    call void @escape(ptr [[A]], ptr @gz)
290 ; CHECK-NEXT:    ret i1 [[CMP]]
292   %a = alloca i64
293   %gep = getelementptr i8, ptr %a, i64 0
294   %cmp = icmp eq ptr %gep, @gz
295   call void @escape(ptr %a, ptr @gz)
296   ret i1 %cmp
299 define i1 @zst_global_middle() {
300 ; CHECK-LABEL: @zst_global_middle(
301 ; CHECK-NEXT:    [[A:%.*]] = alloca i64, align 8
302 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[A]], i64 4
303 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[GEP]], @gz
304 ; CHECK-NEXT:    call void @escape(ptr [[A]], ptr @gz)
305 ; CHECK-NEXT:    ret i1 [[CMP]]
307   %a = alloca i64
308   %gep = getelementptr i8, ptr %a, i64 4
309   %cmp = icmp eq ptr %gep, @gz
310   call void @escape(ptr %a, ptr @gz)
311   ret i1 %cmp
314 define i1 @zst_global_end() {
315 ; CHECK-LABEL: @zst_global_end(
316 ; CHECK-NEXT:    [[A:%.*]] = alloca i64, align 8
317 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[A]], i64 8
318 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[GEP]], @gz
319 ; CHECK-NEXT:    call void @escape(ptr [[A]], ptr @gz)
320 ; CHECK-NEXT:    ret i1 [[CMP]]
322   %a = alloca i64
323   %gep = getelementptr i8, ptr %a, i64 8
324   %cmp = icmp eq ptr %gep, @gz
325   call void @escape(ptr %a, ptr @gz)
326   ret i1 %cmp
329 declare void @escape(ptr, ptr)
331 attributes #0 = { null_pointer_is_valid }