[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / test / Transforms / InstCombine / result-of-usub-is-non-zero-and-no-overflow.ll
blobb875396a8c6dde15d6fb627ec3edfa96b7532a8a
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.
8 declare void @use8(i8)
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
37   ret i1 %r
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
58   ret i1 %r
61 define i1 @t1(i8 %base, i8 %offset) {
62 ; CHECK-LABEL: @t1(
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
79   ret i1 %r
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
100   ret i1 %r
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
119   ret i1 %r
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
139   ret i1 %r
142 define i1 @t2(i8 %base, i8 %offset) {
143 ; CHECK-LABEL: @t2(
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
166   ret i1 %r
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
193   ret i1 %r
196 ; Commutativity
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
216   ret i1 %r
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
237   ret i1 %r
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
257   ret i1 %r
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
278   ret i1 %r
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
298   ret i1 %r
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
319   ret i1 %r
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
346   ret i1 %r
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
373   ret i1 %r
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) {
380 ; CHECK-LABEL: @t7(
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
397   ret i1 %r
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
418   ret i1 %r
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
437   ret i1 %r
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
457   ret i1 %r
460 define i1 @t8(i8 %base, i8 %offset) {
461 ; CHECK-LABEL: @t8(
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
480   ret i1 %r
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
503   ret i1 %r
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
526   ret i1 %r
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
547   ret i1 %r
550 ;-------------------------------------------------------------------------------
552 define i1 @t10(i64 %base, i64* nonnull %offsetptr) {
553 ; CHECK-LABEL: @t10(
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
573   ret i1 %r
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
597   ret i1 %r
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
620   ret i1 %r
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
644   ret i1 %r
647 define i1 @t12(i64 %base, i64* nonnull %offsetptr) {
648 ; CHECK-LABEL: @t12(
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
668   ret i1 %r
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
692   ret i1 %r
694 define i1 @t13(i64 %base, i64* nonnull %offsetptr) {
695 ; CHECK-LABEL: @t13(
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
715   ret i1 %r
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
739   ret i1 %r
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
760   ret i1 %r
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
781   ret i1 %r
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
796   ret i1 %r
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
811   ret i1 %r
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
825   ret i1 %r
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
840   ret i1 %r