283 lines
8.7 KiB
LLVM
283 lines
8.7 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s
|
|
|
|
declare { i256, i1 } @llvm.uadd.with.overflow.i256(i256, i256)
|
|
declare i256 @llvm.uadd.sat.i256(i256, i256)
|
|
|
|
declare { i256, i1 } @llvm.usub.with.overflow.i256(i256, i256)
|
|
declare i256 @llvm.usub.sat.i256(i256, i256)
|
|
|
|
declare { i256, i1 } @llvm.sadd.with.overflow.i256(i256, i256)
|
|
declare i256 @llvm.sadd.sat.i256(i256, i256)
|
|
|
|
declare { i256, i1 } @llvm.ssub.with.overflow.i256(i256, i256)
|
|
declare i256 @llvm.ssub.sat.i256(i256, i256)
|
|
|
|
define i256 @u256_add(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: u256_add:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: adds x0, x0, x4
|
|
; CHECK-NEXT: adcs x1, x1, x5
|
|
; CHECK-NEXT: adcs x2, x2, x6
|
|
; CHECK-NEXT: adc x3, x3, x7
|
|
; CHECK-NEXT: ret
|
|
%1 = add i256 %x, %y
|
|
ret i256 %1
|
|
}
|
|
|
|
define { i256, i8 } @u256_checked_add(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: u256_checked_add:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: adds x0, x0, x4
|
|
; CHECK-NEXT: adcs x1, x1, x5
|
|
; CHECK-NEXT: adcs x2, x2, x6
|
|
; CHECK-NEXT: adcs x3, x3, x7
|
|
; CHECK-NEXT: cset w8, hs
|
|
; CHECK-NEXT: eor w4, w8, #0x1
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call { i256, i1 } @llvm.uadd.with.overflow.i256(i256 %x, i256 %y)
|
|
%2 = extractvalue { i256, i1 } %1, 0
|
|
%3 = extractvalue { i256, i1 } %1, 1
|
|
%4 = xor i1 %3, true
|
|
%5 = zext i1 %4 to i8
|
|
%6 = insertvalue { i256, i8 } undef, i256 %2, 0
|
|
%7 = insertvalue { i256, i8 } %6, i8 %5, 1
|
|
ret { i256, i8 } %7
|
|
}
|
|
|
|
define { i256, i8 } @u256_overflowing_add(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: u256_overflowing_add:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: adds x0, x0, x4
|
|
; CHECK-NEXT: adcs x1, x1, x5
|
|
; CHECK-NEXT: adcs x2, x2, x6
|
|
; CHECK-NEXT: adcs x3, x3, x7
|
|
; CHECK-NEXT: cset w4, hs
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call { i256, i1 } @llvm.uadd.with.overflow.i256(i256 %x, i256 %y)
|
|
%2 = extractvalue { i256, i1 } %1, 0
|
|
%3 = extractvalue { i256, i1 } %1, 1
|
|
%4 = zext i1 %3 to i8
|
|
%5 = insertvalue { i256, i8 } undef, i256 %2, 0
|
|
%6 = insertvalue { i256, i8 } %5, i8 %4, 1
|
|
ret { i256, i8 } %6
|
|
}
|
|
|
|
define i256 @u256_saturating_add(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: u256_saturating_add:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: adds x8, x0, x4
|
|
; CHECK-NEXT: adcs x9, x1, x5
|
|
; CHECK-NEXT: adcs x10, x2, x6
|
|
; CHECK-NEXT: adcs x11, x3, x7
|
|
; CHECK-NEXT: csinv x0, x8, xzr, lo
|
|
; CHECK-NEXT: csinv x1, x9, xzr, lo
|
|
; CHECK-NEXT: csinv x2, x10, xzr, lo
|
|
; CHECK-NEXT: csinv x3, x11, xzr, lo
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call i256 @llvm.uadd.sat.i256(i256 %x, i256 %y)
|
|
ret i256 %1
|
|
}
|
|
|
|
define i256 @u256_sub(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: u256_sub:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: subs x0, x0, x4
|
|
; CHECK-NEXT: sbcs x1, x1, x5
|
|
; CHECK-NEXT: sbcs x2, x2, x6
|
|
; CHECK-NEXT: sbc x3, x3, x7
|
|
; CHECK-NEXT: ret
|
|
%1 = sub i256 %x, %y
|
|
ret i256 %1
|
|
}
|
|
|
|
define { i256, i8 } @u256_checked_sub(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: u256_checked_sub:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: subs x0, x0, x4
|
|
; CHECK-NEXT: sbcs x1, x1, x5
|
|
; CHECK-NEXT: sbcs x2, x2, x6
|
|
; CHECK-NEXT: sbcs x3, x3, x7
|
|
; CHECK-NEXT: cset w8, lo
|
|
; CHECK-NEXT: eor w4, w8, #0x1
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call { i256, i1 } @llvm.usub.with.overflow.i256(i256 %x, i256 %y)
|
|
%2 = extractvalue { i256, i1 } %1, 0
|
|
%3 = extractvalue { i256, i1 } %1, 1
|
|
%4 = xor i1 %3, true
|
|
%5 = zext i1 %4 to i8
|
|
%6 = insertvalue { i256, i8 } undef, i256 %2, 0
|
|
%7 = insertvalue { i256, i8 } %6, i8 %5, 1
|
|
ret { i256, i8 } %7
|
|
}
|
|
|
|
define { i256, i8 } @u256_overflowing_sub(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: u256_overflowing_sub:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: subs x0, x0, x4
|
|
; CHECK-NEXT: sbcs x1, x1, x5
|
|
; CHECK-NEXT: sbcs x2, x2, x6
|
|
; CHECK-NEXT: sbcs x3, x3, x7
|
|
; CHECK-NEXT: cset w4, lo
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call { i256, i1 } @llvm.usub.with.overflow.i256(i256 %x, i256 %y)
|
|
%2 = extractvalue { i256, i1 } %1, 0
|
|
%3 = extractvalue { i256, i1 } %1, 1
|
|
%4 = zext i1 %3 to i8
|
|
%5 = insertvalue { i256, i8 } undef, i256 %2, 0
|
|
%6 = insertvalue { i256, i8 } %5, i8 %4, 1
|
|
ret { i256, i8 } %6
|
|
}
|
|
|
|
define i256 @u256_saturating_sub(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: u256_saturating_sub:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: subs x8, x0, x4
|
|
; CHECK-NEXT: sbcs x9, x1, x5
|
|
; CHECK-NEXT: sbcs x10, x2, x6
|
|
; CHECK-NEXT: sbcs x11, x3, x7
|
|
; CHECK-NEXT: csel x0, xzr, x8, lo
|
|
; CHECK-NEXT: csel x1, xzr, x9, lo
|
|
; CHECK-NEXT: csel x2, xzr, x10, lo
|
|
; CHECK-NEXT: csel x3, xzr, x11, lo
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call i256 @llvm.usub.sat.i256(i256 %x, i256 %y)
|
|
ret i256 %1
|
|
}
|
|
|
|
define i256 @i256_add(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: i256_add:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: adds x0, x0, x4
|
|
; CHECK-NEXT: adcs x1, x1, x5
|
|
; CHECK-NEXT: adcs x2, x2, x6
|
|
; CHECK-NEXT: adc x3, x3, x7
|
|
; CHECK-NEXT: ret
|
|
%1 = add i256 %x, %y
|
|
ret i256 %1
|
|
}
|
|
|
|
define { i256, i8 } @i256_checked_add(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: i256_checked_add:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: adds x0, x0, x4
|
|
; CHECK-NEXT: adcs x1, x1, x5
|
|
; CHECK-NEXT: adcs x2, x2, x6
|
|
; CHECK-NEXT: adcs x3, x3, x7
|
|
; CHECK-NEXT: cset w8, vs
|
|
; CHECK-NEXT: eor w4, w8, #0x1
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call { i256, i1 } @llvm.sadd.with.overflow.i256(i256 %x, i256 %y)
|
|
%2 = extractvalue { i256, i1 } %1, 0
|
|
%3 = extractvalue { i256, i1 } %1, 1
|
|
%4 = xor i1 %3, true
|
|
%5 = zext i1 %4 to i8
|
|
%6 = insertvalue { i256, i8 } undef, i256 %2, 0
|
|
%7 = insertvalue { i256, i8 } %6, i8 %5, 1
|
|
ret { i256, i8 } %7
|
|
}
|
|
|
|
define { i256, i8 } @i256_overflowing_add(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: i256_overflowing_add:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: adds x0, x0, x4
|
|
; CHECK-NEXT: adcs x1, x1, x5
|
|
; CHECK-NEXT: adcs x2, x2, x6
|
|
; CHECK-NEXT: adcs x3, x3, x7
|
|
; CHECK-NEXT: cset w4, vs
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call { i256, i1 } @llvm.sadd.with.overflow.i256(i256 %x, i256 %y)
|
|
%2 = extractvalue { i256, i1 } %1, 0
|
|
%3 = extractvalue { i256, i1 } %1, 1
|
|
%4 = zext i1 %3 to i8
|
|
%5 = insertvalue { i256, i8 } undef, i256 %2, 0
|
|
%6 = insertvalue { i256, i8 } %5, i8 %4, 1
|
|
ret { i256, i8 } %6
|
|
}
|
|
|
|
define i256 @i256_saturating_add(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: i256_saturating_add:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: adds x8, x0, x4
|
|
; CHECK-NEXT: adcs x9, x1, x5
|
|
; CHECK-NEXT: adcs x10, x2, x6
|
|
; CHECK-NEXT: adcs x11, x3, x7
|
|
; CHECK-NEXT: asr x12, x11, #63
|
|
; CHECK-NEXT: csel x0, x12, x8, vs
|
|
; CHECK-NEXT: eor x8, x12, #0x8000000000000000
|
|
; CHECK-NEXT: csel x1, x12, x9, vs
|
|
; CHECK-NEXT: csel x2, x12, x10, vs
|
|
; CHECK-NEXT: csel x3, x8, x11, vs
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call i256 @llvm.sadd.sat.i256(i256 %x, i256 %y)
|
|
ret i256 %1
|
|
}
|
|
|
|
define i256 @i256_sub(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: i256_sub:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: subs x0, x0, x4
|
|
; CHECK-NEXT: sbcs x1, x1, x5
|
|
; CHECK-NEXT: sbcs x2, x2, x6
|
|
; CHECK-NEXT: sbc x3, x3, x7
|
|
; CHECK-NEXT: ret
|
|
%1 = sub i256 %x, %y
|
|
ret i256 %1
|
|
}
|
|
|
|
define { i256, i8 } @i256_checked_sub(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: i256_checked_sub:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: subs x0, x0, x4
|
|
; CHECK-NEXT: sbcs x1, x1, x5
|
|
; CHECK-NEXT: sbcs x2, x2, x6
|
|
; CHECK-NEXT: sbcs x3, x3, x7
|
|
; CHECK-NEXT: cset w8, vs
|
|
; CHECK-NEXT: eor w4, w8, #0x1
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call { i256, i1 } @llvm.ssub.with.overflow.i256(i256 %x, i256 %y)
|
|
%2 = extractvalue { i256, i1 } %1, 0
|
|
%3 = extractvalue { i256, i1 } %1, 1
|
|
%4 = xor i1 %3, true
|
|
%5 = zext i1 %4 to i8
|
|
%6 = insertvalue { i256, i8 } undef, i256 %2, 0
|
|
%7 = insertvalue { i256, i8 } %6, i8 %5, 1
|
|
ret { i256, i8 } %7
|
|
}
|
|
|
|
define { i256, i8 } @i256_overflowing_sub(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: i256_overflowing_sub:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: subs x0, x0, x4
|
|
; CHECK-NEXT: sbcs x1, x1, x5
|
|
; CHECK-NEXT: sbcs x2, x2, x6
|
|
; CHECK-NEXT: sbcs x3, x3, x7
|
|
; CHECK-NEXT: cset w4, vs
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call { i256, i1 } @llvm.ssub.with.overflow.i256(i256 %x, i256 %y)
|
|
%2 = extractvalue { i256, i1 } %1, 0
|
|
%3 = extractvalue { i256, i1 } %1, 1
|
|
%4 = zext i1 %3 to i8
|
|
%5 = insertvalue { i256, i8 } undef, i256 %2, 0
|
|
%6 = insertvalue { i256, i8 } %5, i8 %4, 1
|
|
ret { i256, i8 } %6
|
|
}
|
|
|
|
define i256 @i256_saturating_sub(i256 %x, i256 %y) {
|
|
; CHECK-LABEL: i256_saturating_sub:
|
|
; CHECK: // %bb.0:
|
|
; CHECK-NEXT: subs x8, x0, x4
|
|
; CHECK-NEXT: sbcs x9, x1, x5
|
|
; CHECK-NEXT: sbcs x10, x2, x6
|
|
; CHECK-NEXT: sbcs x11, x3, x7
|
|
; CHECK-NEXT: asr x12, x11, #63
|
|
; CHECK-NEXT: csel x0, x12, x8, vs
|
|
; CHECK-NEXT: eor x8, x12, #0x8000000000000000
|
|
; CHECK-NEXT: csel x1, x12, x9, vs
|
|
; CHECK-NEXT: csel x2, x12, x10, vs
|
|
; CHECK-NEXT: csel x3, x8, x11, vs
|
|
; CHECK-NEXT: ret
|
|
%1 = tail call i256 @llvm.ssub.sat.i256(i256 %x, i256 %y)
|
|
ret i256 %1
|
|
}
|