1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s
4 declare { i128, i1 } @llvm.uadd.with.overflow.i128(i128, i128)
5 declare i128 @llvm.uadd.sat.i128(i128, i128)
7 declare { i128, i1 } @llvm.usub.with.overflow.i128(i128, i128)
8 declare i128 @llvm.usub.sat.i128(i128, i128)
10 declare { i128, i1 } @llvm.umul.with.overflow.i128(i128, i128)
11 declare i128 @llvm.umul.sat.i128(i128, i128)
13 declare { i128, i1 } @llvm.sadd.with.overflow.i128(i128, i128)
14 declare i128 @llvm.sadd.sat.i128(i128, i128)
16 declare { i128, i1 } @llvm.ssub.with.overflow.i128(i128, i128)
17 declare i128 @llvm.ssub.sat.i128(i128, i128)
19 declare { i128, i1 } @llvm.smul.with.overflow.i128(i128, i128)
20 declare i128 @llvm.smul.sat.i128(i128, i128)
22 define i128 @u128_add(i128 %x, i128 %y) {
23 ; CHECK-LABEL: u128_add:
25 ; CHECK-NEXT: adds x0, x0, x2
26 ; CHECK-NEXT: adc x1, x1, x3
32 define { i128, i8 } @u128_checked_add(i128 %x, i128 %y) {
33 ; CHECK-LABEL: u128_checked_add:
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
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
45 %6 = insertvalue { i128, i8 } undef, i128 %2, 0
46 %7 = insertvalue { i128, i8 } %6, i8 %5, 1
50 define { i128, i8 } @u128_overflowing_add(i128 %x, i128 %y) {
51 ; CHECK-LABEL: u128_overflowing_add:
53 ; CHECK-NEXT: adds x0, x0, x2
54 ; CHECK-NEXT: adcs x1, x1, x3
55 ; CHECK-NEXT: cset w2, hs
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
61 %5 = insertvalue { i128, i8 } undef, i128 %2, 0
62 %6 = insertvalue { i128, i8 } %5, i8 %4, 1
66 define i128 @u128_saturating_add(i128 %x, i128 %y) {
67 ; CHECK-LABEL: u128_saturating_add:
69 ; CHECK-NEXT: adds x8, x0, x2
70 ; CHECK-NEXT: adcs x9, x1, x3
71 ; CHECK-NEXT: csinv x0, x8, xzr, lo
72 ; CHECK-NEXT: csinv x1, x9, xzr, lo
74 %1 = tail call i128 @llvm.uadd.sat.i128(i128 %x, i128 %y)
78 define i128 @u128_sub(i128 %x, i128 %y) {
79 ; CHECK-LABEL: u128_sub:
81 ; CHECK-NEXT: subs x0, x0, x2
82 ; CHECK-NEXT: sbc x1, x1, x3
88 define { i128, i8 } @u128_checked_sub(i128 %x, i128 %y) {
89 ; CHECK-LABEL: u128_checked_sub:
91 ; CHECK-NEXT: subs x0, x0, x2
92 ; CHECK-NEXT: sbcs x1, x1, x3
93 ; CHECK-NEXT: cset w8, lo
94 ; CHECK-NEXT: eor w2, w8, #0x1
96 %1 = tail call { i128, i1 } @llvm.usub.with.overflow.i128(i128 %x, i128 %y)
97 %2 = extractvalue { i128, i1 } %1, 0
98 %3 = extractvalue { i128, i1 } %1, 1
100 %5 = zext i1 %4 to i8
101 %6 = insertvalue { i128, i8 } undef, i128 %2, 0
102 %7 = insertvalue { i128, i8 } %6, i8 %5, 1
106 define { i128, i8 } @u128_overflowing_sub(i128 %x, i128 %y) {
107 ; CHECK-LABEL: u128_overflowing_sub:
109 ; CHECK-NEXT: subs x0, x0, x2
110 ; CHECK-NEXT: sbcs x1, x1, x3
111 ; CHECK-NEXT: cset w2, lo
113 %1 = tail call { i128, i1 } @llvm.usub.with.overflow.i128(i128 %x, i128 %y)
114 %2 = extractvalue { i128, i1 } %1, 0
115 %3 = extractvalue { i128, i1 } %1, 1
116 %4 = zext i1 %3 to i8
117 %5 = insertvalue { i128, i8 } undef, i128 %2, 0
118 %6 = insertvalue { i128, i8 } %5, i8 %4, 1
122 define i128 @u128_saturating_sub(i128 %x, i128 %y) {
123 ; CHECK-LABEL: u128_saturating_sub:
125 ; CHECK-NEXT: subs x8, x0, x2
126 ; CHECK-NEXT: sbcs x9, x1, x3
127 ; CHECK-NEXT: csel x0, xzr, x8, lo
128 ; CHECK-NEXT: csel x1, xzr, x9, lo
130 %1 = tail call i128 @llvm.usub.sat.i128(i128 %x, i128 %y)
134 define i128 @i128_add(i128 %x, i128 %y) {
135 ; CHECK-LABEL: i128_add:
137 ; CHECK-NEXT: adds x0, x0, x2
138 ; CHECK-NEXT: adc x1, x1, x3
144 define { i128, i8 } @i128_checked_add(i128 %x, i128 %y) {
145 ; CHECK-LABEL: i128_checked_add:
147 ; CHECK-NEXT: adds x0, x0, x2
148 ; CHECK-NEXT: adcs x1, x1, x3
149 ; CHECK-NEXT: cset w8, vs
150 ; CHECK-NEXT: eor w2, w8, #0x1
152 %1 = tail call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %x, i128 %y)
153 %2 = extractvalue { i128, i1 } %1, 0
154 %3 = extractvalue { i128, i1 } %1, 1
156 %5 = zext i1 %4 to i8
157 %6 = insertvalue { i128, i8 } undef, i128 %2, 0
158 %7 = insertvalue { i128, i8 } %6, i8 %5, 1
162 define { i128, i8 } @i128_overflowing_add(i128 %x, i128 %y) {
163 ; CHECK-LABEL: i128_overflowing_add:
165 ; CHECK-NEXT: adds x0, x0, x2
166 ; CHECK-NEXT: adcs x1, x1, x3
167 ; CHECK-NEXT: cset w2, vs
169 %1 = tail call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %x, i128 %y)
170 %2 = extractvalue { i128, i1 } %1, 0
171 %3 = extractvalue { i128, i1 } %1, 1
172 %4 = zext i1 %3 to i8
173 %5 = insertvalue { i128, i8 } undef, i128 %2, 0
174 %6 = insertvalue { i128, i8 } %5, i8 %4, 1
178 define i128 @i128_saturating_add(i128 %x, i128 %y) {
179 ; CHECK-LABEL: i128_saturating_add:
181 ; CHECK-NEXT: adds x8, x0, x2
182 ; CHECK-NEXT: adcs x9, x1, x3
183 ; CHECK-NEXT: asr x10, x9, #63
184 ; CHECK-NEXT: eor x11, x10, #0x8000000000000000
185 ; CHECK-NEXT: csel x0, x10, x8, vs
186 ; CHECK-NEXT: csel x1, x11, x9, vs
188 %1 = tail call i128 @llvm.sadd.sat.i128(i128 %x, i128 %y)
192 define i128 @i128_sub(i128 %x, i128 %y) {
193 ; CHECK-LABEL: i128_sub:
195 ; CHECK-NEXT: subs x0, x0, x2
196 ; CHECK-NEXT: sbc x1, x1, x3
202 define { i128, i8 } @i128_checked_sub(i128 %x, i128 %y) {
203 ; CHECK-LABEL: i128_checked_sub:
205 ; CHECK-NEXT: subs x0, x0, x2
206 ; CHECK-NEXT: sbcs x1, x1, x3
207 ; CHECK-NEXT: cset w8, vs
208 ; CHECK-NEXT: eor w2, w8, #0x1
210 %1 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %x, i128 %y)
211 %2 = extractvalue { i128, i1 } %1, 0
212 %3 = extractvalue { i128, i1 } %1, 1
214 %5 = zext i1 %4 to i8
215 %6 = insertvalue { i128, i8 } undef, i128 %2, 0
216 %7 = insertvalue { i128, i8 } %6, i8 %5, 1
220 define { i128, i8 } @i128_overflowing_sub(i128 %x, i128 %y) {
221 ; CHECK-LABEL: i128_overflowing_sub:
223 ; CHECK-NEXT: subs x0, x0, x2
224 ; CHECK-NEXT: sbcs x1, x1, x3
225 ; CHECK-NEXT: cset w2, vs
227 %1 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %x, i128 %y)
228 %2 = extractvalue { i128, i1 } %1, 0
229 %3 = extractvalue { i128, i1 } %1, 1
230 %4 = zext i1 %3 to i8
231 %5 = insertvalue { i128, i8 } undef, i128 %2, 0
232 %6 = insertvalue { i128, i8 } %5, i8 %4, 1
236 define i128 @i128_saturating_sub(i128 %x, i128 %y) {
237 ; CHECK-LABEL: i128_saturating_sub:
239 ; CHECK-NEXT: subs x8, x0, x2
240 ; CHECK-NEXT: sbcs x9, x1, x3
241 ; CHECK-NEXT: asr x10, x9, #63
242 ; CHECK-NEXT: eor x11, x10, #0x8000000000000000
243 ; CHECK-NEXT: csel x0, x10, x8, vs
244 ; CHECK-NEXT: csel x1, x11, x9, vs
246 %1 = tail call i128 @llvm.ssub.sat.i128(i128 %x, i128 %y)
250 define i128 @u128_mul(i128 %x, i128 %y) {
251 ; CHECK-LABEL: u128_mul:
253 ; CHECK-NEXT: umulh x8, x0, x2
254 ; CHECK-NEXT: madd x8, x0, x3, x8
255 ; CHECK-NEXT: mul x0, x0, x2
256 ; CHECK-NEXT: madd x1, x1, x2, x8
262 define { i128, i8 } @u128_checked_mul(i128 %x, i128 %y) {
263 ; CHECK-LABEL: u128_checked_mul:
265 ; CHECK-NEXT: mul x9, x3, x0
266 ; CHECK-NEXT: cmp x1, #0
267 ; CHECK-NEXT: ccmp x3, #0, #4, ne
268 ; CHECK-NEXT: umulh x8, x1, x2
269 ; CHECK-NEXT: umulh x10, x3, x0
270 ; CHECK-NEXT: madd x9, x1, x2, x9
271 ; CHECK-NEXT: ccmp xzr, x8, #0, eq
272 ; CHECK-NEXT: umulh x11, x0, x2
273 ; CHECK-NEXT: ccmp xzr, x10, #0, eq
274 ; CHECK-NEXT: mul x0, x0, x2
275 ; CHECK-NEXT: cset w8, ne
276 ; CHECK-NEXT: adds x1, x11, x9
277 ; CHECK-NEXT: csinc w8, w8, wzr, lo
278 ; CHECK-NEXT: eor w2, w8, #0x1
280 %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
281 %2 = extractvalue { i128, i1 } %1, 0
282 %3 = extractvalue { i128, i1 } %1, 1
284 %5 = zext i1 %4 to i8
285 %6 = insertvalue { i128, i8 } undef, i128 %2, 0
286 %7 = insertvalue { i128, i8 } %6, i8 %5, 1
290 define { i128, i8 } @u128_overflowing_mul(i128 %x, i128 %y) {
291 ; CHECK-LABEL: u128_overflowing_mul:
293 ; CHECK-NEXT: mul x9, x3, x0
294 ; CHECK-NEXT: cmp x1, #0
295 ; CHECK-NEXT: ccmp x3, #0, #4, ne
296 ; CHECK-NEXT: umulh x8, x1, x2
297 ; CHECK-NEXT: umulh x10, x3, x0
298 ; CHECK-NEXT: madd x9, x1, x2, x9
299 ; CHECK-NEXT: ccmp xzr, x8, #0, eq
300 ; CHECK-NEXT: umulh x11, x0, x2
301 ; CHECK-NEXT: ccmp xzr, x10, #0, eq
302 ; CHECK-NEXT: mul x0, x0, x2
303 ; CHECK-NEXT: cset w8, ne
304 ; CHECK-NEXT: adds x1, x11, x9
305 ; CHECK-NEXT: csinc w2, w8, wzr, lo
307 %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
308 %2 = extractvalue { i128, i1 } %1, 0
309 %3 = extractvalue { i128, i1 } %1, 1
310 %4 = zext i1 %3 to i8
311 %5 = insertvalue { i128, i8 } undef, i128 %2, 0
312 %6 = insertvalue { i128, i8 } %5, i8 %4, 1
316 define i128 @u128_saturating_mul(i128 %x, i128 %y) {
317 ; CHECK-LABEL: u128_saturating_mul:
319 ; CHECK-NEXT: mul x9, x3, x0
320 ; CHECK-NEXT: cmp x1, #0
321 ; CHECK-NEXT: ccmp x3, #0, #4, ne
322 ; CHECK-NEXT: umulh x8, x1, x2
323 ; CHECK-NEXT: umulh x10, x3, x0
324 ; CHECK-NEXT: madd x9, x1, x2, x9
325 ; CHECK-NEXT: ccmp xzr, x8, #0, eq
326 ; CHECK-NEXT: umulh x11, x0, x2
327 ; CHECK-NEXT: ccmp xzr, x10, #0, eq
328 ; CHECK-NEXT: mul x8, x0, x2
329 ; CHECK-NEXT: cset w10, ne
330 ; CHECK-NEXT: adds x9, x11, x9
331 ; CHECK-NEXT: csinc w10, w10, wzr, lo
332 ; CHECK-NEXT: cmp w10, #0
333 ; CHECK-NEXT: csinv x0, x8, xzr, eq
334 ; CHECK-NEXT: csinv x1, x9, xzr, eq
336 %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
337 %2 = extractvalue { i128, i1 } %1, 0
338 %3 = extractvalue { i128, i1 } %1, 1
339 %4 = select i1 %3, i128 -1, i128 %2
343 define i128 @i128_mul(i128 %x, i128 %y) {
344 ; CHECK-LABEL: i128_mul:
346 ; CHECK-NEXT: umulh x8, x0, x2
347 ; CHECK-NEXT: madd x8, x0, x3, x8
348 ; CHECK-NEXT: mul x0, x0, x2
349 ; CHECK-NEXT: madd x1, x1, x2, x8
355 define { i128, i8 } @i128_checked_mul(i128 %x, i128 %y) {
356 ; CHECK-LABEL: i128_checked_mul:
358 ; CHECK-NEXT: stp x30, xzr, [sp, #-16]! // 8-byte Folded Spill
359 ; CHECK-NEXT: .cfi_def_cfa_offset 16
360 ; CHECK-NEXT: .cfi_offset w30, -16
361 ; CHECK-NEXT: add x4, sp, #8
362 ; CHECK-NEXT: bl __muloti4
363 ; CHECK-NEXT: ldr x8, [sp, #8]
364 ; CHECK-NEXT: cmp x8, #0
365 ; CHECK-NEXT: cset w2, eq
366 ; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
368 %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
369 %2 = extractvalue { i128, i1 } %1, 0
370 %3 = extractvalue { i128, i1 } %1, 1
372 %5 = zext i1 %4 to i8
373 %6 = insertvalue { i128, i8 } undef, i128 %2, 0
374 %7 = insertvalue { i128, i8 } %6, i8 %5, 1
378 define { i128, i8 } @i128_overflowing_mul(i128 %x, i128 %y) {
379 ; CHECK-LABEL: i128_overflowing_mul:
381 ; CHECK-NEXT: stp x30, xzr, [sp, #-16]! // 8-byte Folded Spill
382 ; CHECK-NEXT: .cfi_def_cfa_offset 16
383 ; CHECK-NEXT: .cfi_offset w30, -16
384 ; CHECK-NEXT: add x4, sp, #8
385 ; CHECK-NEXT: bl __muloti4
386 ; CHECK-NEXT: ldr x8, [sp, #8]
387 ; CHECK-NEXT: cmp x8, #0
388 ; CHECK-NEXT: cset w2, ne
389 ; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
391 %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
392 %2 = extractvalue { i128, i1 } %1, 0
393 %3 = extractvalue { i128, i1 } %1, 1
394 %4 = zext i1 %3 to i8
395 %5 = insertvalue { i128, i8 } undef, i128 %2, 0
396 %6 = insertvalue { i128, i8 } %5, i8 %4, 1
400 define i128 @i128_saturating_mul(i128 %x, i128 %y) {
401 ; CHECK-LABEL: i128_saturating_mul:
403 ; CHECK-NEXT: str x30, [sp, #-32]! // 8-byte Folded Spill
404 ; CHECK-NEXT: stp x20, x19, [sp, #16] // 16-byte Folded Spill
405 ; CHECK-NEXT: .cfi_def_cfa_offset 32
406 ; CHECK-NEXT: .cfi_offset w19, -8
407 ; CHECK-NEXT: .cfi_offset w20, -16
408 ; CHECK-NEXT: .cfi_offset w30, -32
409 ; CHECK-NEXT: add x4, sp, #8
410 ; CHECK-NEXT: mov x19, x3
411 ; CHECK-NEXT: mov x20, x1
412 ; CHECK-NEXT: str xzr, [sp, #8]
413 ; CHECK-NEXT: bl __muloti4
414 ; CHECK-NEXT: eor x8, x19, x20
415 ; CHECK-NEXT: ldr x9, [sp, #8]
416 ; CHECK-NEXT: asr x8, x8, #63
417 ; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload
418 ; CHECK-NEXT: cmp x9, #0
419 ; CHECK-NEXT: eor x10, x8, #0x7fffffffffffffff
420 ; CHECK-NEXT: csinv x0, x0, x8, eq
421 ; CHECK-NEXT: csel x1, x10, x1, ne
422 ; CHECK-NEXT: ldr x30, [sp], #32 // 8-byte Folded Reload
424 %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
425 %2 = extractvalue { i128, i1 } %1, 0
426 %3 = extractvalue { i128, i1 } %1, 1
428 %5 = icmp sgt i128 %4, -1
429 %6 = select i1 %5, i128 170141183460469231731687303715884105727, i128 -170141183460469231731687303715884105728
430 %7 = select i1 %3, i128 %6, i128 %2
434 define { i128, i1 } @saddo_not_1(i128 %x) nounwind {
435 ; CHECK-LABEL: saddo_not_1:
437 ; CHECK-NEXT: negs x0, x0
438 ; CHECK-NEXT: ngcs x1, x1
439 ; CHECK-NEXT: cset w2, vs
441 %not = xor i128 %x, -1
442 %r = call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %not, i128 1)
446 define { i128, i1 } @saddo_carry_not_1(i128 %x) nounwind {
447 ; CHECK-LABEL: saddo_carry_not_1:
449 ; CHECK-NEXT: mov w8, #1 // =0x1
450 ; CHECK-NEXT: negs x0, x0
451 ; CHECK-NEXT: sbcs x1, x8, x1
452 ; CHECK-NEXT: cset w2, vs
454 %not = xor i128 %x, -1
455 %r = call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %not, i128 u0x10000000000000001)