[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / InstCombine / result-of-add-of-negative-is-non-zero-and-no-underflow.ll
blobbcc62dc983c689105b5f0d38f8c89e74f08259bb
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -instcombine -S | FileCheck %s
4 declare void @use8(i8)
6 declare void @use1(i1)
7 declare void @llvm.assume(i1)
9 ; Here we don't know that at least one of the values being added is non-zero
10 define i1 @t0_bad(i8 %base, i8 %offset) {
11 ; CHECK-LABEL: @t0_bad(
12 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]]
13 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
14 ; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
15 ; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
16 ; CHECK-NEXT:    [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
17 ; CHECK-NEXT:    ret i1 [[R]]
19   %adjusted = add i8 %base, %offset
20   call void @use8(i8 %adjusted)
21   %not_null = icmp ne i8 %adjusted, 0
22   %no_underflow = icmp ult i8 %adjusted, %base
23   %r = and i1 %not_null, %no_underflow
24   ret i1 %r
27 define i1 @t0_bad_logical(i8 %base, i8 %offset) {
28 ; CHECK-LABEL: @t0_bad_logical(
29 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]]
30 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
31 ; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
32 ; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
33 ; CHECK-NEXT:    [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
34 ; CHECK-NEXT:    ret i1 [[R]]
36   %adjusted = add i8 %base, %offset
37   call void @use8(i8 %adjusted)
38   %not_null = icmp ne i8 %adjusted, 0
39   %no_underflow = icmp ult i8 %adjusted, %base
40   %r = select i1 %not_null, i1 %no_underflow, i1 false
41   ret i1 %r
44 ; Ok, base is non-zero.
45 define i1 @t1(i8 %base, i8 %offset) {
46 ; CHECK-LABEL: @t1(
47 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
48 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
49 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
50 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
51 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
52 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
53 ; CHECK-NEXT:    ret i1 [[TMP2]]
55   %cmp = icmp slt i8 %base, 0
56   call void @llvm.assume(i1 %cmp)
58   %adjusted = add i8 %base, %offset
59   call void @use8(i8 %adjusted)
60   %not_null = icmp ne i8 %adjusted, 0
61   %no_underflow = icmp ult i8 %adjusted, %base
62   %r = and i1 %not_null, %no_underflow
63   ret i1 %r
66 define i1 @t1_logical(i8 %base, i8 %offset) {
67 ; CHECK-LABEL: @t1_logical(
68 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
69 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
70 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
71 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
72 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
73 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
74 ; CHECK-NEXT:    ret i1 [[TMP2]]
76   %cmp = icmp slt i8 %base, 0
77   call void @llvm.assume(i1 %cmp)
79   %adjusted = add i8 %base, %offset
80   call void @use8(i8 %adjusted)
81   %not_null = icmp ne i8 %adjusted, 0
82   %no_underflow = icmp ult i8 %adjusted, %base
83   %r = select i1 %not_null, i1 %no_underflow, i1 false
84   ret i1 %r
87 ; Ok, offset is non-zero.
88 define i1 @t2(i8 %base, i8 %offset) {
89 ; CHECK-LABEL: @t2(
90 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[OFFSET:%.*]], 0
91 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
92 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET]]
93 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
94 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[OFFSET]]
95 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[BASE]]
96 ; CHECK-NEXT:    ret i1 [[TMP2]]
98   %cmp = icmp slt i8 %offset, 0
99   call void @llvm.assume(i1 %cmp)
101   %adjusted = add i8 %base, %offset
102   call void @use8(i8 %adjusted)
103   %not_null = icmp ne i8 %adjusted, 0
104   %no_underflow = icmp ult i8 %adjusted, %base
105   %r = and i1 %not_null, %no_underflow
106   ret i1 %r
109 define i1 @t2_logical(i8 %base, i8 %offset) {
110 ; CHECK-LABEL: @t2_logical(
111 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[OFFSET:%.*]], 0
112 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
113 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET]]
114 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
115 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[OFFSET]]
116 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[BASE]]
117 ; CHECK-NEXT:    ret i1 [[TMP2]]
119   %cmp = icmp slt i8 %offset, 0
120   call void @llvm.assume(i1 %cmp)
122   %adjusted = add i8 %base, %offset
123   call void @use8(i8 %adjusted)
124   %not_null = icmp ne i8 %adjusted, 0
125   %no_underflow = icmp ult i8 %adjusted, %base
126   %r = select i1 %not_null, i1 %no_underflow, i1 false
127   ret i1 %r
130 ; We need to produce extra instruction, so one of icmp's must go away.
131 define i1 @t3_oneuse0(i8 %base, i8 %offset) {
132 ; CHECK-LABEL: @t3_oneuse0(
133 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
134 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
135 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
136 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
137 ; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
138 ; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
139 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
140 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
141 ; CHECK-NEXT:    ret i1 [[TMP2]]
143   %cmp = icmp slt i8 %base, 0
144   call void @llvm.assume(i1 %cmp)
146   %adjusted = add i8 %base, %offset
147   call void @use8(i8 %adjusted)
148   %not_null = icmp ne i8 %adjusted, 0
149   call void @use1(i1 %not_null)
150   %no_underflow = icmp ult i8 %adjusted, %base
151   %r = and i1 %not_null, %no_underflow
152   ret i1 %r
155 define i1 @t3_oneuse0_logical(i8 %base, i8 %offset) {
156 ; CHECK-LABEL: @t3_oneuse0_logical(
157 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
158 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
159 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
160 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
161 ; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
162 ; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
163 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
164 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
165 ; CHECK-NEXT:    ret i1 [[TMP2]]
167   %cmp = icmp slt i8 %base, 0
168   call void @llvm.assume(i1 %cmp)
170   %adjusted = add i8 %base, %offset
171   call void @use8(i8 %adjusted)
172   %not_null = icmp ne i8 %adjusted, 0
173   call void @use1(i1 %not_null)
174   %no_underflow = icmp ult i8 %adjusted, %base
175   %r = select i1 %not_null, i1 %no_underflow, i1 false
176   ret i1 %r
178 define i1 @t4_oneuse1(i8 %base, i8 %offset) {
179 ; CHECK-LABEL: @t4_oneuse1(
180 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
181 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
182 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
183 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
184 ; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
185 ; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
186 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
187 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
188 ; CHECK-NEXT:    ret i1 [[TMP2]]
190   %cmp = icmp slt i8 %base, 0
191   call void @llvm.assume(i1 %cmp)
193   %adjusted = add i8 %base, %offset
194   call void @use8(i8 %adjusted)
195   %not_null = icmp ne i8 %adjusted, 0
196   %no_underflow = icmp ult i8 %adjusted, %base
197   call void @use1(i1 %no_underflow)
198   %r = and i1 %not_null, %no_underflow
199   ret i1 %r
202 define i1 @t4_oneuse1_logical(i8 %base, i8 %offset) {
203 ; CHECK-LABEL: @t4_oneuse1_logical(
204 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
205 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
206 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
207 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
208 ; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
209 ; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
210 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
211 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
212 ; CHECK-NEXT:    ret i1 [[TMP2]]
214   %cmp = icmp slt i8 %base, 0
215   call void @llvm.assume(i1 %cmp)
217   %adjusted = add i8 %base, %offset
218   call void @use8(i8 %adjusted)
219   %not_null = icmp ne i8 %adjusted, 0
220   %no_underflow = icmp ult i8 %adjusted, %base
221   call void @use1(i1 %no_underflow)
222   %r = select i1 %not_null, i1 %no_underflow, i1 false
223   ret i1 %r
225 define i1 @t5_oneuse2_bad(i8 %base, i8 %offset) {
226 ; CHECK-LABEL: @t5_oneuse2_bad(
227 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
228 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
229 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
230 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
231 ; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
232 ; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
233 ; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
234 ; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
235 ; CHECK-NEXT:    [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
236 ; CHECK-NEXT:    ret i1 [[R]]
238   %cmp = icmp slt i8 %base, 0
239   call void @llvm.assume(i1 %cmp)
241   %adjusted = add i8 %base, %offset
242   call void @use8(i8 %adjusted)
243   %not_null = icmp ne i8 %adjusted, 0
244   call void @use1(i1 %not_null)
245   %no_underflow = icmp ult i8 %adjusted, %base
246   call void @use1(i1 %no_underflow)
247   %r = and i1 %not_null, %no_underflow
248   ret i1 %r
251 define i1 @t5_oneuse2_bad_logical(i8 %base, i8 %offset) {
252 ; CHECK-LABEL: @t5_oneuse2_bad_logical(
253 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
254 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
255 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
256 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
257 ; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
258 ; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
259 ; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
260 ; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
261 ; CHECK-NEXT:    [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
262 ; CHECK-NEXT:    ret i1 [[R]]
264   %cmp = icmp slt i8 %base, 0
265   call void @llvm.assume(i1 %cmp)
267   %adjusted = add i8 %base, %offset
268   call void @use8(i8 %adjusted)
269   %not_null = icmp ne i8 %adjusted, 0
270   call void @use1(i1 %not_null)
271   %no_underflow = icmp ult i8 %adjusted, %base
272   call void @use1(i1 %no_underflow)
273   %r = select i1 %not_null, i1 %no_underflow, i1 false
274   ret i1 %r
277 define i1 @t6_commutativity0(i8 %base, i8 %offset) {
278 ; CHECK-LABEL: @t6_commutativity0(
279 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
280 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
281 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
282 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
283 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
284 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
285 ; CHECK-NEXT:    ret i1 [[TMP2]]
287   %cmp = icmp slt i8 %base, 0
288   call void @llvm.assume(i1 %cmp)
290   %adjusted = add i8 %base, %offset
291   call void @use8(i8 %adjusted)
292   %not_null = icmp ne i8 %adjusted, 0
293   %no_underflow = icmp ult i8 %adjusted, %base
294   %r = and i1 %no_underflow, %not_null ; swapped
295   ret i1 %r
298 define i1 @t6_commutativity0_logical(i8 %base, i8 %offset) {
299 ; CHECK-LABEL: @t6_commutativity0_logical(
300 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
301 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
302 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
303 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
304 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
305 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
306 ; CHECK-NEXT:    ret i1 [[TMP2]]
308   %cmp = icmp slt i8 %base, 0
309   call void @llvm.assume(i1 %cmp)
311   %adjusted = add i8 %base, %offset
312   call void @use8(i8 %adjusted)
313   %not_null = icmp ne i8 %adjusted, 0
314   %no_underflow = icmp ult i8 %adjusted, %base
315   %r = select i1 %no_underflow, i1 %not_null, i1 false ; swapped
316   ret i1 %r
318 define i1 @t7_commutativity1(i8 %base, i8 %offset) {
319 ; CHECK-LABEL: @t7_commutativity1(
320 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
321 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
322 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
323 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
324 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
325 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
326 ; CHECK-NEXT:    ret i1 [[TMP2]]
328   %cmp = icmp slt i8 %base, 0
329   call void @llvm.assume(i1 %cmp)
331   %adjusted = add i8 %base, %offset
332   call void @use8(i8 %adjusted)
333   %not_null = icmp ne i8 %adjusted, 0
334   %no_underflow = icmp ugt i8 %base, %adjusted ; swapped
335   %r = and i1 %not_null, %no_underflow
336   ret i1 %r
339 define i1 @t7_commutativity1_logical(i8 %base, i8 %offset) {
340 ; CHECK-LABEL: @t7_commutativity1_logical(
341 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
342 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
343 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
344 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
345 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
346 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
347 ; CHECK-NEXT:    ret i1 [[TMP2]]
349   %cmp = icmp slt i8 %base, 0
350   call void @llvm.assume(i1 %cmp)
352   %adjusted = add i8 %base, %offset
353   call void @use8(i8 %adjusted)
354   %not_null = icmp ne i8 %adjusted, 0
355   %no_underflow = icmp ugt i8 %base, %adjusted ; swapped
356   %r = select i1 %not_null, i1 %no_underflow, i1 false
357   ret i1 %r
359 define i1 @t7_commutativity3(i8 %base, i8 %offset) {
360 ; CHECK-LABEL: @t7_commutativity3(
361 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
362 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
363 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
364 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
365 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
366 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
367 ; CHECK-NEXT:    ret i1 [[TMP2]]
369   %cmp = icmp slt i8 %base, 0
370   call void @llvm.assume(i1 %cmp)
372   %adjusted = add i8 %base, %offset
373   call void @use8(i8 %adjusted)
374   %not_null = icmp ne i8 %adjusted, 0
375   %no_underflow = icmp ugt i8 %base, %adjusted ; swapped
376   %r = and i1 %no_underflow, %not_null ; swapped
377   ret i1 %r
380 define i1 @t7_commutativity3_logical(i8 %base, i8 %offset) {
381 ; CHECK-LABEL: @t7_commutativity3_logical(
382 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
383 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
384 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
385 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
386 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
387 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
388 ; CHECK-NEXT:    ret i1 [[TMP2]]
390   %cmp = icmp slt i8 %base, 0
391   call void @llvm.assume(i1 %cmp)
393   %adjusted = add i8 %base, %offset
394   call void @use8(i8 %adjusted)
395   %not_null = icmp ne i8 %adjusted, 0
396   %no_underflow = icmp ugt i8 %base, %adjusted ; swapped
397   %r = select i1 %no_underflow, i1 %not_null, i1 false ; swapped
398   ret i1 %r
401 ; We could have the opposite question, did we get null or overflow happened?
402 define i1 @t8(i8 %base, i8 %offset) {
403 ; CHECK-LABEL: @t8(
404 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
405 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
406 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
407 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
408 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
409 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp uge i8 [[TMP1]], [[OFFSET]]
410 ; CHECK-NEXT:    ret i1 [[TMP2]]
412   %cmp = icmp slt i8 %base, 0
413   call void @llvm.assume(i1 %cmp)
415   %adjusted = add i8 %base, %offset
416   call void @use8(i8 %adjusted)
417   %not_null = icmp eq i8 %adjusted, 0
418   %no_underflow = icmp uge i8 %adjusted, %base
419   %r = or i1 %not_null, %no_underflow
420   ret i1 %r
423 define i1 @t8_logical(i8 %base, i8 %offset) {
424 ; CHECK-LABEL: @t8_logical(
425 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
426 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
427 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
428 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
429 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
430 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp uge i8 [[TMP1]], [[OFFSET]]
431 ; CHECK-NEXT:    ret i1 [[TMP2]]
433   %cmp = icmp slt i8 %base, 0
434   call void @llvm.assume(i1 %cmp)
436   %adjusted = add i8 %base, %offset
437   call void @use8(i8 %adjusted)
438   %not_null = icmp eq i8 %adjusted, 0
439   %no_underflow = icmp uge i8 %adjusted, %base
440   %r = select i1 %not_null, i1 true, i1 %no_underflow
441   ret i1 %r
444 ; The comparison can be with any of the values being added.
445 define i1 @t9(i8 %base, i8 %offset) {
446 ; CHECK-LABEL: @t9(
447 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
448 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
449 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
450 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
451 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
452 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
453 ; CHECK-NEXT:    ret i1 [[TMP2]]
455   %cmp = icmp slt i8 %base, 0
456   call void @llvm.assume(i1 %cmp)
458   %adjusted = add i8 %base, %offset
459   call void @use8(i8 %adjusted)
460   %not_null = icmp ne i8 %adjusted, 0
461   %no_underflow = icmp ult i8 %adjusted, %offset
462   %r = and i1 %not_null, %no_underflow
463   ret i1 %r
466 define i1 @t9_logical(i8 %base, i8 %offset) {
467 ; CHECK-LABEL: @t9_logical(
468 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
469 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
470 ; CHECK-NEXT:    [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
471 ; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
472 ; CHECK-NEXT:    [[TMP1:%.*]] = sub i8 0, [[BASE]]
473 ; CHECK-NEXT:    [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
474 ; CHECK-NEXT:    ret i1 [[TMP2]]
476   %cmp = icmp slt i8 %base, 0
477   call void @llvm.assume(i1 %cmp)
479   %adjusted = add i8 %base, %offset
480   call void @use8(i8 %adjusted)
481   %not_null = icmp ne i8 %adjusted, 0
482   %no_underflow = icmp ult i8 %adjusted, %offset
483   %r = select i1 %not_null, i1 %no_underflow, i1 false
484   ret i1 %r