1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes=correlated-propagation < %s | FileCheck %s
3
4declare void @llvm.trap()
5declare {i8, i1} @llvm.uadd.with.overflow(i8, i8)
6declare {i8, i1} @llvm.sadd.with.overflow(i8, i8)
7declare {i8, i1} @llvm.usub.with.overflow(i8, i8)
8declare {i8, i1} @llvm.ssub.with.overflow(i8, i8)
9declare {i8, i1} @llvm.umul.with.overflow(i8, i8)
10declare {i8, i1} @llvm.smul.with.overflow(i8, i8)
11
12define i1 @uadd_ov_false(i8 %x, i8* %px, i1* %pc) {
13; CHECK-LABEL: @uadd_ov_false(
14; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[X:%.*]], i8 100)
15; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
16; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
17; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
18; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
19; CHECK:       no_overflow:
20; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i8 [[X]], -102
21; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
22; CHECK-NEXT:    ret i1 false
23; CHECK:       trap:
24; CHECK-NEXT:    call void @llvm.trap()
25; CHECK-NEXT:    unreachable
26;
27  %val_ov = call {i8, i1} @llvm.uadd.with.overflow(i8 %x, i8 100)
28  %val = extractvalue {i8, i1} %val_ov, 0
29  store i8 %val, i8* %px
30  %ov = extractvalue {i8, i1} %val_ov, 1
31  br i1 %ov, label %trap, label %no_overflow
32
33no_overflow:
34  %c1 = icmp ugt i8 %x, 154
35  store i1 %c1, i1* %pc
36  %c2 = icmp ugt i8 %x, 155
37  ret i1 %c2
38
39trap:
40  call void @llvm.trap()
41  unreachable
42}
43
44define i1 @uadd_ov_true(i8 %x, i8* %px, i1* %pc) {
45; CHECK-LABEL: @uadd_ov_true(
46; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[X:%.*]], i8 100)
47; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
48; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
49; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
50; CHECK-NEXT:    br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]]
51; CHECK:       overflow:
52; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i8 [[X]], -100
53; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
54; CHECK-NEXT:    ret i1 true
55; CHECK:       trap:
56; CHECK-NEXT:    call void @llvm.trap()
57; CHECK-NEXT:    unreachable
58;
59  %val_ov = call {i8, i1} @llvm.uadd.with.overflow(i8 %x, i8 100)
60  %val = extractvalue {i8, i1} %val_ov, 0
61  store i8 %val, i8* %px
62  %ov = extractvalue {i8, i1} %val_ov, 1
63  br i1 %ov, label %overflow, label %trap
64
65overflow:
66  %c1 = icmp ugt i8 %x, 156
67  store i1 %c1, i1* %pc
68  %c2 = icmp ugt i8 %x, 155
69  ret i1 %c2
70
71trap:
72  call void @llvm.trap()
73  unreachable
74}
75
76define i1 @sadd_ov_false(i8 %x, i8* %px, i1* %pc) {
77; CHECK-LABEL: @sadd_ov_false(
78; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[X:%.*]], i8 100)
79; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
80; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
81; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
82; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
83; CHECK:       no_overflow:
84; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i8 [[X]], 26
85; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
86; CHECK-NEXT:    ret i1 false
87; CHECK:       trap:
88; CHECK-NEXT:    call void @llvm.trap()
89; CHECK-NEXT:    unreachable
90;
91  %val_ov = call {i8, i1} @llvm.sadd.with.overflow(i8 %x, i8 100)
92  %val = extractvalue {i8, i1} %val_ov, 0
93  store i8 %val, i8* %px
94  %ov = extractvalue {i8, i1} %val_ov, 1
95  br i1 %ov, label %trap, label %no_overflow
96
97no_overflow:
98  %c1 = icmp sgt i8 %x, 26
99  store i1 %c1, i1* %pc
100  %c2 = icmp sgt i8 %x, 27
101  ret i1 %c2
102
103trap:
104  call void @llvm.trap()
105  unreachable
106}
107
108define i1 @sadd_ov_true(i8 %x, i8* %px, i1* %pc) {
109; CHECK-LABEL: @sadd_ov_true(
110; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[X:%.*]], i8 100)
111; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
112; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
113; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
114; CHECK-NEXT:    br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]]
115; CHECK:       overflow:
116; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i8 [[X]], 28
117; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
118; CHECK-NEXT:    ret i1 true
119; CHECK:       trap:
120; CHECK-NEXT:    call void @llvm.trap()
121; CHECK-NEXT:    unreachable
122;
123  %val_ov = call {i8, i1} @llvm.sadd.with.overflow(i8 %x, i8 100)
124  %val = extractvalue {i8, i1} %val_ov, 0
125  store i8 %val, i8* %px
126  %ov = extractvalue {i8, i1} %val_ov, 1
127  br i1 %ov, label %overflow, label %trap
128
129overflow:
130  %c1 = icmp sgt i8 %x, 28
131  store i1 %c1, i1* %pc
132  %c2 = icmp sgt i8 %x, 27
133  ret i1 %c2
134
135trap:
136  call void @llvm.trap()
137  unreachable
138}
139
140define i1 @usub_ov_false(i8 %x, i8* %px, i1* %pc) {
141; CHECK-LABEL: @usub_ov_false(
142; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 100)
143; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
144; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
145; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
146; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
147; CHECK:       no_overflow:
148; CHECK-NEXT:    [[C1:%.*]] = icmp ult i8 [[X]], 101
149; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
150; CHECK-NEXT:    ret i1 false
151; CHECK:       trap:
152; CHECK-NEXT:    call void @llvm.trap()
153; CHECK-NEXT:    unreachable
154;
155  %val_ov = call {i8, i1} @llvm.usub.with.overflow(i8 %x, i8 100)
156  %val = extractvalue {i8, i1} %val_ov, 0
157  store i8 %val, i8* %px
158  %ov = extractvalue {i8, i1} %val_ov, 1
159  br i1 %ov, label %trap, label %no_overflow
160
161no_overflow:
162  %c1 = icmp ult i8 %x, 101
163  store i1 %c1, i1* %pc
164  %c2 = icmp ult i8 %x, 100
165  ret i1 %c2
166
167trap:
168  call void @llvm.trap()
169  unreachable
170}
171
172define i1 @usub_ov_true(i8 %x, i8* %px, i1* %pc) {
173; CHECK-LABEL: @usub_ov_true(
174; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 100)
175; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
176; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
177; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
178; CHECK-NEXT:    br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]]
179; CHECK:       overflow:
180; CHECK-NEXT:    [[C1:%.*]] = icmp ult i8 [[X]], 99
181; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
182; CHECK-NEXT:    ret i1 true
183; CHECK:       trap:
184; CHECK-NEXT:    call void @llvm.trap()
185; CHECK-NEXT:    unreachable
186;
187  %val_ov = call {i8, i1} @llvm.usub.with.overflow(i8 %x, i8 100)
188  %val = extractvalue {i8, i1} %val_ov, 0
189  store i8 %val, i8* %px
190  %ov = extractvalue {i8, i1} %val_ov, 1
191  br i1 %ov, label %overflow, label %trap
192
193overflow:
194  %c1 = icmp ult i8 %x, 99
195  store i1 %c1, i1* %pc
196  %c2 = icmp ult i8 %x, 100
197  ret i1 %c2
198
199trap:
200  call void @llvm.trap()
201  unreachable
202}
203
204define i1 @ssub_ov_false(i8 %x, i8* %px, i1* %pc) {
205; CHECK-LABEL: @ssub_ov_false(
206; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 100)
207; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
208; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
209; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
210; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
211; CHECK:       no_overflow:
212; CHECK-NEXT:    [[C1:%.*]] = icmp slt i8 [[X]], -27
213; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
214; CHECK-NEXT:    ret i1 false
215; CHECK:       trap:
216; CHECK-NEXT:    call void @llvm.trap()
217; CHECK-NEXT:    unreachable
218;
219  %val_ov = call {i8, i1} @llvm.ssub.with.overflow(i8 %x, i8 100)
220  %val = extractvalue {i8, i1} %val_ov, 0
221  store i8 %val, i8* %px
222  %ov = extractvalue {i8, i1} %val_ov, 1
223  br i1 %ov, label %trap, label %no_overflow
224
225no_overflow:
226  %c1 = icmp slt i8 %x, -27
227  store i1 %c1, i1* %pc
228  %c2 = icmp slt i8 %x, -28
229  ret i1 %c2
230
231trap:
232  call void @llvm.trap()
233  unreachable
234}
235
236define i1 @ssub_ov_true(i8 %x, i8* %px, i1* %pc) {
237; CHECK-LABEL: @ssub_ov_true(
238; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 100)
239; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
240; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
241; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
242; CHECK-NEXT:    br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]]
243; CHECK:       overflow:
244; CHECK-NEXT:    [[C1:%.*]] = icmp ult i8 [[X]], -29
245; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
246; CHECK-NEXT:    ret i1 true
247; CHECK:       trap:
248; CHECK-NEXT:    call void @llvm.trap()
249; CHECK-NEXT:    unreachable
250;
251  %val_ov = call {i8, i1} @llvm.ssub.with.overflow(i8 %x, i8 100)
252  %val = extractvalue {i8, i1} %val_ov, 0
253  store i8 %val, i8* %px
254  %ov = extractvalue {i8, i1} %val_ov, 1
255  br i1 %ov, label %overflow, label %trap
256
257overflow:
258  %c1 = icmp slt i8 %x, -29
259  store i1 %c1, i1* %pc
260  %c2 = icmp slt i8 %x, -28
261  ret i1 %c2
262
263trap:
264  call void @llvm.trap()
265  unreachable
266}
267
268define i1 @umul_ov_false(i8 %x, i8* %px, i1* %pc) {
269; CHECK-LABEL: @umul_ov_false(
270; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[X:%.*]], i8 10)
271; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
272; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
273; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
274; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
275; CHECK:       no_overflow:
276; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i8 [[X]], 24
277; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
278; CHECK-NEXT:    ret i1 false
279; CHECK:       trap:
280; CHECK-NEXT:    call void @llvm.trap()
281; CHECK-NEXT:    unreachable
282;
283  %val_ov = call {i8, i1} @llvm.umul.with.overflow(i8 %x, i8 10)
284  %val = extractvalue {i8, i1} %val_ov, 0
285  store i8 %val, i8* %px
286  %ov = extractvalue {i8, i1} %val_ov, 1
287  br i1 %ov, label %trap, label %no_overflow
288
289no_overflow:
290  %c1 = icmp ugt i8 %x, 24
291  store i1 %c1, i1* %pc
292  %c2 = icmp ugt i8 %x, 25
293  ret i1 %c2
294
295trap:
296  call void @llvm.trap()
297  unreachable
298}
299
300define i1 @umul_ov_true(i8 %x, i8* %px, i1* %pc) {
301; CHECK-LABEL: @umul_ov_true(
302; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[X:%.*]], i8 10)
303; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
304; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
305; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
306; CHECK-NEXT:    br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]]
307; CHECK:       overflow:
308; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i8 [[X]], 26
309; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
310; CHECK-NEXT:    ret i1 true
311; CHECK:       trap:
312; CHECK-NEXT:    call void @llvm.trap()
313; CHECK-NEXT:    unreachable
314;
315  %val_ov = call {i8, i1} @llvm.umul.with.overflow(i8 %x, i8 10)
316  %val = extractvalue {i8, i1} %val_ov, 0
317  store i8 %val, i8* %px
318  %ov = extractvalue {i8, i1} %val_ov, 1
319  br i1 %ov, label %overflow, label %trap
320
321overflow:
322  %c1 = icmp ugt i8 %x, 26
323  store i1 %c1, i1* %pc
324  %c2 = icmp ugt i8 %x, 25
325  ret i1 %c2
326
327trap:
328  call void @llvm.trap()
329  unreachable
330}
331
332; Signed mul is constrained from both sides.
333define i1 @smul_ov_false_bound1(i8 %x, i8* %px, i1* %pc) {
334; CHECK-LABEL: @smul_ov_false_bound1(
335; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10)
336; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
337; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
338; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
339; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
340; CHECK:       no_overflow:
341; CHECK-NEXT:    [[C1:%.*]] = icmp slt i8 [[X]], -11
342; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
343; CHECK-NEXT:    ret i1 false
344; CHECK:       trap:
345; CHECK-NEXT:    call void @llvm.trap()
346; CHECK-NEXT:    unreachable
347;
348  %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10)
349  %val = extractvalue {i8, i1} %val_ov, 0
350  store i8 %val, i8* %px
351  %ov = extractvalue {i8, i1} %val_ov, 1
352  br i1 %ov, label %trap, label %no_overflow
353
354no_overflow:
355  %c1 = icmp slt i8 %x, -11
356  store i1 %c1, i1* %pc
357  %c2 = icmp slt i8 %x, -12
358  ret i1 %c2
359
360trap:
361  call void @llvm.trap()
362  unreachable
363}
364
365define i1 @smul_ov_false_bound2(i8 %x, i8* %px, i1* %pc) {
366; CHECK-LABEL: @smul_ov_false_bound2(
367; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10)
368; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
369; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
370; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
371; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
372; CHECK:       no_overflow:
373; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i8 [[X]], 11
374; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
375; CHECK-NEXT:    ret i1 false
376; CHECK:       trap:
377; CHECK-NEXT:    call void @llvm.trap()
378; CHECK-NEXT:    unreachable
379;
380  %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10)
381  %val = extractvalue {i8, i1} %val_ov, 0
382  store i8 %val, i8* %px
383  %ov = extractvalue {i8, i1} %val_ov, 1
384  br i1 %ov, label %trap, label %no_overflow
385
386no_overflow:
387  %c1 = icmp sgt i8 %x, 11
388  store i1 %c1, i1* %pc
389  %c2 = icmp sgt i8 %x, 12
390  ret i1 %c2
391
392trap:
393  call void @llvm.trap()
394  unreachable
395}
396
397; Can't use slt/sgt to test for a hole in the range, check equality instead.
398define i1 @smul_ov_true_bound1(i8 %x, i8* %px, i1* %pc) {
399; CHECK-LABEL: @smul_ov_true_bound1(
400; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10)
401; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
402; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
403; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
404; CHECK-NEXT:    br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]]
405; CHECK:       overflow:
406; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[X]], -13
407; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
408; CHECK-NEXT:    ret i1 false
409; CHECK:       trap:
410; CHECK-NEXT:    call void @llvm.trap()
411; CHECK-NEXT:    unreachable
412;
413  %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10)
414  %val = extractvalue {i8, i1} %val_ov, 0
415  store i8 %val, i8* %px
416  %ov = extractvalue {i8, i1} %val_ov, 1
417  br i1 %ov, label %overflow, label %trap
418
419overflow:
420  %c1 = icmp eq i8 %x, -13
421  store i1 %c1, i1* %pc
422  %c2 = icmp eq i8 %x, -12
423  ret i1 %c2
424
425trap:
426  call void @llvm.trap()
427  unreachable
428}
429
430define i1 @smul_ov_true_bound2(i8 %x, i8* %px, i1* %pc) {
431; CHECK-LABEL: @smul_ov_true_bound2(
432; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10)
433; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
434; CHECK-NEXT:    store i8 [[VAL]], i8* [[PX:%.*]], align 1
435; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
436; CHECK-NEXT:    br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]]
437; CHECK:       overflow:
438; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[X]], 13
439; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
440; CHECK-NEXT:    ret i1 false
441; CHECK:       trap:
442; CHECK-NEXT:    call void @llvm.trap()
443; CHECK-NEXT:    unreachable
444;
445  %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10)
446  %val = extractvalue {i8, i1} %val_ov, 0
447  store i8 %val, i8* %px
448  %ov = extractvalue {i8, i1} %val_ov, 1
449  br i1 %ov, label %overflow, label %trap
450
451overflow:
452  %c1 = icmp eq i8 %x, 13
453  store i1 %c1, i1* %pc
454  %c2 = icmp eq i8 %x, 12
455  ret i1 %c2
456
457trap:
458  call void @llvm.trap()
459  unreachable
460}
461
462define i1 @uadd_val(i8 %x, i1* %pc) {
463; CHECK-LABEL: @uadd_val(
464; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[X:%.*]], i8 100)
465; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
466; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
467; CHECK:       no_overflow:
468; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
469; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i8 [[VAL]], 100
470; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
471; CHECK-NEXT:    ret i1 true
472; CHECK:       trap:
473; CHECK-NEXT:    call void @llvm.trap()
474; CHECK-NEXT:    unreachable
475;
476  %val_ov = call {i8, i1} @llvm.uadd.with.overflow(i8 %x, i8 100)
477  %ov = extractvalue {i8, i1} %val_ov, 1
478  br i1 %ov, label %trap, label %no_overflow
479
480no_overflow:
481  %val = extractvalue {i8, i1} %val_ov, 0
482  %c1 = icmp ugt i8 %val, 100
483  store i1 %c1, i1* %pc
484  %c2 = icmp uge i8 %val, 100
485  ret i1 %c2
486
487trap:
488  call void @llvm.trap()
489  unreachable
490}
491
492define i1 @sadd_val(i8 %x, i1* %pc) {
493; CHECK-LABEL: @sadd_val(
494; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[X:%.*]], i8 100)
495; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
496; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
497; CHECK:       no_overflow:
498; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
499; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i8 [[VAL]], -28
500; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
501; CHECK-NEXT:    ret i1 true
502; CHECK:       trap:
503; CHECK-NEXT:    call void @llvm.trap()
504; CHECK-NEXT:    unreachable
505;
506  %val_ov = call {i8, i1} @llvm.sadd.with.overflow(i8 %x, i8 100)
507  %ov = extractvalue {i8, i1} %val_ov, 1
508  br i1 %ov, label %trap, label %no_overflow
509
510no_overflow:
511  %val = extractvalue {i8, i1} %val_ov, 0
512  %c1 = icmp sgt i8 %val, -28
513  store i1 %c1, i1* %pc
514  %c2 = icmp sge i8 %val, -28
515  ret i1 %c2
516
517trap:
518  call void @llvm.trap()
519  unreachable
520}
521
522define i1 @usub_val(i8 %x, i1* %pc) {
523; CHECK-LABEL: @usub_val(
524; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 100)
525; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
526; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
527; CHECK:       no_overflow:
528; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
529; CHECK-NEXT:    [[C1:%.*]] = icmp ult i8 [[VAL]], -101
530; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
531; CHECK-NEXT:    ret i1 true
532; CHECK:       trap:
533; CHECK-NEXT:    call void @llvm.trap()
534; CHECK-NEXT:    unreachable
535;
536  %val_ov = call {i8, i1} @llvm.usub.with.overflow(i8 %x, i8 100)
537  %ov = extractvalue {i8, i1} %val_ov, 1
538  br i1 %ov, label %trap, label %no_overflow
539
540no_overflow:
541  %val = extractvalue {i8, i1} %val_ov, 0
542  %c1 = icmp ult i8 %val, 155
543  store i1 %c1, i1* %pc
544  %c2 = icmp ule i8 %val, 155
545  ret i1 %c2
546
547trap:
548  call void @llvm.trap()
549  unreachable
550}
551
552define i1 @ssub_val(i8 %x, i1* %pc) {
553; CHECK-LABEL: @ssub_val(
554; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 100)
555; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
556; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
557; CHECK:       no_overflow:
558; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
559; CHECK-NEXT:    [[C1:%.*]] = icmp slt i8 [[VAL]], 27
560; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
561; CHECK-NEXT:    ret i1 true
562; CHECK:       trap:
563; CHECK-NEXT:    call void @llvm.trap()
564; CHECK-NEXT:    unreachable
565;
566  %val_ov = call {i8, i1} @llvm.ssub.with.overflow(i8 %x, i8 100)
567  %ov = extractvalue {i8, i1} %val_ov, 1
568  br i1 %ov, label %trap, label %no_overflow
569
570no_overflow:
571  %val = extractvalue {i8, i1} %val_ov, 0
572  %c1 = icmp slt i8 %val, 27
573  store i1 %c1, i1* %pc
574  %c2 = icmp sle i8 %val, 27
575  ret i1 %c2
576
577trap:
578  call void @llvm.trap()
579  unreachable
580}
581
582define i1 @umul_val(i8 %x, i1* %pc) {
583; CHECK-LABEL: @umul_val(
584; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[X:%.*]], i8 10)
585; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
586; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
587; CHECK:       no_overflow:
588; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
589; CHECK-NEXT:    [[C1:%.*]] = icmp ult i8 [[VAL]], -6
590; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
591; CHECK-NEXT:    ret i1 true
592; CHECK:       trap:
593; CHECK-NEXT:    call void @llvm.trap()
594; CHECK-NEXT:    unreachable
595;
596  %val_ov = call {i8, i1} @llvm.umul.with.overflow(i8 %x, i8 10)
597  %ov = extractvalue {i8, i1} %val_ov, 1
598  br i1 %ov, label %trap, label %no_overflow
599
600no_overflow:
601  %val = extractvalue {i8, i1} %val_ov, 0
602  %c1 = icmp ult i8 %val, 250
603  store i1 %c1, i1* %pc
604  %c2 = icmp ule i8 %val, 250
605  ret i1 %c2
606
607trap:
608  call void @llvm.trap()
609  unreachable
610}
611
612define i1 @smul_val_bound1(i8 %x, i1* %pc) {
613; CHECK-LABEL: @smul_val_bound1(
614; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10)
615; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
616; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
617; CHECK:       no_overflow:
618; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
619; CHECK-NEXT:    [[C1:%.*]] = icmp slt i8 [[VAL]], 120
620; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
621; CHECK-NEXT:    ret i1 true
622; CHECK:       trap:
623; CHECK-NEXT:    call void @llvm.trap()
624; CHECK-NEXT:    unreachable
625;
626  %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10)
627  %ov = extractvalue {i8, i1} %val_ov, 1
628  br i1 %ov, label %trap, label %no_overflow
629
630no_overflow:
631  %val = extractvalue {i8, i1} %val_ov, 0
632  %c1 = icmp slt i8 %val, 120
633  store i1 %c1, i1* %pc
634  %c2 = icmp sle i8 %val, 120
635  ret i1 %c2
636
637trap:
638  call void @llvm.trap()
639  unreachable
640}
641
642define i1 @smul_val_bound2(i8 %x, i1* %pc) {
643; CHECK-LABEL: @smul_val_bound2(
644; CHECK-NEXT:    [[VAL_OV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[X:%.*]], i8 10)
645; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1
646; CHECK-NEXT:    br i1 [[OV]], label [[TRAP:%.*]], label [[NO_OVERFLOW:%.*]]
647; CHECK:       no_overflow:
648; CHECK-NEXT:    [[VAL:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 0
649; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i8 [[VAL]], -120
650; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]], align 1
651; CHECK-NEXT:    ret i1 true
652; CHECK:       trap:
653; CHECK-NEXT:    call void @llvm.trap()
654; CHECK-NEXT:    unreachable
655;
656  %val_ov = call {i8, i1} @llvm.smul.with.overflow(i8 %x, i8 10)
657  %ov = extractvalue {i8, i1} %val_ov, 1
658  br i1 %ov, label %trap, label %no_overflow
659
660no_overflow:
661  %val = extractvalue {i8, i1} %val_ov, 0
662  %c1 = icmp sgt i8 %val, -120
663  store i1 %c1, i1* %pc
664  %c2 = icmp sge i8 %val, -120
665  ret i1 %c2
666
667trap:
668  call void @llvm.trap()
669  unreachable
670}
671