1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt %s -instsimplify -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 void @llvm.assume(i1)
13
14; If we are checking that we either did not get null or got no overflow,
15; this is tautological and is always true.
16
17define i1 @commutativity0(i8 %base, i8 %offset) {
18; CHECK-LABEL: @commutativity0(
19; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
20; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
21; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
22; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
23; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
24; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
25; CHECK-NEXT:    ret i1 true
26;
27  %adjusted = sub i8 %base, %offset
28  call void @use8(i8 %adjusted)
29  %no_underflow = icmp uge i8 %base, %offset
30  call void @use1(i1 %no_underflow)
31  %not_null = icmp ne i8 %adjusted, 0
32  call void @use1(i1 %not_null)
33  %r = or i1 %not_null, %no_underflow
34  ret i1 %r
35}
36define i1 @commutativity1(i8 %base, i8 %offset) {
37; CHECK-LABEL: @commutativity1(
38; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
39; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
40; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[OFFSET]], [[BASE]]
41; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
42; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
43; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
44; CHECK-NEXT:    ret i1 true
45;
46  %adjusted = sub i8 %base, %offset
47  call void @use8(i8 %adjusted)
48  %no_underflow = icmp ule i8 %offset, %base ; swapped
49  call void @use1(i1 %no_underflow)
50  %not_null = icmp ne i8 %adjusted, 0
51  call void @use1(i1 %not_null)
52  %r = or i1 %not_null, %no_underflow
53  ret i1 %r
54}
55define i1 @commutativity2(i8 %base, i8 %offset) {
56; CHECK-LABEL: @commutativity2(
57; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
58; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
59; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
60; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
61; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
62; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
63; CHECK-NEXT:    ret i1 true
64;
65  %adjusted = sub i8 %base, %offset
66  call void @use8(i8 %adjusted)
67  %no_underflow = icmp uge i8 %base, %offset
68  call void @use1(i1 %no_underflow)
69  %not_null = icmp ne i8 %adjusted, 0
70  call void @use1(i1 %not_null)
71  %r = or i1 %no_underflow, %not_null ; swapped
72  ret i1 %r
73}
74
75define i1 @commutativity3(i8 %base, i8 %offset) {
76; CHECK-LABEL: @commutativity3(
77; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
78; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
79; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[OFFSET]], [[BASE]]
80; CHECK-NEXT:    call void @use1(i1 [[NO_UNDERFLOW]])
81; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
82; CHECK-NEXT:    call void @use1(i1 [[NOT_NULL]])
83; CHECK-NEXT:    ret i1 true
84;
85  %adjusted = sub i8 %base, %offset
86  call void @use8(i8 %adjusted)
87  %no_underflow = icmp ule i8 %offset, %base ; swapped
88  call void @use1(i1 %no_underflow)
89  %not_null = icmp ne i8 %adjusted, 0
90  call void @use1(i1 %not_null)
91  %r = or i1 %no_underflow, %not_null ; swapped
92  ret i1 %r
93}
94
95;-------------------------------------------------------------------------------
96
97define i1 @exaustive_t0_no_underflow(i8 %base, i8 %offset) {
98; CHECK-LABEL: @exaustive_t0_no_underflow(
99; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
100; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
101; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
102; CHECK-NEXT:    ret i1 [[NO_UNDERFLOW]]
103;
104  %adjusted = sub i8 %base, %offset
105  call void @use8(i8 %adjusted)
106  %not_null = icmp ne i8 %adjusted, 0
107  %no_underflow = icmp ult i8 %base, %offset
108  %r = and i1 %no_underflow, %not_null
109  ret i1 %r
110}
111
112define i1 @exaustive_t1_not_null(i8 %base, i8 %offset) {
113; CHECK-LABEL: @exaustive_t1_not_null(
114; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
115; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
116; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
117; CHECK-NEXT:    ret i1 [[NOT_NULL]]
118;
119  %adjusted = sub i8 %base, %offset
120  call void @use8(i8 %adjusted)
121  %not_null = icmp ne i8 %adjusted, 0
122  %no_underflow = icmp ult i8 %base, %offset
123  %r = or i1 %no_underflow, %not_null
124  ret i1 %r
125}
126
127define i1 @exaustive_t2_false(i8 %base, i8 %offset) {
128; CHECK-LABEL: @exaustive_t2_false(
129; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
130; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
131; CHECK-NEXT:    ret i1 false
132;
133  %adjusted = sub i8 %base, %offset
134  call void @use8(i8 %adjusted)
135  %not_null = icmp eq i8 %adjusted, 0
136  %no_underflow = icmp ult i8 %base, %offset
137  %r = and i1 %no_underflow, %not_null
138  ret i1 %r
139}
140
141define i1 @exaustive_t3_bad(i8 %base, i8 %offset) {
142; CHECK-LABEL: @exaustive_t3_bad(
143; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
144; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
145; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
146; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
147; CHECK-NEXT:    [[R:%.*]] = or i1 [[NO_UNDERFLOW]], [[NOT_NULL]]
148; CHECK-NEXT:    ret i1 [[R]]
149;
150  %adjusted = sub i8 %base, %offset
151  call void @use8(i8 %adjusted)
152  %not_null = icmp eq i8 %adjusted, 0
153  %no_underflow = icmp ult i8 %base, %offset
154  %r = or i1 %no_underflow, %not_null
155  ret i1 %r
156}
157
158define i1 @exaustive_t4_no_underflow(i8 %base, i8 %offset) {
159; CHECK-LABEL: @exaustive_t4_no_underflow(
160; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
161; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
162; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
163; CHECK-NEXT:    ret i1 [[NO_UNDERFLOW]]
164;
165  %adjusted = sub i8 %base, %offset
166  call void @use8(i8 %adjusted)
167  %not_null = icmp ne i8 %adjusted, 0
168  %no_underflow = icmp ugt i8 %base, %offset
169  %r = and i1 %no_underflow, %not_null
170  ret i1 %r
171}
172
173define i1 @exaustive_t5_not_null(i8 %base, i8 %offset) {
174; CHECK-LABEL: @exaustive_t5_not_null(
175; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
176; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
177; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
178; CHECK-NEXT:    ret i1 [[NOT_NULL]]
179;
180  %adjusted = sub i8 %base, %offset
181  call void @use8(i8 %adjusted)
182  %not_null = icmp ne i8 %adjusted, 0
183  %no_underflow = icmp ugt i8 %base, %offset
184  %r = or i1 %no_underflow, %not_null
185  ret i1 %r
186}
187
188define i1 @exaustive_t6_false(i8 %base, i8 %offset) {
189; CHECK-LABEL: @exaustive_t6_false(
190; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
191; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
192; CHECK-NEXT:    ret i1 false
193;
194  %adjusted = sub i8 %base, %offset
195  call void @use8(i8 %adjusted)
196  %not_null = icmp eq i8 %adjusted, 0
197  %no_underflow = icmp ugt i8 %base, %offset
198  %r = and i1 %no_underflow, %not_null
199  ret i1 %r
200}
201
202define i1 @exaustive_t7_bad(i8 %base, i8 %offset) {
203; CHECK-LABEL: @exaustive_t7_bad(
204; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
205; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
206; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
207; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
208; CHECK-NEXT:    [[R:%.*]] = or i1 [[NO_UNDERFLOW]], [[NOT_NULL]]
209; CHECK-NEXT:    ret i1 [[R]]
210;
211  %adjusted = sub i8 %base, %offset
212  call void @use8(i8 %adjusted)
213  %not_null = icmp eq i8 %adjusted, 0
214  %no_underflow = icmp ugt i8 %base, %offset
215  %r = or i1 %no_underflow, %not_null
216  ret i1 %r
217}
218
219define i1 @exaustive_t8_bad(i8 %base, i8 %offset) {
220; CHECK-LABEL: @exaustive_t8_bad(
221; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
222; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
223; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
224; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
225; CHECK-NEXT:    [[R:%.*]] = and i1 [[NO_UNDERFLOW]], [[NOT_NULL]]
226; CHECK-NEXT:    ret i1 [[R]]
227;
228  %adjusted = sub i8 %base, %offset
229  call void @use8(i8 %adjusted)
230  %not_null = icmp ne i8 %adjusted, 0
231  %no_underflow = icmp ule i8 %base, %offset
232  %r = and i1 %no_underflow, %not_null
233  ret i1 %r
234}
235
236define i1 @exaustive_t9_true(i8 %base, i8 %offset) {
237; CHECK-LABEL: @exaustive_t9_true(
238; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
239; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
240; CHECK-NEXT:    ret i1 true
241;
242  %adjusted = sub i8 %base, %offset
243  call void @use8(i8 %adjusted)
244  %not_null = icmp ne i8 %adjusted, 0
245  %no_underflow = icmp ule i8 %base, %offset
246  %r = or i1 %no_underflow, %not_null
247  ret i1 %r
248}
249
250define i1 @exaustive_t10_not_null(i8 %base, i8 %offset) {
251; CHECK-LABEL: @exaustive_t10_not_null(
252; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
253; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
254; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
255; CHECK-NEXT:    ret i1 [[NOT_NULL]]
256;
257  %adjusted = sub i8 %base, %offset
258  call void @use8(i8 %adjusted)
259  %not_null = icmp eq i8 %adjusted, 0
260  %no_underflow = icmp ule i8 %base, %offset
261  %r = and i1 %no_underflow, %not_null
262  ret i1 %r
263}
264
265define i1 @exaustive_t11_no_underflow(i8 %base, i8 %offset) {
266; CHECK-LABEL: @exaustive_t11_no_underflow(
267; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
268; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
269; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
270; CHECK-NEXT:    ret i1 [[NO_UNDERFLOW]]
271;
272  %adjusted = sub i8 %base, %offset
273  call void @use8(i8 %adjusted)
274  %not_null = icmp eq i8 %adjusted, 0
275  %no_underflow = icmp ule i8 %base, %offset
276  %r = or i1 %no_underflow, %not_null
277  ret i1 %r
278}
279
280define i1 @exaustive_t12_bad(i8 %base, i8 %offset) {
281; CHECK-LABEL: @exaustive_t12_bad(
282; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
283; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
284; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
285; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
286; CHECK-NEXT:    [[R:%.*]] = and i1 [[NO_UNDERFLOW]], [[NOT_NULL]]
287; CHECK-NEXT:    ret i1 [[R]]
288;
289  %adjusted = sub i8 %base, %offset
290  call void @use8(i8 %adjusted)
291  %not_null = icmp ne i8 %adjusted, 0
292  %no_underflow = icmp uge i8 %base, %offset
293  %r = and i1 %no_underflow, %not_null
294  ret i1 %r
295}
296
297define i1 @exaustive_t13_true(i8 %base, i8 %offset) {
298; CHECK-LABEL: @exaustive_t13_true(
299; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
300; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
301; CHECK-NEXT:    ret i1 true
302;
303  %adjusted = sub i8 %base, %offset
304  call void @use8(i8 %adjusted)
305  %not_null = icmp ne i8 %adjusted, 0
306  %no_underflow = icmp uge i8 %base, %offset
307  %r = or i1 %no_underflow, %not_null
308  ret i1 %r
309}
310
311define i1 @exaustive_t14_not_null(i8 %base, i8 %offset) {
312; CHECK-LABEL: @exaustive_t14_not_null(
313; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
314; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
315; CHECK-NEXT:    [[NOT_NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
316; CHECK-NEXT:    ret i1 [[NOT_NULL]]
317;
318  %adjusted = sub i8 %base, %offset
319  call void @use8(i8 %adjusted)
320  %not_null = icmp eq i8 %adjusted, 0
321  %no_underflow = icmp uge i8 %base, %offset
322  %r = and i1 %no_underflow, %not_null
323  ret i1 %r
324}
325
326define i1 @exaustive_t15_no_underflow(i8 %base, i8 %offset) {
327; CHECK-LABEL: @exaustive_t15_no_underflow(
328; CHECK-NEXT:    [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
329; CHECK-NEXT:    call void @use8(i8 [[ADJUSTED]])
330; CHECK-NEXT:    [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
331; CHECK-NEXT:    ret i1 [[NO_UNDERFLOW]]
332;
333  %adjusted = sub i8 %base, %offset
334  call void @use8(i8 %adjusted)
335  %not_null = icmp eq i8 %adjusted, 0
336  %no_underflow = icmp uge i8 %base, %offset
337  %r = or i1 %no_underflow, %not_null
338  ret i1 %r
339}
340