xref: /llvm-project/llvm/test/Transforms/InstCombine/result-of-usub-is-non-zero-and-no-overflow.ll (revision a105877646d68e48cdeeeadd9d1e075dc3c5d68d)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
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.
7
8declare void @use8(i8)
9declare void @use64(i64)
10declare void @use1(i1)
11
12declare {i8, i1} @llvm.usub.with.overflow(i8, i8)
13declare void @useagg({i8, i1})
14
15declare void @llvm.assume(i1)
16
17; There is a number of base patterns..
18
19define 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 ule i8 [[OFFSET]], [[BASE]]
24; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
25; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]]
26; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
27; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[OFFSET]], [[BASE]]
28; CHECK-NEXT:    ret i1 [[R]]
29;
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
38}
39
40define 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 ule i8 [[OFFSET]], [[BASE]]
45; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
46; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]]
47; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
48; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[OFFSET]], [[BASE]]
49; CHECK-NEXT:    ret i1 [[R]]
50;
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
59}
60
61define 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 [[BASE]], [[OFFSET]]
68; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
69; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
70; CHECK-NEXT:    ret i1 [[R]]
71;
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
80}
81
82define 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 [[BASE]], [[OFFSET]]
89; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
90; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
91; CHECK-NEXT:    ret i1 [[R]]
92;
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
101}
102define 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 [[BASE]], [[OFFSET]]
109; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
110; CHECK-NEXT:    ret i1 [[NO_UNDERFLOW]]
111;
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
120}
121
122define 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 [[BASE]], [[OFFSET]]
129; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
130; CHECK-NEXT:    ret i1 [[NO_UNDERFLOW]]
131;
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
140}
141
142define 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]]
155;
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
167}
168
169define 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]]
182;
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
194}
195
196; Commutativity
197
198define 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 ule i8 [[OFFSET]], [[BASE]]
203; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
204; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]]
205; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
206; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[OFFSET]], [[BASE]]
207; CHECK-NEXT:    ret i1 [[R]]
208;
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
217}
218
219define 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 ule i8 [[OFFSET]], [[BASE]]
224; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
225; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]]
226; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
227; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[OFFSET]], [[BASE]]
228; CHECK-NEXT:    ret i1 [[R]]
229;
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
238}
239define 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 [[BASE]], [[OFFSET]]
246; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
247; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
248; CHECK-NEXT:    ret i1 [[R]]
249;
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
258}
259
260define 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 [[BASE]], [[OFFSET]]
267; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
268; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
269; CHECK-NEXT:    ret i1 [[R]]
270;
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
279}
280define 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 ule i8 [[OFFSET]], [[BASE]]
285; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
286; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]]
287; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
288; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
289; CHECK-NEXT:    ret i1 [[R]]
290;
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
299}
300
301define 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 ule i8 [[OFFSET]], [[BASE]]
306; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
307; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]]
308; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
309; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
310; CHECK-NEXT:    ret i1 [[R]]
311;
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
320}
321
322define 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]]
335;
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
347}
348
349define 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]]
362;
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
374}
375
376; What if we were checking the opposite question, that we either got null,
377; or overflow happened?
378
379define 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 [[BASE]], [[OFFSET]]
386; CHECK-NEXT:    call void @use1(i1 [[NULL]])
387; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
388; CHECK-NEXT:    ret i1 [[R]]
389;
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
398}
399
400define 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 [[BASE]], [[OFFSET]]
407; CHECK-NEXT:    call void @use1(i1 [[NULL]])
408; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
409; CHECK-NEXT:    ret i1 [[R]]
410;
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
419}
420define 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 [[BASE]], [[OFFSET]]
427; CHECK-NEXT:    call void @use1(i1 [[NULL]])
428; CHECK-NEXT:    ret i1 [[UNDERFLOW]]
429;
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
438}
439
440define 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 [[BASE]], [[OFFSET]]
447; CHECK-NEXT:    call void @use1(i1 [[NULL]])
448; CHECK-NEXT:    ret i1 [[UNDERFLOW]]
449;
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
458}
459
460define 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]]
471;
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
481}
482
483define 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]]
494;
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
504}
505
506; And these patterns also have commutative variants
507
508define 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 [[BASE]], [[OFFSET]]
515; CHECK-NEXT:    call void @use1(i1 [[NULL]])
516; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
517; CHECK-NEXT:    ret i1 [[R]]
518;
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
527}
528
529define 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 [[BASE]], [[OFFSET]]
536; CHECK-NEXT:    call void @use1(i1 [[NULL]])
537; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
538; CHECK-NEXT:    ret i1 [[R]]
539;
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
548}
549
550;-------------------------------------------------------------------------------
551
552define i1 @t10(i64 %base, ptr nonnull %offsetptr) {
553; CHECK-LABEL: @t10(
554; CHECK-NEXT:    [[OFFSET:%.*]] = ptrtoint ptr [[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 uge i64 [[BASE]], [[OFFSET]]
558; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
559; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i64 [[BASE]], [[OFFSET]]
560; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
561; CHECK-NEXT:    [[R:%.*]] = icmp ugt i64 [[BASE]], [[OFFSET]]
562; CHECK-NEXT:    ret i1 [[R]]
563;
564  %offset = ptrtoint ptr %offsetptr to i64
565
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
574}
575
576define i1 @t10_logical(i64 %base, ptr nonnull %offsetptr) {
577; CHECK-LABEL: @t10_logical(
578; CHECK-NEXT:    [[OFFSET:%.*]] = ptrtoint ptr [[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 uge i64 [[BASE]], [[OFFSET]]
582; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
583; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i64 [[BASE]], [[OFFSET]]
584; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
585; CHECK-NEXT:    [[R:%.*]] = icmp ugt i64 [[BASE]], [[OFFSET]]
586; CHECK-NEXT:    ret i1 [[R]]
587;
588  %offset = ptrtoint ptr %offsetptr to i64
589
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
598}
599define i1 @t11_commutative(i64 %base, ptr nonnull %offsetptr) {
600; CHECK-LABEL: @t11_commutative(
601; CHECK-NEXT:    [[OFFSET:%.*]] = ptrtoint ptr [[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 uge i64 [[BASE]], [[OFFSET]]
605; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
606; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i64 [[BASE]], [[OFFSET]]
607; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
608; CHECK-NEXT:    [[R:%.*]] = icmp ugt i64 [[BASE]], [[OFFSET]]
609; CHECK-NEXT:    ret i1 [[R]]
610;
611  %offset = ptrtoint ptr %offsetptr to i64
612
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
621}
622
623define i1 @t11_commutative_logical(i64 %base, ptr nonnull %offsetptr) {
624; CHECK-LABEL: @t11_commutative_logical(
625; CHECK-NEXT:    [[OFFSET:%.*]] = ptrtoint ptr [[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 uge i64 [[BASE]], [[OFFSET]]
629; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
630; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i64 [[BASE]], [[OFFSET]]
631; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
632; CHECK-NEXT:    [[R:%.*]] = icmp ugt i64 [[BASE]], [[OFFSET]]
633; CHECK-NEXT:    ret i1 [[R]]
634;
635  %offset = ptrtoint ptr %offsetptr to i64
636
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
645}
646
647define i1 @t12(i64 %base, ptr nonnull %offsetptr) {
648; CHECK-LABEL: @t12(
649; CHECK-NEXT:    [[OFFSET:%.*]] = ptrtoint ptr [[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 ult i64 [[BASE]], [[OFFSET]]
653; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
654; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp eq i64 [[BASE]], [[OFFSET]]
655; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
656; CHECK-NEXT:    [[R:%.*]] = icmp ule i64 [[BASE]], [[OFFSET]]
657; CHECK-NEXT:    ret i1 [[R]]
658;
659  %offset = ptrtoint ptr %offsetptr to i64
660
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
669}
670
671define i1 @t12_logical(i64 %base, ptr nonnull %offsetptr) {
672; CHECK-LABEL: @t12_logical(
673; CHECK-NEXT:    [[OFFSET:%.*]] = ptrtoint ptr [[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 ult i64 [[BASE]], [[OFFSET]]
677; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
678; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp eq i64 [[BASE]], [[OFFSET]]
679; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
680; CHECK-NEXT:    [[R:%.*]] = icmp ule i64 [[BASE]], [[OFFSET]]
681; CHECK-NEXT:    ret i1 [[R]]
682;
683  %offset = ptrtoint ptr %offsetptr to i64
684
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
693}
694define i1 @t13(i64 %base, ptr nonnull %offsetptr) {
695; CHECK-LABEL: @t13(
696; CHECK-NEXT:    [[OFFSET:%.*]] = ptrtoint ptr [[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 ult i64 [[BASE]], [[OFFSET]]
700; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
701; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp eq i64 [[BASE]], [[OFFSET]]
702; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
703; CHECK-NEXT:    [[R:%.*]] = icmp ule i64 [[BASE]], [[OFFSET]]
704; CHECK-NEXT:    ret i1 [[R]]
705;
706  %offset = ptrtoint ptr %offsetptr to i64
707
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
716}
717
718define i1 @t13_logical(i64 %base, ptr nonnull %offsetptr) {
719; CHECK-LABEL: @t13_logical(
720; CHECK-NEXT:    [[OFFSET:%.*]] = ptrtoint ptr [[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 ult i64 [[BASE]], [[OFFSET]]
724; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
725; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp eq i64 [[BASE]], [[OFFSET]]
726; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
727; CHECK-NEXT:    [[R:%.*]] = icmp ule i64 [[BASE]], [[OFFSET]]
728; CHECK-NEXT:    ret i1 [[R]]
729;
730  %offset = ptrtoint ptr %offsetptr to i64
731
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
740}
741
742define 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 [[BASE]], [[OFFSET]]
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]]
752;
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
761}
762
763define 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 [[BASE]], [[OFFSET]]
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]]
773;
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
782}
783
784define 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:    [[R:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
789; CHECK-NEXT:    ret i1 [[R]]
790;
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
797}
798
799define 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:    [[R:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
804; CHECK-NEXT:    ret i1 [[R]]
805;
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
812}
813define 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:    [[R:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
818; CHECK-NEXT:    ret i1 [[R]]
819;
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
826}
827
828define 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:    [[R:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
833; CHECK-NEXT:    ret i1 [[R]]
834;
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
841}
842