1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -instcombine -S | FileCheck %s
4 ; Here we subtract two values, check that subtraction did not overflow AND
5 ; that the result is non-zero. This can be simplified just to a comparison
6 ; between the base and offset.
9 declare void @use64(i64)
10 declare void @use1(i1)
12 declare {i8, i1} @llvm.usub.with.overflow(i8, i8)
13 declare void @useagg({i8, i1})
15 declare void @llvm.assume(i1)
17 ; There is a number of base patterns..
19 define i1 @t0_noncanonical_ignoreme(i8 %base, i8 %offset) {
20 ; CHECK-LABEL: @t0_noncanonical_ignoreme(
21 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
22 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
23 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
24 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
25 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
26 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
27 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
28 ; CHECK-NEXT: ret i1 [[TMP1]]
30 %adjusted = sub i8 %base, %offset
31 call void @use8(i8 %adjusted)
32 %no_underflow = icmp ule i8 %adjusted, %base
33 call void @use1(i1 %no_underflow)
34 %not_null = icmp ne i8 %adjusted, 0
35 call void @use1(i1 %not_null)
36 %r = and i1 %not_null, %no_underflow
40 define i1 @t0_noncanonical_ignoreme_logical(i8 %base, i8 %offset) {
41 ; CHECK-LABEL: @t0_noncanonical_ignoreme_logical(
42 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
43 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
44 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
45 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
46 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
47 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
48 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
49 ; CHECK-NEXT: ret i1 [[TMP1]]
51 %adjusted = sub i8 %base, %offset
52 call void @use8(i8 %adjusted)
53 %no_underflow = icmp ule i8 %adjusted, %base
54 call void @use1(i1 %no_underflow)
55 %not_null = icmp ne i8 %adjusted, 0
56 call void @use1(i1 %not_null)
57 %r = select i1 %not_null, i1 %no_underflow, i1 false
61 define i1 @t1(i8 %base, i8 %offset) {
63 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
64 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
65 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
66 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
67 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
68 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
69 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
70 ; CHECK-NEXT: ret i1 [[TMP1]]
72 %adjusted = sub i8 %base, %offset
73 call void @use8(i8 %adjusted)
74 %no_underflow = icmp uge i8 %base, %offset
75 call void @use1(i1 %no_underflow)
76 %not_null = icmp ne i8 %adjusted, 0
77 call void @use1(i1 %not_null)
78 %r = and i1 %not_null, %no_underflow
82 define i1 @t1_logical(i8 %base, i8 %offset) {
83 ; CHECK-LABEL: @t1_logical(
84 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
85 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
86 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
87 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
88 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
89 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
90 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
91 ; CHECK-NEXT: ret i1 [[TMP1]]
93 %adjusted = sub i8 %base, %offset
94 call void @use8(i8 %adjusted)
95 %no_underflow = icmp uge i8 %base, %offset
96 call void @use1(i1 %no_underflow)
97 %not_null = icmp ne i8 %adjusted, 0
98 call void @use1(i1 %not_null)
99 %r = select i1 %not_null, i1 %no_underflow, i1 false
102 define i1 @t1_strict(i8 %base, i8 %offset) {
103 ; CHECK-LABEL: @t1_strict(
104 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
105 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
106 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
107 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
108 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
109 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
110 ; CHECK-NEXT: ret i1 [[NO_UNDERFLOW]]
112 %adjusted = sub i8 %base, %offset
113 call void @use8(i8 %adjusted)
114 %no_underflow = icmp ugt i8 %base, %offset ; same is valid for strict predicate
115 call void @use1(i1 %no_underflow)
116 %not_null = icmp ne i8 %adjusted, 0
117 call void @use1(i1 %not_null)
118 %r = and i1 %not_null, %no_underflow
122 define i1 @t1_strict_logical(i8 %base, i8 %offset) {
123 ; CHECK-LABEL: @t1_strict_logical(
124 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
125 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
126 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
127 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
128 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
129 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
130 ; CHECK-NEXT: ret i1 [[NO_UNDERFLOW]]
132 %adjusted = sub i8 %base, %offset
133 call void @use8(i8 %adjusted)
134 %no_underflow = icmp ugt i8 %base, %offset ; same is valid for strict predicate
135 call void @use1(i1 %no_underflow)
136 %not_null = icmp ne i8 %adjusted, 0
137 call void @use1(i1 %not_null)
138 %r = select i1 %not_null, i1 %no_underflow, i1 false
142 define i1 @t2(i8 %base, i8 %offset) {
144 ; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]])
145 ; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]])
146 ; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0
147 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
148 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1
149 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
150 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = xor i1 [[UNDERFLOW]], true
151 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
152 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
153 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
154 ; CHECK-NEXT: ret i1 [[R]]
156 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset)
157 call void @useagg({i8, i1} %agg)
158 %adjusted = extractvalue {i8, i1} %agg, 0
159 call void @use8(i8 %adjusted)
160 %underflow = extractvalue {i8, i1} %agg, 1
161 call void @use1(i1 %underflow)
162 %no_underflow = xor i1 %underflow, -1
163 call void @use1(i1 %no_underflow)
164 %not_null = icmp ne i8 %adjusted, 0
165 %r = and i1 %not_null, %no_underflow
169 define i1 @t2_logical(i8 %base, i8 %offset) {
170 ; CHECK-LABEL: @t2_logical(
171 ; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]])
172 ; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]])
173 ; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0
174 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
175 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1
176 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
177 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = xor i1 [[UNDERFLOW]], true
178 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
179 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
180 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
181 ; CHECK-NEXT: ret i1 [[R]]
183 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset)
184 call void @useagg({i8, i1} %agg)
185 %adjusted = extractvalue {i8, i1} %agg, 0
186 call void @use8(i8 %adjusted)
187 %underflow = extractvalue {i8, i1} %agg, 1
188 call void @use1(i1 %underflow)
189 %no_underflow = xor i1 %underflow, -1
190 call void @use1(i1 %no_underflow)
191 %not_null = icmp ne i8 %adjusted, 0
192 %r = select i1 %not_null, i1 %no_underflow, i1 false
198 define i1 @t3_commutability0(i8 %base, i8 %offset) {
199 ; CHECK-LABEL: @t3_commutability0(
200 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
201 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
202 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
203 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
204 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
205 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
206 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
207 ; CHECK-NEXT: ret i1 [[TMP1]]
209 %adjusted = sub i8 %base, %offset
210 call void @use8(i8 %adjusted)
211 %no_underflow = icmp ule i8 %offset, %base ; swapped
212 call void @use1(i1 %no_underflow)
213 %not_null = icmp ne i8 %adjusted, 0
214 call void @use1(i1 %not_null)
215 %r = and i1 %not_null, %no_underflow
219 define i1 @t3_commutability0_logical(i8 %base, i8 %offset) {
220 ; CHECK-LABEL: @t3_commutability0_logical(
221 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
222 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
223 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
224 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
225 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
226 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
227 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
228 ; CHECK-NEXT: ret i1 [[TMP1]]
230 %adjusted = sub i8 %base, %offset
231 call void @use8(i8 %adjusted)
232 %no_underflow = icmp ule i8 %offset, %base ; swapped
233 call void @use1(i1 %no_underflow)
234 %not_null = icmp ne i8 %adjusted, 0
235 call void @use1(i1 %not_null)
236 %r = select i1 %not_null, i1 %no_underflow, i1 false
239 define i1 @t4_commutability1(i8 %base, i8 %offset) {
240 ; CHECK-LABEL: @t4_commutability1(
241 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
242 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
243 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
244 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
245 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
246 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
247 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
248 ; CHECK-NEXT: ret i1 [[TMP1]]
250 %adjusted = sub i8 %base, %offset
251 call void @use8(i8 %adjusted)
252 %no_underflow = icmp uge i8 %base, %offset
253 call void @use1(i1 %no_underflow)
254 %not_null = icmp ne i8 %adjusted, 0
255 call void @use1(i1 %not_null)
256 %r = and i1 %no_underflow, %not_null ; swapped
260 define i1 @t4_commutability1_logical(i8 %base, i8 %offset) {
261 ; CHECK-LABEL: @t4_commutability1_logical(
262 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
263 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
264 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
265 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
266 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
267 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
268 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
269 ; CHECK-NEXT: ret i1 [[TMP1]]
271 %adjusted = sub i8 %base, %offset
272 call void @use8(i8 %adjusted)
273 %no_underflow = icmp uge i8 %base, %offset
274 call void @use1(i1 %no_underflow)
275 %not_null = icmp ne i8 %adjusted, 0
276 call void @use1(i1 %not_null)
277 %r = select i1 %no_underflow, i1 %not_null, i1 false ; swapped
280 define i1 @t5_commutability2(i8 %base, i8 %offset) {
281 ; CHECK-LABEL: @t5_commutability2(
282 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
283 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
284 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
285 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
286 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
287 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
288 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
289 ; CHECK-NEXT: ret i1 [[TMP1]]
291 %adjusted = sub i8 %base, %offset
292 call void @use8(i8 %adjusted)
293 %no_underflow = icmp ule i8 %offset, %base ; swapped
294 call void @use1(i1 %no_underflow)
295 %not_null = icmp ne i8 %adjusted, 0
296 call void @use1(i1 %not_null)
297 %r = and i1 %no_underflow, %not_null ; swapped
301 define i1 @t5_commutability2_logical(i8 %base, i8 %offset) {
302 ; CHECK-LABEL: @t5_commutability2_logical(
303 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
304 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
305 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
306 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
307 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
308 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
309 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
310 ; CHECK-NEXT: ret i1 [[TMP1]]
312 %adjusted = sub i8 %base, %offset
313 call void @use8(i8 %adjusted)
314 %no_underflow = icmp ule i8 %offset, %base ; swapped
315 call void @use1(i1 %no_underflow)
316 %not_null = icmp ne i8 %adjusted, 0
317 call void @use1(i1 %not_null)
318 %r = select i1 %no_underflow, i1 %not_null, i1 false ; swapped
322 define i1 @t6_commutability(i8 %base, i8 %offset) {
323 ; CHECK-LABEL: @t6_commutability(
324 ; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]])
325 ; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]])
326 ; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0
327 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
328 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1
329 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
330 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = xor i1 [[UNDERFLOW]], true
331 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
332 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
333 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
334 ; CHECK-NEXT: ret i1 [[R]]
336 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset)
337 call void @useagg({i8, i1} %agg)
338 %adjusted = extractvalue {i8, i1} %agg, 0
339 call void @use8(i8 %adjusted)
340 %underflow = extractvalue {i8, i1} %agg, 1
341 call void @use1(i1 %underflow)
342 %no_underflow = xor i1 %underflow, -1
343 call void @use1(i1 %no_underflow)
344 %not_null = icmp ne i8 %adjusted, 0
345 %r = and i1 %no_underflow, %not_null ; swapped
349 define i1 @t6_commutability_logical(i8 %base, i8 %offset) {
350 ; CHECK-LABEL: @t6_commutability_logical(
351 ; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]])
352 ; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]])
353 ; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0
354 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
355 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1
356 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
357 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = xor i1 [[UNDERFLOW]], true
358 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
359 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
360 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
361 ; CHECK-NEXT: ret i1 [[R]]
363 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset)
364 call void @useagg({i8, i1} %agg)
365 %adjusted = extractvalue {i8, i1} %agg, 0
366 call void @use8(i8 %adjusted)
367 %underflow = extractvalue {i8, i1} %agg, 1
368 call void @use1(i1 %underflow)
369 %no_underflow = xor i1 %underflow, -1
370 call void @use1(i1 %no_underflow)
371 %not_null = icmp ne i8 %adjusted, 0
372 %r = select i1 %no_underflow, i1 %not_null, i1 false ; swapped
376 ; What if we were checking the opposite question, that we either got null,
377 ; or overflow happened?
379 define i1 @t7(i8 %base, i8 %offset) {
381 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
382 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
383 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
384 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
385 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
386 ; CHECK-NEXT: call void @use1(i1 [[NULL]])
387 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
388 ; CHECK-NEXT: ret i1 [[TMP1]]
390 %adjusted = sub i8 %base, %offset
391 call void @use8(i8 %adjusted)
392 %underflow = icmp ult i8 %base, %offset
393 call void @use1(i1 %underflow)
394 %null = icmp eq i8 %adjusted, 0
395 call void @use1(i1 %null)
396 %r = or i1 %null, %underflow
400 define i1 @t7_logical(i8 %base, i8 %offset) {
401 ; CHECK-LABEL: @t7_logical(
402 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
403 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
404 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
405 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
406 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
407 ; CHECK-NEXT: call void @use1(i1 [[NULL]])
408 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
409 ; CHECK-NEXT: ret i1 [[TMP1]]
411 %adjusted = sub i8 %base, %offset
412 call void @use8(i8 %adjusted)
413 %underflow = icmp ult i8 %base, %offset
414 call void @use1(i1 %underflow)
415 %null = icmp eq i8 %adjusted, 0
416 call void @use1(i1 %null)
417 %r = select i1 %null, i1 true, i1 %underflow
420 define i1 @t7_nonstrict(i8 %base, i8 %offset) {
421 ; CHECK-LABEL: @t7_nonstrict(
422 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
423 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
424 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
425 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
426 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
427 ; CHECK-NEXT: call void @use1(i1 [[NULL]])
428 ; CHECK-NEXT: ret i1 [[UNDERFLOW]]
430 %adjusted = sub i8 %base, %offset
431 call void @use8(i8 %adjusted)
432 %underflow = icmp ule i8 %base, %offset ; same is valid for non-strict predicate
433 call void @use1(i1 %underflow)
434 %null = icmp eq i8 %adjusted, 0
435 call void @use1(i1 %null)
436 %r = or i1 %null, %underflow
440 define i1 @t7_nonstrict_logical(i8 %base, i8 %offset) {
441 ; CHECK-LABEL: @t7_nonstrict_logical(
442 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
443 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
444 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
445 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
446 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
447 ; CHECK-NEXT: call void @use1(i1 [[NULL]])
448 ; CHECK-NEXT: ret i1 [[UNDERFLOW]]
450 %adjusted = sub i8 %base, %offset
451 call void @use8(i8 %adjusted)
452 %underflow = icmp ule i8 %base, %offset ; same is valid for non-strict predicate
453 call void @use1(i1 %underflow)
454 %null = icmp eq i8 %adjusted, 0
455 call void @use1(i1 %null)
456 %r = select i1 %null, i1 true, i1 %underflow
460 define i1 @t8(i8 %base, i8 %offset) {
462 ; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]])
463 ; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]])
464 ; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0
465 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
466 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1
467 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
468 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
469 ; CHECK-NEXT: [[R:%.*]] = or i1 [[NULL]], [[UNDERFLOW]]
470 ; CHECK-NEXT: ret i1 [[R]]
472 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset)
473 call void @useagg({i8, i1} %agg)
474 %adjusted = extractvalue {i8, i1} %agg, 0
475 call void @use8(i8 %adjusted)
476 %underflow = extractvalue {i8, i1} %agg, 1
477 call void @use1(i1 %underflow)
478 %null = icmp eq i8 %adjusted, 0
479 %r = or i1 %null, %underflow
483 define i1 @t8_logical(i8 %base, i8 %offset) {
484 ; CHECK-LABEL: @t8_logical(
485 ; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]])
486 ; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]])
487 ; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0
488 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
489 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1
490 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
491 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
492 ; CHECK-NEXT: [[R:%.*]] = or i1 [[NULL]], [[UNDERFLOW]]
493 ; CHECK-NEXT: ret i1 [[R]]
495 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset)
496 call void @useagg({i8, i1} %agg)
497 %adjusted = extractvalue {i8, i1} %agg, 0
498 call void @use8(i8 %adjusted)
499 %underflow = extractvalue {i8, i1} %agg, 1
500 call void @use1(i1 %underflow)
501 %null = icmp eq i8 %adjusted, 0
502 %r = select i1 %null, i1 true, i1 %underflow
506 ; And these patterns also have commutative variants
508 define i1 @t9_commutative(i8 %base, i8 %offset) {
509 ; CHECK-LABEL: @t9_commutative(
510 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
511 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
512 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
513 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
514 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
515 ; CHECK-NEXT: call void @use1(i1 [[NULL]])
516 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
517 ; CHECK-NEXT: ret i1 [[TMP1]]
519 %adjusted = sub i8 %base, %offset
520 call void @use8(i8 %adjusted)
521 %underflow = icmp ult i8 %base, %adjusted ; swapped
522 call void @use1(i1 %underflow)
523 %null = icmp eq i8 %adjusted, 0
524 call void @use1(i1 %null)
525 %r = or i1 %null, %underflow
529 define i1 @t9_commutative_logical(i8 %base, i8 %offset) {
530 ; CHECK-LABEL: @t9_commutative_logical(
531 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
532 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
533 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
534 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
535 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
536 ; CHECK-NEXT: call void @use1(i1 [[NULL]])
537 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
538 ; CHECK-NEXT: ret i1 [[TMP1]]
540 %adjusted = sub i8 %base, %offset
541 call void @use8(i8 %adjusted)
542 %underflow = icmp ult i8 %base, %adjusted ; swapped
543 call void @use1(i1 %underflow)
544 %null = icmp eq i8 %adjusted, 0
545 call void @use1(i1 %null)
546 %r = select i1 %null, i1 true, i1 %underflow
550 ;-------------------------------------------------------------------------------
552 define i1 @t10(i64 %base, i64* nonnull %offsetptr) {
554 ; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint i64* [[OFFSETPTR:%.*]] to i64
555 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]]
556 ; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]])
557 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i64 [[OFFSET]], [[BASE]]
558 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
559 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[ADJUSTED]], 0
560 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
561 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[OFFSET]], [[BASE]]
562 ; CHECK-NEXT: ret i1 [[TMP1]]
564 %offset = ptrtoint i64* %offsetptr to i64
566 %adjusted = sub i64 %base, %offset
567 call void @use64(i64 %adjusted)
568 %no_underflow = icmp ult i64 %adjusted, %base
569 call void @use1(i1 %no_underflow)
570 %not_null = icmp ne i64 %adjusted, 0
571 call void @use1(i1 %not_null)
572 %r = and i1 %not_null, %no_underflow
576 define i1 @t10_logical(i64 %base, i64* nonnull %offsetptr) {
577 ; CHECK-LABEL: @t10_logical(
578 ; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint i64* [[OFFSETPTR:%.*]] to i64
579 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]]
580 ; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]])
581 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i64 [[OFFSET]], [[BASE]]
582 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
583 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[ADJUSTED]], 0
584 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
585 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[OFFSET]], [[BASE]]
586 ; CHECK-NEXT: ret i1 [[TMP1]]
588 %offset = ptrtoint i64* %offsetptr to i64
590 %adjusted = sub i64 %base, %offset
591 call void @use64(i64 %adjusted)
592 %no_underflow = icmp ult i64 %adjusted, %base
593 call void @use1(i1 %no_underflow)
594 %not_null = icmp ne i64 %adjusted, 0
595 call void @use1(i1 %not_null)
596 %r = select i1 %not_null, i1 %no_underflow, i1 false
599 define i1 @t11_commutative(i64 %base, i64* nonnull %offsetptr) {
600 ; CHECK-LABEL: @t11_commutative(
601 ; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint i64* [[OFFSETPTR:%.*]] to i64
602 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]]
603 ; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]])
604 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i64 [[OFFSET]], [[BASE]]
605 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
606 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[ADJUSTED]], 0
607 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
608 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[OFFSET]], [[BASE]]
609 ; CHECK-NEXT: ret i1 [[TMP1]]
611 %offset = ptrtoint i64* %offsetptr to i64
613 %adjusted = sub i64 %base, %offset
614 call void @use64(i64 %adjusted)
615 %no_underflow = icmp ugt i64 %base, %adjusted ; swapped
616 call void @use1(i1 %no_underflow)
617 %not_null = icmp ne i64 %adjusted, 0
618 call void @use1(i1 %not_null)
619 %r = and i1 %not_null, %no_underflow
623 define i1 @t11_commutative_logical(i64 %base, i64* nonnull %offsetptr) {
624 ; CHECK-LABEL: @t11_commutative_logical(
625 ; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint i64* [[OFFSETPTR:%.*]] to i64
626 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]]
627 ; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]])
628 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i64 [[OFFSET]], [[BASE]]
629 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
630 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[ADJUSTED]], 0
631 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
632 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[OFFSET]], [[BASE]]
633 ; CHECK-NEXT: ret i1 [[TMP1]]
635 %offset = ptrtoint i64* %offsetptr to i64
637 %adjusted = sub i64 %base, %offset
638 call void @use64(i64 %adjusted)
639 %no_underflow = icmp ugt i64 %base, %adjusted ; swapped
640 call void @use1(i1 %no_underflow)
641 %not_null = icmp ne i64 %adjusted, 0
642 call void @use1(i1 %not_null)
643 %r = select i1 %not_null, i1 %no_underflow, i1 false
647 define i1 @t12(i64 %base, i64* nonnull %offsetptr) {
649 ; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint i64* [[OFFSETPTR:%.*]] to i64
650 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]]
651 ; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]])
652 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i64 [[OFFSET]], [[BASE]]
653 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
654 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i64 [[ADJUSTED]], 0
655 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
656 ; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i64 [[OFFSET]], [[BASE]]
657 ; CHECK-NEXT: ret i1 [[TMP1]]
659 %offset = ptrtoint i64* %offsetptr to i64
661 %adjusted = sub i64 %base, %offset
662 call void @use64(i64 %adjusted)
663 %no_underflow = icmp uge i64 %adjusted, %base
664 call void @use1(i1 %no_underflow)
665 %not_null = icmp eq i64 %adjusted, 0
666 call void @use1(i1 %not_null)
667 %r = or i1 %not_null, %no_underflow
671 define i1 @t12_logical(i64 %base, i64* nonnull %offsetptr) {
672 ; CHECK-LABEL: @t12_logical(
673 ; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint i64* [[OFFSETPTR:%.*]] to i64
674 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]]
675 ; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]])
676 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i64 [[OFFSET]], [[BASE]]
677 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
678 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i64 [[ADJUSTED]], 0
679 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
680 ; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i64 [[OFFSET]], [[BASE]]
681 ; CHECK-NEXT: ret i1 [[TMP1]]
683 %offset = ptrtoint i64* %offsetptr to i64
685 %adjusted = sub i64 %base, %offset
686 call void @use64(i64 %adjusted)
687 %no_underflow = icmp uge i64 %adjusted, %base
688 call void @use1(i1 %no_underflow)
689 %not_null = icmp eq i64 %adjusted, 0
690 call void @use1(i1 %not_null)
691 %r = select i1 %not_null, i1 true, i1 %no_underflow
694 define i1 @t13(i64 %base, i64* nonnull %offsetptr) {
696 ; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint i64* [[OFFSETPTR:%.*]] to i64
697 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]]
698 ; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]])
699 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i64 [[OFFSET]], [[BASE]]
700 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
701 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i64 [[ADJUSTED]], 0
702 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
703 ; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i64 [[OFFSET]], [[BASE]]
704 ; CHECK-NEXT: ret i1 [[TMP1]]
706 %offset = ptrtoint i64* %offsetptr to i64
708 %adjusted = sub i64 %base, %offset
709 call void @use64(i64 %adjusted)
710 %no_underflow = icmp ule i64 %base, %adjusted ; swapped
711 call void @use1(i1 %no_underflow)
712 %not_null = icmp eq i64 %adjusted, 0
713 call void @use1(i1 %not_null)
714 %r = or i1 %not_null, %no_underflow
718 define i1 @t13_logical(i64 %base, i64* nonnull %offsetptr) {
719 ; CHECK-LABEL: @t13_logical(
720 ; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint i64* [[OFFSETPTR:%.*]] to i64
721 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]]
722 ; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]])
723 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i64 [[OFFSET]], [[BASE]]
724 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
725 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i64 [[ADJUSTED]], 0
726 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
727 ; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i64 [[OFFSET]], [[BASE]]
728 ; CHECK-NEXT: ret i1 [[TMP1]]
730 %offset = ptrtoint i64* %offsetptr to i64
732 %adjusted = sub i64 %base, %offset
733 call void @use64(i64 %adjusted)
734 %no_underflow = icmp ule i64 %base, %adjusted ; swapped
735 call void @use1(i1 %no_underflow)
736 %not_null = icmp eq i64 %adjusted, 0
737 call void @use1(i1 %not_null)
738 %r = select i1 %not_null, i1 true, i1 %no_underflow
742 define i1 @t14_bad(i64 %base, i64 %offset) {
743 ; CHECK-LABEL: @t14_bad(
744 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET:%.*]]
745 ; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]])
746 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE]]
747 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
748 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[ADJUSTED]], 0
749 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
750 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
751 ; CHECK-NEXT: ret i1 [[R]]
753 %adjusted = sub i64 %base, %offset
754 call void @use64(i64 %adjusted)
755 %no_underflow = icmp ult i64 %adjusted, %base
756 call void @use1(i1 %no_underflow)
757 %not_null = icmp ne i64 %adjusted, 0
758 call void @use1(i1 %not_null)
759 %r = and i1 %not_null, %no_underflow
763 define i1 @t14_bad_logical(i64 %base, i64 %offset) {
764 ; CHECK-LABEL: @t14_bad_logical(
765 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET:%.*]]
766 ; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]])
767 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE]]
768 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
769 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[ADJUSTED]], 0
770 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
771 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
772 ; CHECK-NEXT: ret i1 [[R]]
774 %adjusted = sub i64 %base, %offset
775 call void @use64(i64 %adjusted)
776 %no_underflow = icmp ult i64 %adjusted, %base
777 call void @use1(i1 %no_underflow)
778 %not_null = icmp ne i64 %adjusted, 0
779 call void @use1(i1 %not_null)
780 %r = select i1 %not_null, i1 %no_underflow, i1 false
784 define i1 @base_ult_offset(i8 %base, i8 %offset) {
785 ; CHECK-LABEL: @base_ult_offset(
786 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
787 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
788 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
789 ; CHECK-NEXT: ret i1 [[TMP1]]
791 %adjusted = sub i8 %base, %offset
792 call void @use8(i8 %adjusted)
793 %not_null = icmp ne i8 %adjusted, 0
794 %no_underflow = icmp ule i8 %base, %offset
795 %r = and i1 %no_underflow, %not_null
799 define i1 @base_ult_offset_logical(i8 %base, i8 %offset) {
800 ; CHECK-LABEL: @base_ult_offset_logical(
801 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
802 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
803 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
804 ; CHECK-NEXT: ret i1 [[TMP1]]
806 %adjusted = sub i8 %base, %offset
807 call void @use8(i8 %adjusted)
808 %not_null = icmp ne i8 %adjusted, 0
809 %no_underflow = icmp ule i8 %base, %offset
810 %r = select i1 %no_underflow, i1 %not_null, i1 false
813 define i1 @base_uge_offset(i8 %base, i8 %offset) {
814 ; CHECK-LABEL: @base_uge_offset(
815 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
816 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
817 ; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
818 ; CHECK-NEXT: ret i1 [[TMP1]]
820 %adjusted = sub i8 %base, %offset
821 call void @use8(i8 %adjusted)
822 %not_null = icmp eq i8 %adjusted, 0
823 %no_underflow = icmp ugt i8 %base, %offset
824 %r = or i1 %no_underflow, %not_null
828 define i1 @base_uge_offset_logical(i8 %base, i8 %offset) {
829 ; CHECK-LABEL: @base_uge_offset_logical(
830 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
831 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
832 ; CHECK-NEXT: [[TMP1:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
833 ; CHECK-NEXT: ret i1 [[TMP1]]
835 %adjusted = sub i8 %base, %offset
836 call void @use8(i8 %adjusted)
837 %not_null = icmp eq i8 %adjusted, 0
838 %no_underflow = icmp ugt i8 %base, %offset
839 %r = select i1 %no_underflow, i1 true, i1 %not_null