Files
clang-p2996/llvm/test/CodeGen/AArch64/i128-math.ll
Nikita Popov dad9e4a165 [RuntimeLibCalls] Consistently disable unavailable libcalls (#116214)
The logic for marking runtime libcalls unavailable currently duplicates
essentially the same logic for some random subset of targets, where
someone reported an issue and then someone went and fixed the issue for
that specific target only. However, the availability for most of these
is completely target independent. In particular:

 * MULO_I128 is never available in libgcc
 * Various I128 libcalls are not available for 32-bit targets in libgcc
 * powi is never available in MSVCRT

Unify the logic for these, so we don't miss any targets. This fixes
https://github.com/llvm/llvm-project/issues/16778 on AArch64, which is
one of the targets that was previously missed in this logic.
2024-11-15 15:46:28 +01:00

530 lines
17 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s
declare { i128, i1 } @llvm.uadd.with.overflow.i128(i128, i128)
declare i128 @llvm.uadd.sat.i128(i128, i128)
declare { i128, i1 } @llvm.usub.with.overflow.i128(i128, i128)
declare i128 @llvm.usub.sat.i128(i128, i128)
declare { i128, i1 } @llvm.umul.with.overflow.i128(i128, i128)
declare i128 @llvm.umul.sat.i128(i128, i128)
declare { i128, i1 } @llvm.sadd.with.overflow.i128(i128, i128)
declare i128 @llvm.sadd.sat.i128(i128, i128)
declare { i128, i1 } @llvm.ssub.with.overflow.i128(i128, i128)
declare i128 @llvm.ssub.sat.i128(i128, i128)
declare { i128, i1 } @llvm.smul.with.overflow.i128(i128, i128)
declare i128 @llvm.smul.sat.i128(i128, i128)
define i128 @u128_add(i128 %x, i128 %y) {
; CHECK-LABEL: u128_add:
; CHECK: // %bb.0:
; CHECK-NEXT: adds x0, x0, x2
; CHECK-NEXT: adc x1, x1, x3
; CHECK-NEXT: ret
%1 = add i128 %x, %y
ret i128 %1
}
define { i128, i8 } @u128_checked_add(i128 %x, i128 %y) {
; CHECK-LABEL: u128_checked_add:
; CHECK: // %bb.0:
; CHECK-NEXT: adds x0, x0, x2
; CHECK-NEXT: adcs x1, x1, x3
; CHECK-NEXT: cset w8, hs
; CHECK-NEXT: eor w2, w8, #0x1
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.uadd.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = xor i1 %3, true
%5 = zext i1 %4 to i8
%6 = insertvalue { i128, i8 } undef, i128 %2, 0
%7 = insertvalue { i128, i8 } %6, i8 %5, 1
ret { i128, i8 } %7
}
define { i128, i8 } @u128_overflowing_add(i128 %x, i128 %y) {
; CHECK-LABEL: u128_overflowing_add:
; CHECK: // %bb.0:
; CHECK-NEXT: adds x0, x0, x2
; CHECK-NEXT: adcs x1, x1, x3
; CHECK-NEXT: cset w2, hs
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.uadd.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = zext i1 %3 to i8
%5 = insertvalue { i128, i8 } undef, i128 %2, 0
%6 = insertvalue { i128, i8 } %5, i8 %4, 1
ret { i128, i8 } %6
}
define i128 @u128_saturating_add(i128 %x, i128 %y) {
; CHECK-LABEL: u128_saturating_add:
; CHECK: // %bb.0:
; CHECK-NEXT: adds x8, x0, x2
; CHECK-NEXT: adcs x9, x1, x3
; CHECK-NEXT: csinv x0, x8, xzr, lo
; CHECK-NEXT: csinv x1, x9, xzr, lo
; CHECK-NEXT: ret
%1 = tail call i128 @llvm.uadd.sat.i128(i128 %x, i128 %y)
ret i128 %1
}
define i128 @u128_sub(i128 %x, i128 %y) {
; CHECK-LABEL: u128_sub:
; CHECK: // %bb.0:
; CHECK-NEXT: subs x0, x0, x2
; CHECK-NEXT: sbc x1, x1, x3
; CHECK-NEXT: ret
%1 = sub i128 %x, %y
ret i128 %1
}
define { i128, i8 } @u128_checked_sub(i128 %x, i128 %y) {
; CHECK-LABEL: u128_checked_sub:
; CHECK: // %bb.0:
; CHECK-NEXT: subs x0, x0, x2
; CHECK-NEXT: sbcs x1, x1, x3
; CHECK-NEXT: cset w8, lo
; CHECK-NEXT: eor w2, w8, #0x1
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.usub.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = xor i1 %3, true
%5 = zext i1 %4 to i8
%6 = insertvalue { i128, i8 } undef, i128 %2, 0
%7 = insertvalue { i128, i8 } %6, i8 %5, 1
ret { i128, i8 } %7
}
define { i128, i8 } @u128_overflowing_sub(i128 %x, i128 %y) {
; CHECK-LABEL: u128_overflowing_sub:
; CHECK: // %bb.0:
; CHECK-NEXT: subs x0, x0, x2
; CHECK-NEXT: sbcs x1, x1, x3
; CHECK-NEXT: cset w2, lo
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.usub.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = zext i1 %3 to i8
%5 = insertvalue { i128, i8 } undef, i128 %2, 0
%6 = insertvalue { i128, i8 } %5, i8 %4, 1
ret { i128, i8 } %6
}
define i128 @u128_saturating_sub(i128 %x, i128 %y) {
; CHECK-LABEL: u128_saturating_sub:
; CHECK: // %bb.0:
; CHECK-NEXT: subs x8, x0, x2
; CHECK-NEXT: sbcs x9, x1, x3
; CHECK-NEXT: csel x0, xzr, x8, lo
; CHECK-NEXT: csel x1, xzr, x9, lo
; CHECK-NEXT: ret
%1 = tail call i128 @llvm.usub.sat.i128(i128 %x, i128 %y)
ret i128 %1
}
define i128 @i128_add(i128 %x, i128 %y) {
; CHECK-LABEL: i128_add:
; CHECK: // %bb.0:
; CHECK-NEXT: adds x0, x0, x2
; CHECK-NEXT: adc x1, x1, x3
; CHECK-NEXT: ret
%1 = add i128 %x, %y
ret i128 %1
}
define { i128, i8 } @i128_checked_add(i128 %x, i128 %y) {
; CHECK-LABEL: i128_checked_add:
; CHECK: // %bb.0:
; CHECK-NEXT: adds x0, x0, x2
; CHECK-NEXT: adcs x1, x1, x3
; CHECK-NEXT: cset w8, vs
; CHECK-NEXT: eor w2, w8, #0x1
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = xor i1 %3, true
%5 = zext i1 %4 to i8
%6 = insertvalue { i128, i8 } undef, i128 %2, 0
%7 = insertvalue { i128, i8 } %6, i8 %5, 1
ret { i128, i8 } %7
}
define { i128, i8 } @i128_overflowing_add(i128 %x, i128 %y) {
; CHECK-LABEL: i128_overflowing_add:
; CHECK: // %bb.0:
; CHECK-NEXT: adds x0, x0, x2
; CHECK-NEXT: adcs x1, x1, x3
; CHECK-NEXT: cset w2, vs
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = zext i1 %3 to i8
%5 = insertvalue { i128, i8 } undef, i128 %2, 0
%6 = insertvalue { i128, i8 } %5, i8 %4, 1
ret { i128, i8 } %6
}
define i128 @i128_saturating_add(i128 %x, i128 %y) {
; CHECK-LABEL: i128_saturating_add:
; CHECK: // %bb.0:
; CHECK-NEXT: adds x8, x0, x2
; CHECK-NEXT: adcs x9, x1, x3
; CHECK-NEXT: asr x10, x9, #63
; CHECK-NEXT: eor x11, x10, #0x8000000000000000
; CHECK-NEXT: csel x0, x10, x8, vs
; CHECK-NEXT: csel x1, x11, x9, vs
; CHECK-NEXT: ret
%1 = tail call i128 @llvm.sadd.sat.i128(i128 %x, i128 %y)
ret i128 %1
}
define i128 @i128_sub(i128 %x, i128 %y) {
; CHECK-LABEL: i128_sub:
; CHECK: // %bb.0:
; CHECK-NEXT: subs x0, x0, x2
; CHECK-NEXT: sbc x1, x1, x3
; CHECK-NEXT: ret
%1 = sub i128 %x, %y
ret i128 %1
}
define { i128, i8 } @i128_checked_sub(i128 %x, i128 %y) {
; CHECK-LABEL: i128_checked_sub:
; CHECK: // %bb.0:
; CHECK-NEXT: subs x0, x0, x2
; CHECK-NEXT: sbcs x1, x1, x3
; CHECK-NEXT: cset w8, vs
; CHECK-NEXT: eor w2, w8, #0x1
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = xor i1 %3, true
%5 = zext i1 %4 to i8
%6 = insertvalue { i128, i8 } undef, i128 %2, 0
%7 = insertvalue { i128, i8 } %6, i8 %5, 1
ret { i128, i8 } %7
}
define { i128, i8 } @i128_overflowing_sub(i128 %x, i128 %y) {
; CHECK-LABEL: i128_overflowing_sub:
; CHECK: // %bb.0:
; CHECK-NEXT: subs x0, x0, x2
; CHECK-NEXT: sbcs x1, x1, x3
; CHECK-NEXT: cset w2, vs
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = zext i1 %3 to i8
%5 = insertvalue { i128, i8 } undef, i128 %2, 0
%6 = insertvalue { i128, i8 } %5, i8 %4, 1
ret { i128, i8 } %6
}
define i128 @i128_saturating_sub(i128 %x, i128 %y) {
; CHECK-LABEL: i128_saturating_sub:
; CHECK: // %bb.0:
; CHECK-NEXT: subs x8, x0, x2
; CHECK-NEXT: sbcs x9, x1, x3
; CHECK-NEXT: asr x10, x9, #63
; CHECK-NEXT: eor x11, x10, #0x8000000000000000
; CHECK-NEXT: csel x0, x10, x8, vs
; CHECK-NEXT: csel x1, x11, x9, vs
; CHECK-NEXT: ret
%1 = tail call i128 @llvm.ssub.sat.i128(i128 %x, i128 %y)
ret i128 %1
}
define i128 @u128_mul(i128 %x, i128 %y) {
; CHECK-LABEL: u128_mul:
; CHECK: // %bb.0:
; CHECK-NEXT: umulh x8, x0, x2
; CHECK-NEXT: madd x8, x0, x3, x8
; CHECK-NEXT: mul x0, x0, x2
; CHECK-NEXT: madd x1, x1, x2, x8
; CHECK-NEXT: ret
%1 = mul i128 %x, %y
ret i128 %1
}
define { i128, i8 } @u128_checked_mul(i128 %x, i128 %y) {
; CHECK-LABEL: u128_checked_mul:
; CHECK: // %bb.0:
; CHECK-NEXT: mul x9, x3, x0
; CHECK-NEXT: cmp x1, #0
; CHECK-NEXT: ccmp x3, #0, #4, ne
; CHECK-NEXT: umulh x8, x1, x2
; CHECK-NEXT: umulh x10, x3, x0
; CHECK-NEXT: madd x9, x1, x2, x9
; CHECK-NEXT: ccmp xzr, x8, #0, eq
; CHECK-NEXT: umulh x11, x0, x2
; CHECK-NEXT: ccmp xzr, x10, #0, eq
; CHECK-NEXT: mul x0, x0, x2
; CHECK-NEXT: cset w8, ne
; CHECK-NEXT: adds x1, x11, x9
; CHECK-NEXT: csinc w8, w8, wzr, lo
; CHECK-NEXT: eor w2, w8, #0x1
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = xor i1 %3, true
%5 = zext i1 %4 to i8
%6 = insertvalue { i128, i8 } undef, i128 %2, 0
%7 = insertvalue { i128, i8 } %6, i8 %5, 1
ret { i128, i8 } %7
}
define { i128, i8 } @u128_overflowing_mul(i128 %x, i128 %y) {
; CHECK-LABEL: u128_overflowing_mul:
; CHECK: // %bb.0:
; CHECK-NEXT: mul x9, x3, x0
; CHECK-NEXT: cmp x1, #0
; CHECK-NEXT: ccmp x3, #0, #4, ne
; CHECK-NEXT: umulh x8, x1, x2
; CHECK-NEXT: umulh x10, x3, x0
; CHECK-NEXT: madd x9, x1, x2, x9
; CHECK-NEXT: ccmp xzr, x8, #0, eq
; CHECK-NEXT: umulh x11, x0, x2
; CHECK-NEXT: ccmp xzr, x10, #0, eq
; CHECK-NEXT: mul x0, x0, x2
; CHECK-NEXT: cset w8, ne
; CHECK-NEXT: adds x1, x11, x9
; CHECK-NEXT: csinc w2, w8, wzr, lo
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = zext i1 %3 to i8
%5 = insertvalue { i128, i8 } undef, i128 %2, 0
%6 = insertvalue { i128, i8 } %5, i8 %4, 1
ret { i128, i8 } %6
}
define i128 @u128_saturating_mul(i128 %x, i128 %y) {
; CHECK-LABEL: u128_saturating_mul:
; CHECK: // %bb.0:
; CHECK-NEXT: mul x9, x3, x0
; CHECK-NEXT: cmp x1, #0
; CHECK-NEXT: ccmp x3, #0, #4, ne
; CHECK-NEXT: umulh x8, x1, x2
; CHECK-NEXT: umulh x10, x3, x0
; CHECK-NEXT: madd x9, x1, x2, x9
; CHECK-NEXT: ccmp xzr, x8, #0, eq
; CHECK-NEXT: umulh x11, x0, x2
; CHECK-NEXT: ccmp xzr, x10, #0, eq
; CHECK-NEXT: mul x8, x0, x2
; CHECK-NEXT: cset w10, ne
; CHECK-NEXT: adds x9, x11, x9
; CHECK-NEXT: csinc w10, w10, wzr, lo
; CHECK-NEXT: cmp w10, #0
; CHECK-NEXT: csinv x0, x8, xzr, eq
; CHECK-NEXT: csinv x1, x9, xzr, eq
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = select i1 %3, i128 -1, i128 %2
ret i128 %4
}
define i128 @i128_mul(i128 %x, i128 %y) {
; CHECK-LABEL: i128_mul:
; CHECK: // %bb.0:
; CHECK-NEXT: umulh x8, x0, x2
; CHECK-NEXT: madd x8, x0, x3, x8
; CHECK-NEXT: mul x0, x0, x2
; CHECK-NEXT: madd x1, x1, x2, x8
; CHECK-NEXT: ret
%1 = mul i128 %x, %y
ret i128 %1
}
define { i128, i8 } @i128_checked_mul(i128 %x, i128 %y) {
; CHECK-LABEL: i128_checked_mul:
; CHECK: // %bb.0:
; CHECK-NEXT: asr x8, x1, #63
; CHECK-NEXT: asr x11, x3, #63
; CHECK-NEXT: umulh x13, x0, x2
; CHECK-NEXT: mul x9, x2, x8
; CHECK-NEXT: umulh x10, x2, x8
; CHECK-NEXT: umulh x12, x11, x0
; CHECK-NEXT: mul x14, x1, x2
; CHECK-NEXT: add x10, x10, x9
; CHECK-NEXT: madd x8, x3, x8, x10
; CHECK-NEXT: madd x10, x11, x1, x12
; CHECK-NEXT: mul x11, x11, x0
; CHECK-NEXT: umulh x12, x1, x2
; CHECK-NEXT: mul x15, x0, x3
; CHECK-NEXT: add x10, x10, x11
; CHECK-NEXT: adds x9, x11, x9
; CHECK-NEXT: umulh x16, x0, x3
; CHECK-NEXT: adc x10, x10, x8
; CHECK-NEXT: adds x8, x14, x13
; CHECK-NEXT: cinc x12, x12, hs
; CHECK-NEXT: mul x11, x1, x3
; CHECK-NEXT: adds x8, x15, x8
; CHECK-NEXT: umulh x13, x1, x3
; CHECK-NEXT: mov x1, x8
; CHECK-NEXT: cinc x14, x16, hs
; CHECK-NEXT: adds x12, x12, x14
; CHECK-NEXT: mul x0, x0, x2
; CHECK-NEXT: cset w14, hs
; CHECK-NEXT: adds x11, x11, x12
; CHECK-NEXT: asr x12, x8, #63
; CHECK-NEXT: adc x13, x13, x14
; CHECK-NEXT: adds x9, x11, x9
; CHECK-NEXT: adc x10, x13, x10
; CHECK-NEXT: cmp x9, x12
; CHECK-NEXT: ccmp x10, x12, #0, eq
; CHECK-NEXT: cset w2, eq
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = xor i1 %3, true
%5 = zext i1 %4 to i8
%6 = insertvalue { i128, i8 } undef, i128 %2, 0
%7 = insertvalue { i128, i8 } %6, i8 %5, 1
ret { i128, i8 } %7
}
define { i128, i8 } @i128_overflowing_mul(i128 %x, i128 %y) {
; CHECK-LABEL: i128_overflowing_mul:
; CHECK: // %bb.0:
; CHECK-NEXT: asr x8, x1, #63
; CHECK-NEXT: asr x11, x3, #63
; CHECK-NEXT: umulh x13, x0, x2
; CHECK-NEXT: mul x9, x2, x8
; CHECK-NEXT: umulh x10, x2, x8
; CHECK-NEXT: umulh x12, x11, x0
; CHECK-NEXT: mul x14, x1, x2
; CHECK-NEXT: add x10, x10, x9
; CHECK-NEXT: madd x8, x3, x8, x10
; CHECK-NEXT: madd x10, x11, x1, x12
; CHECK-NEXT: mul x11, x11, x0
; CHECK-NEXT: umulh x12, x1, x2
; CHECK-NEXT: mul x15, x0, x3
; CHECK-NEXT: add x10, x10, x11
; CHECK-NEXT: adds x9, x11, x9
; CHECK-NEXT: umulh x16, x0, x3
; CHECK-NEXT: adc x10, x10, x8
; CHECK-NEXT: adds x8, x14, x13
; CHECK-NEXT: cinc x12, x12, hs
; CHECK-NEXT: mul x11, x1, x3
; CHECK-NEXT: adds x8, x15, x8
; CHECK-NEXT: umulh x13, x1, x3
; CHECK-NEXT: mov x1, x8
; CHECK-NEXT: cinc x14, x16, hs
; CHECK-NEXT: adds x12, x12, x14
; CHECK-NEXT: mul x0, x0, x2
; CHECK-NEXT: cset w14, hs
; CHECK-NEXT: adds x11, x11, x12
; CHECK-NEXT: asr x12, x8, #63
; CHECK-NEXT: adc x13, x13, x14
; CHECK-NEXT: adds x9, x11, x9
; CHECK-NEXT: adc x10, x13, x10
; CHECK-NEXT: cmp x9, x12
; CHECK-NEXT: ccmp x10, x12, #0, eq
; CHECK-NEXT: cset w2, ne
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = zext i1 %3 to i8
%5 = insertvalue { i128, i8 } undef, i128 %2, 0
%6 = insertvalue { i128, i8 } %5, i8 %4, 1
ret { i128, i8 } %6
}
define i128 @i128_saturating_mul(i128 %x, i128 %y) {
; CHECK-LABEL: i128_saturating_mul:
; CHECK: // %bb.0:
; CHECK-NEXT: asr x8, x1, #63
; CHECK-NEXT: asr x11, x3, #63
; CHECK-NEXT: umulh x13, x0, x2
; CHECK-NEXT: mul x9, x2, x8
; CHECK-NEXT: umulh x10, x2, x8
; CHECK-NEXT: umulh x12, x11, x0
; CHECK-NEXT: mul x14, x1, x2
; CHECK-NEXT: add x10, x10, x9
; CHECK-NEXT: madd x8, x3, x8, x10
; CHECK-NEXT: madd x10, x11, x1, x12
; CHECK-NEXT: mul x11, x11, x0
; CHECK-NEXT: umulh x12, x1, x2
; CHECK-NEXT: mul x16, x0, x3
; CHECK-NEXT: add x10, x10, x11
; CHECK-NEXT: adds x9, x11, x9
; CHECK-NEXT: umulh x15, x0, x3
; CHECK-NEXT: adc x8, x10, x8
; CHECK-NEXT: adds x10, x14, x13
; CHECK-NEXT: cinc x12, x12, hs
; CHECK-NEXT: mul x17, x1, x3
; CHECK-NEXT: adds x10, x16, x10
; CHECK-NEXT: umulh x11, x1, x3
; CHECK-NEXT: cinc x13, x15, hs
; CHECK-NEXT: adds x12, x12, x13
; CHECK-NEXT: cset w13, hs
; CHECK-NEXT: adds x12, x17, x12
; CHECK-NEXT: adc x11, x11, x13
; CHECK-NEXT: adds x9, x12, x9
; CHECK-NEXT: asr x12, x10, #63
; CHECK-NEXT: mul x13, x0, x2
; CHECK-NEXT: adc x8, x11, x8
; CHECK-NEXT: eor x11, x3, x1
; CHECK-NEXT: eor x8, x8, x12
; CHECK-NEXT: eor x9, x9, x12
; CHECK-NEXT: asr x11, x11, #63
; CHECK-NEXT: orr x8, x9, x8
; CHECK-NEXT: eor x9, x11, #0x7fffffffffffffff
; CHECK-NEXT: cmp x8, #0
; CHECK-NEXT: csel x1, x9, x10, ne
; CHECK-NEXT: csinv x0, x13, x11, eq
; CHECK-NEXT: ret
%1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
%2 = extractvalue { i128, i1 } %1, 0
%3 = extractvalue { i128, i1 } %1, 1
%4 = xor i128 %y, %x
%5 = icmp sgt i128 %4, -1
%6 = select i1 %5, i128 170141183460469231731687303715884105727, i128 -170141183460469231731687303715884105728
%7 = select i1 %3, i128 %6, i128 %2
ret i128 %7
}
define { i128, i1 } @saddo_not_1(i128 %x) nounwind {
; CHECK-LABEL: saddo_not_1:
; CHECK: // %bb.0:
; CHECK-NEXT: negs x0, x0
; CHECK-NEXT: ngcs x1, x1
; CHECK-NEXT: cset w2, vs
; CHECK-NEXT: ret
%not = xor i128 %x, -1
%r = call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %not, i128 1)
ret { i128, i1 } %r
}
define { i128, i1 } @saddo_carry_not_1(i128 %x) nounwind {
; CHECK-LABEL: saddo_carry_not_1:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #1 // =0x1
; CHECK-NEXT: negs x0, x0
; CHECK-NEXT: sbcs x1, x8, x1
; CHECK-NEXT: cset w2, vs
; CHECK-NEXT: ret
%not = xor i128 %x, -1
%r = call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %not, i128 u0x10000000000000001)
ret { i128, i1 } %r
}