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
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]]
22 %b.off = getelementptr i8, ptr %b, i64 4
23 %res = icmp ne ptr %a, %b.off
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]]
38 %a.off = getelementptr i8, ptr %a, i64 4
39 %res = icmp ne ptr %a.off, %b
43 define i1 @positive_non_equal_end() {
44 ; CHECK-LABEL: @positive_non_equal_end(
45 ; CHECK-NEXT: ret i1 true
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
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]]
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
73 define i1 @positive_non_equal() {
74 ; CHECK-LABEL: @positive_non_equal(
75 ; CHECK-NEXT: ret i1 true
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
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]]
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
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
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
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
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
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
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
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
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
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
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]]
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)
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]]
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)
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]]
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)
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]]
293 %gep = getelementptr i8, ptr %a, i64 0
294 %cmp = icmp eq ptr %gep, @gz
295 call void @escape(ptr %a, ptr @gz)
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]]
308 %gep = getelementptr i8, ptr %a, i64 4
309 %cmp = icmp eq ptr %gep, @gz
310 call void @escape(ptr %a, ptr @gz)
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]]
323 %gep = getelementptr i8, ptr %a, i64 8
324 %cmp = icmp eq ptr %gep, @gz
325 call void @escape(ptr %a, ptr @gz)
329 declare void @escape(ptr, ptr)
331 attributes #0 = { null_pointer_is_valid }