1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s
3
4declare { i128, i1 } @llvm.uadd.with.overflow.i128(i128, i128)
5declare   i128       @llvm.uadd.sat.i128(i128, i128)
6
7declare { i128, i1 } @llvm.usub.with.overflow.i128(i128, i128)
8declare   i128       @llvm.usub.sat.i128(i128, i128)
9
10declare { i128, i1 } @llvm.umul.with.overflow.i128(i128, i128)
11declare   i128       @llvm.umul.sat.i128(i128, i128)
12
13declare { i128, i1 } @llvm.sadd.with.overflow.i128(i128, i128)
14declare   i128       @llvm.sadd.sat.i128(i128, i128)
15
16declare { i128, i1 } @llvm.ssub.with.overflow.i128(i128, i128)
17declare   i128       @llvm.ssub.sat.i128(i128, i128)
18
19declare { i128, i1 } @llvm.smul.with.overflow.i128(i128, i128)
20declare   i128       @llvm.smul.sat.i128(i128, i128)
21
22define i128 @u128_add(i128 %x, i128 %y) {
23; CHECK-LABEL: u128_add:
24; CHECK:       // %bb.0:
25; CHECK-NEXT:    adds x0, x0, x2
26; CHECK-NEXT:    adcs x1, x1, x3
27; CHECK-NEXT:    ret
28  %1 = add i128 %x, %y
29  ret i128 %1
30}
31
32define { i128, i8 } @u128_checked_add(i128 %x, i128 %y) {
33; CHECK-LABEL: u128_checked_add:
34; CHECK:       // %bb.0:
35; CHECK-NEXT:    adds x0, x0, x2
36; CHECK-NEXT:    adcs x1, x1, x3
37; CHECK-NEXT:    cset w8, hs
38; CHECK-NEXT:    eor w2, w8, #0x1
39; CHECK-NEXT:    ret
40  %1 = tail call { i128, i1 } @llvm.uadd.with.overflow.i128(i128 %x, i128 %y)
41  %2 = extractvalue { i128, i1 } %1, 0
42  %3 = extractvalue { i128, i1 } %1, 1
43  %4 = xor i1 %3, true
44  %5 = zext i1 %4 to i8
45  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
46  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
47  ret { i128, i8 } %7
48}
49
50define { i128, i8 } @u128_overflowing_add(i128 %x, i128 %y) {
51; CHECK-LABEL: u128_overflowing_add:
52; CHECK:       // %bb.0:
53; CHECK-NEXT:    adds x0, x0, x2
54; CHECK-NEXT:    adcs x1, x1, x3
55; CHECK-NEXT:    cset w2, hs
56; CHECK-NEXT:    ret
57  %1 = tail call { i128, i1 } @llvm.uadd.with.overflow.i128(i128 %x, i128 %y)
58  %2 = extractvalue { i128, i1 } %1, 0
59  %3 = extractvalue { i128, i1 } %1, 1
60  %4 = zext i1 %3 to i8
61  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
62  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
63  ret { i128, i8 } %6
64}
65
66define i128 @u128_saturating_add(i128 %x, i128 %y) {
67; CHECK-LABEL: u128_saturating_add:
68; CHECK:       // %bb.0:
69; CHECK-NEXT:    adds x8, x0, x2
70; CHECK-NEXT:    adcs x9, x1, x3
71; CHECK-NEXT:    cset w10, hs
72; CHECK-NEXT:    cmp w10, #0
73; CHECK-NEXT:    csinv x0, x8, xzr, eq
74; CHECK-NEXT:    csinv x1, x9, xzr, eq
75; CHECK-NEXT:    ret
76  %1 = tail call i128 @llvm.uadd.sat.i128(i128 %x, i128 %y)
77  ret i128 %1
78}
79
80define i128 @u128_sub(i128 %x, i128 %y) {
81; CHECK-LABEL: u128_sub:
82; CHECK:       // %bb.0:
83; CHECK-NEXT:    subs x0, x0, x2
84; CHECK-NEXT:    sbcs x1, x1, x3
85; CHECK-NEXT:    ret
86  %1 = sub i128 %x, %y
87  ret i128 %1
88}
89
90define { i128, i8 } @u128_checked_sub(i128 %x, i128 %y) {
91; CHECK-LABEL: u128_checked_sub:
92; CHECK:       // %bb.0:
93; CHECK-NEXT:    subs x0, x0, x2
94; CHECK-NEXT:    sbcs x1, x1, x3
95; CHECK-NEXT:    cset w8, lo
96; CHECK-NEXT:    eor w2, w8, #0x1
97; CHECK-NEXT:    ret
98  %1 = tail call { i128, i1 } @llvm.usub.with.overflow.i128(i128 %x, i128 %y)
99  %2 = extractvalue { i128, i1 } %1, 0
100  %3 = extractvalue { i128, i1 } %1, 1
101  %4 = xor i1 %3, true
102  %5 = zext i1 %4 to i8
103  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
104  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
105  ret { i128, i8 } %7
106}
107
108define { i128, i8 } @u128_overflowing_sub(i128 %x, i128 %y) {
109; CHECK-LABEL: u128_overflowing_sub:
110; CHECK:       // %bb.0:
111; CHECK-NEXT:    subs x0, x0, x2
112; CHECK-NEXT:    sbcs x1, x1, x3
113; CHECK-NEXT:    cset w2, lo
114; CHECK-NEXT:    ret
115  %1 = tail call { i128, i1 } @llvm.usub.with.overflow.i128(i128 %x, i128 %y)
116  %2 = extractvalue { i128, i1 } %1, 0
117  %3 = extractvalue { i128, i1 } %1, 1
118  %4 = zext i1 %3 to i8
119  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
120  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
121  ret { i128, i8 } %6
122}
123
124define i128 @u128_saturating_sub(i128 %x, i128 %y) {
125; CHECK-LABEL: u128_saturating_sub:
126; CHECK:       // %bb.0:
127; CHECK-NEXT:    subs x8, x0, x2
128; CHECK-NEXT:    sbcs x9, x1, x3
129; CHECK-NEXT:    cset w10, lo
130; CHECK-NEXT:    cmp w10, #0
131; CHECK-NEXT:    csel x0, xzr, x8, ne
132; CHECK-NEXT:    csel x1, xzr, x9, ne
133; CHECK-NEXT:    ret
134  %1 = tail call i128 @llvm.usub.sat.i128(i128 %x, i128 %y)
135  ret i128 %1
136}
137
138define i128 @i128_add(i128 %x, i128 %y) {
139; CHECK-LABEL: i128_add:
140; CHECK:       // %bb.0:
141; CHECK-NEXT:    adds x0, x0, x2
142; CHECK-NEXT:    adcs x1, x1, x3
143; CHECK-NEXT:    ret
144  %1 = add i128 %x, %y
145  ret i128 %1
146}
147
148define { i128, i8 } @i128_checked_add(i128 %x, i128 %y) {
149; CHECK-LABEL: i128_checked_add:
150; CHECK:       // %bb.0:
151; CHECK-NEXT:    adds x0, x0, x2
152; CHECK-NEXT:    adcs x1, x1, x3
153; CHECK-NEXT:    cset w8, vs
154; CHECK-NEXT:    eor w2, w8, #0x1
155; CHECK-NEXT:    ret
156  %1 = tail call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %x, i128 %y)
157  %2 = extractvalue { i128, i1 } %1, 0
158  %3 = extractvalue { i128, i1 } %1, 1
159  %4 = xor i1 %3, true
160  %5 = zext i1 %4 to i8
161  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
162  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
163  ret { i128, i8 } %7
164}
165
166define { i128, i8 } @i128_overflowing_add(i128 %x, i128 %y) {
167; CHECK-LABEL: i128_overflowing_add:
168; CHECK:       // %bb.0:
169; CHECK-NEXT:    adds x0, x0, x2
170; CHECK-NEXT:    adcs x1, x1, x3
171; CHECK-NEXT:    cset w2, vs
172; CHECK-NEXT:    ret
173  %1 = tail call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %x, i128 %y)
174  %2 = extractvalue { i128, i1 } %1, 0
175  %3 = extractvalue { i128, i1 } %1, 1
176  %4 = zext i1 %3 to i8
177  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
178  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
179  ret { i128, i8 } %6
180}
181
182define i128 @i128_saturating_add(i128 %x, i128 %y) {
183; CHECK-LABEL: i128_saturating_add:
184; CHECK:       // %bb.0:
185; CHECK-NEXT:    adds x8, x0, x2
186; CHECK-NEXT:    adcs x9, x1, x3
187; CHECK-NEXT:    asr x10, x9, #63
188; CHECK-NEXT:    cset w11, vs
189; CHECK-NEXT:    cmp w11, #0
190; CHECK-NEXT:    eor x11, x10, #0x8000000000000000
191; CHECK-NEXT:    csel x0, x10, x8, ne
192; CHECK-NEXT:    csel x1, x11, x9, ne
193; CHECK-NEXT:    ret
194  %1 = tail call i128 @llvm.sadd.sat.i128(i128 %x, i128 %y)
195  ret i128 %1
196}
197
198define i128 @i128_sub(i128 %x, i128 %y) {
199; CHECK-LABEL: i128_sub:
200; CHECK:       // %bb.0:
201; CHECK-NEXT:    subs x0, x0, x2
202; CHECK-NEXT:    sbcs x1, x1, x3
203; CHECK-NEXT:    ret
204  %1 = sub i128 %x, %y
205  ret i128 %1
206}
207
208define { i128, i8 } @i128_checked_sub(i128 %x, i128 %y) {
209; CHECK-LABEL: i128_checked_sub:
210; CHECK:       // %bb.0:
211; CHECK-NEXT:    subs x0, x0, x2
212; CHECK-NEXT:    sbcs x1, x1, x3
213; CHECK-NEXT:    cset w8, vs
214; CHECK-NEXT:    eor w2, w8, #0x1
215; CHECK-NEXT:    ret
216  %1 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %x, i128 %y)
217  %2 = extractvalue { i128, i1 } %1, 0
218  %3 = extractvalue { i128, i1 } %1, 1
219  %4 = xor i1 %3, true
220  %5 = zext i1 %4 to i8
221  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
222  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
223  ret { i128, i8 } %7
224}
225
226define { i128, i8 } @i128_overflowing_sub(i128 %x, i128 %y) {
227; CHECK-LABEL: i128_overflowing_sub:
228; CHECK:       // %bb.0:
229; CHECK-NEXT:    subs x0, x0, x2
230; CHECK-NEXT:    sbcs x1, x1, x3
231; CHECK-NEXT:    cset w2, vs
232; CHECK-NEXT:    ret
233  %1 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %x, i128 %y)
234  %2 = extractvalue { i128, i1 } %1, 0
235  %3 = extractvalue { i128, i1 } %1, 1
236  %4 = zext i1 %3 to i8
237  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
238  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
239  ret { i128, i8 } %6
240}
241
242define i128 @i128_saturating_sub(i128 %x, i128 %y) {
243; CHECK-LABEL: i128_saturating_sub:
244; CHECK:       // %bb.0:
245; CHECK-NEXT:    subs x8, x0, x2
246; CHECK-NEXT:    sbcs x9, x1, x3
247; CHECK-NEXT:    asr x10, x9, #63
248; CHECK-NEXT:    cset w11, vs
249; CHECK-NEXT:    cmp w11, #0
250; CHECK-NEXT:    eor x11, x10, #0x8000000000000000
251; CHECK-NEXT:    csel x0, x10, x8, ne
252; CHECK-NEXT:    csel x1, x11, x9, ne
253; CHECK-NEXT:    ret
254  %1 = tail call i128 @llvm.ssub.sat.i128(i128 %x, i128 %y)
255  ret i128 %1
256}
257
258define i128 @u128_mul(i128 %x, i128 %y) {
259; CHECK-LABEL: u128_mul:
260; CHECK:       // %bb.0:
261; CHECK-NEXT:    umulh x8, x0, x2
262; CHECK-NEXT:    madd x8, x0, x3, x8
263; CHECK-NEXT:    mul x0, x0, x2
264; CHECK-NEXT:    madd x1, x1, x2, x8
265; CHECK-NEXT:    ret
266  %1 = mul i128 %x, %y
267  ret i128 %1
268}
269
270define { i128, i8 } @u128_checked_mul(i128 %x, i128 %y) {
271; CHECK-LABEL: u128_checked_mul:
272; CHECK:       // %bb.0:
273; CHECK-NEXT:    mul x8, x3, x0
274; CHECK-NEXT:    umulh x9, x0, x2
275; CHECK-NEXT:    madd x8, x1, x2, x8
276; CHECK-NEXT:    umulh x10, x1, x2
277; CHECK-NEXT:    adds x8, x9, x8
278; CHECK-NEXT:    cset w9, hs
279; CHECK-NEXT:    cmp x1, #0
280; CHECK-NEXT:    ccmp x3, #0, #4, ne
281; CHECK-NEXT:    mov x1, x8
282; CHECK-NEXT:    ccmp xzr, x10, #0, eq
283; CHECK-NEXT:    umulh x10, x3, x0
284; CHECK-NEXT:    mul x0, x0, x2
285; CHECK-NEXT:    ccmp xzr, x10, #0, eq
286; CHECK-NEXT:    cset w10, ne
287; CHECK-NEXT:    orr w9, w10, w9
288; CHECK-NEXT:    eor w2, w9, #0x1
289; CHECK-NEXT:    ret
290  %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
291  %2 = extractvalue { i128, i1 } %1, 0
292  %3 = extractvalue { i128, i1 } %1, 1
293  %4 = xor i1 %3, true
294  %5 = zext i1 %4 to i8
295  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
296  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
297  ret { i128, i8 } %7
298}
299
300define { i128, i8 } @u128_overflowing_mul(i128 %x, i128 %y) {
301; CHECK-LABEL: u128_overflowing_mul:
302; CHECK:       // %bb.0:
303; CHECK-NEXT:    mul x8, x3, x0
304; CHECK-NEXT:    umulh x9, x0, x2
305; CHECK-NEXT:    madd x8, x1, x2, x8
306; CHECK-NEXT:    umulh x10, x1, x2
307; CHECK-NEXT:    adds x8, x9, x8
308; CHECK-NEXT:    cset w9, hs
309; CHECK-NEXT:    cmp x1, #0
310; CHECK-NEXT:    ccmp x3, #0, #4, ne
311; CHECK-NEXT:    mov x1, x8
312; CHECK-NEXT:    ccmp xzr, x10, #0, eq
313; CHECK-NEXT:    umulh x10, x3, x0
314; CHECK-NEXT:    mul x0, x0, x2
315; CHECK-NEXT:    ccmp xzr, x10, #0, eq
316; CHECK-NEXT:    cset w10, ne
317; CHECK-NEXT:    orr w2, w10, w9
318; CHECK-NEXT:    ret
319  %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
320  %2 = extractvalue { i128, i1 } %1, 0
321  %3 = extractvalue { i128, i1 } %1, 1
322  %4 = zext i1 %3 to i8
323  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
324  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
325  ret { i128, i8 } %6
326}
327
328define i128 @u128_saturating_mul(i128 %x, i128 %y) {
329; CHECK-LABEL: u128_saturating_mul:
330; CHECK:       // %bb.0:
331; CHECK-NEXT:    mul x8, x3, x0
332; CHECK-NEXT:    umulh x9, x0, x2
333; CHECK-NEXT:    madd x8, x1, x2, x8
334; CHECK-NEXT:    umulh x10, x1, x2
335; CHECK-NEXT:    adds x8, x9, x8
336; CHECK-NEXT:    cset w9, hs
337; CHECK-NEXT:    cmp x1, #0
338; CHECK-NEXT:    ccmp x3, #0, #4, ne
339; CHECK-NEXT:    ccmp xzr, x10, #0, eq
340; CHECK-NEXT:    umulh x10, x3, x0
341; CHECK-NEXT:    ccmp xzr, x10, #0, eq
342; CHECK-NEXT:    cset w10, ne
343; CHECK-NEXT:    orr w9, w10, w9
344; CHECK-NEXT:    mul x10, x0, x2
345; CHECK-NEXT:    cmp w9, #0
346; CHECK-NEXT:    csinv x0, x10, xzr, eq
347; CHECK-NEXT:    csinv x1, x8, xzr, eq
348; CHECK-NEXT:    ret
349  %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
350  %2 = extractvalue { i128, i1 } %1, 0
351  %3 = extractvalue { i128, i1 } %1, 1
352  %4 = select i1 %3, i128 -1, i128 %2
353  ret i128 %4
354}
355
356define i128 @i128_mul(i128 %x, i128 %y) {
357; CHECK-LABEL: i128_mul:
358; CHECK:       // %bb.0:
359; CHECK-NEXT:    umulh x8, x0, x2
360; CHECK-NEXT:    madd x8, x0, x3, x8
361; CHECK-NEXT:    mul x0, x0, x2
362; CHECK-NEXT:    madd x1, x1, x2, x8
363; CHECK-NEXT:    ret
364  %1 = mul i128 %x, %y
365  ret i128 %1
366}
367
368define { i128, i8 } @i128_checked_mul(i128 %x, i128 %y) {
369; CHECK-LABEL: i128_checked_mul:
370; CHECK:       // %bb.0:
371; CHECK-NEXT:    stp x30, xzr, [sp, #-16]! // 8-byte Folded Spill
372; CHECK-NEXT:    .cfi_def_cfa_offset 16
373; CHECK-NEXT:    .cfi_offset w30, -16
374; CHECK-NEXT:    add x4, sp, #8
375; CHECK-NEXT:    bl __muloti4
376; CHECK-NEXT:    ldr x8, [sp, #8]
377; CHECK-NEXT:    cmp x8, #0
378; CHECK-NEXT:    cset w2, eq
379; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
380; CHECK-NEXT:    ret
381  %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
382  %2 = extractvalue { i128, i1 } %1, 0
383  %3 = extractvalue { i128, i1 } %1, 1
384  %4 = xor i1 %3, true
385  %5 = zext i1 %4 to i8
386  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
387  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
388  ret { i128, i8 } %7
389}
390
391define { i128, i8 } @i128_overflowing_mul(i128 %x, i128 %y) {
392; CHECK-LABEL: i128_overflowing_mul:
393; CHECK:       // %bb.0:
394; CHECK-NEXT:    stp x30, xzr, [sp, #-16]! // 8-byte Folded Spill
395; CHECK-NEXT:    .cfi_def_cfa_offset 16
396; CHECK-NEXT:    .cfi_offset w30, -16
397; CHECK-NEXT:    add x4, sp, #8
398; CHECK-NEXT:    bl __muloti4
399; CHECK-NEXT:    ldr x8, [sp, #8]
400; CHECK-NEXT:    cmp x8, #0
401; CHECK-NEXT:    cset w2, ne
402; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
403; CHECK-NEXT:    ret
404  %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
405  %2 = extractvalue { i128, i1 } %1, 0
406  %3 = extractvalue { i128, i1 } %1, 1
407  %4 = zext i1 %3 to i8
408  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
409  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
410  ret { i128, i8 } %6
411}
412
413define i128 @i128_saturating_mul(i128 %x, i128 %y) {
414; CHECK-LABEL: i128_saturating_mul:
415; CHECK:       // %bb.0:
416; CHECK-NEXT:    str x30, [sp, #-32]! // 8-byte Folded Spill
417; CHECK-NEXT:    .cfi_def_cfa_offset 32
418; CHECK-NEXT:    stp x20, x19, [sp, #16] // 16-byte Folded Spill
419; CHECK-NEXT:    .cfi_offset w19, -8
420; CHECK-NEXT:    .cfi_offset w20, -16
421; CHECK-NEXT:    .cfi_offset w30, -32
422; CHECK-NEXT:    add x4, sp, #8
423; CHECK-NEXT:    mov x19, x3
424; CHECK-NEXT:    mov x20, x1
425; CHECK-NEXT:    str xzr, [sp, #8]
426; CHECK-NEXT:    bl __muloti4
427; CHECK-NEXT:    ldr x8, [sp, #8]
428; CHECK-NEXT:    eor x9, x19, x20
429; CHECK-NEXT:    ldp x20, x19, [sp, #16] // 16-byte Folded Reload
430; CHECK-NEXT:    asr x9, x9, #63
431; CHECK-NEXT:    eor x10, x9, #0x7fffffffffffffff
432; CHECK-NEXT:    cmp x8, #0
433; CHECK-NEXT:    csinv x0, x0, x9, eq
434; CHECK-NEXT:    csel x1, x10, x1, ne
435; CHECK-NEXT:    ldr x30, [sp], #32 // 8-byte Folded Reload
436; CHECK-NEXT:    ret
437  %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
438  %2 = extractvalue { i128, i1 } %1, 0
439  %3 = extractvalue { i128, i1 } %1, 1
440  %4 = xor i128 %y, %x
441  %5 = icmp sgt i128 %4, -1
442  %6 = select i1 %5, i128 170141183460469231731687303715884105727, i128 -170141183460469231731687303715884105728
443  %7 = select i1 %3, i128 %6, i128 %2
444  ret i128 %7
445}
446