Merge pull request #615 from tgross35/test-refactoring
Rework the test crate to separate individual tests
This commit is contained in:
commit
b07accb2c5
7 changed files with 750 additions and 609 deletions
|
|
@ -4,139 +4,149 @@
|
|||
|
||||
use testcrate::*;
|
||||
|
||||
macro_rules! sum {
|
||||
($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => {
|
||||
$(
|
||||
fuzz_2(N, |x: $i, y: $i| {
|
||||
let add0 = x.wrapping_add(y);
|
||||
let sub0 = x.wrapping_sub(y);
|
||||
let add1: $i = $fn_add(x, y);
|
||||
let sub1: $i = $fn_sub(x, y);
|
||||
if add0 != add1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn_add), x, y, add0, add1
|
||||
);
|
||||
}
|
||||
if sub0 != sub1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn_sub), x, y, sub0, sub1
|
||||
);
|
||||
}
|
||||
});
|
||||
)*
|
||||
};
|
||||
}
|
||||
mod int_addsub {
|
||||
use super::*;
|
||||
|
||||
macro_rules! overflowing_sum {
|
||||
($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => {
|
||||
$(
|
||||
fuzz_2(N, |x: $i, y: $i| {
|
||||
let add0 = x.overflowing_add(y);
|
||||
let sub0 = x.overflowing_sub(y);
|
||||
let add1: ($i, bool) = $fn_add(x, y);
|
||||
let sub1: ($i, bool) = $fn_sub(x, y);
|
||||
if add0.0 != add1.0 || add0.1 != add1.1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn_add), x, y, add0, add1
|
||||
);
|
||||
}
|
||||
if sub0.0 != sub1.0 || sub0.1 != sub1.1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn_sub), x, y, sub0, sub1
|
||||
);
|
||||
}
|
||||
});
|
||||
)*
|
||||
};
|
||||
}
|
||||
macro_rules! sum {
|
||||
($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fn_add() {
|
||||
use compiler_builtins::int::addsub::{$fn_add, $fn_sub};
|
||||
|
||||
#[test]
|
||||
fn addsub() {
|
||||
use compiler_builtins::int::addsub::{
|
||||
__rust_i128_add, __rust_i128_addo, __rust_i128_sub, __rust_i128_subo, __rust_u128_add,
|
||||
__rust_u128_addo, __rust_u128_sub, __rust_u128_subo,
|
||||
};
|
||||
fuzz_2(N, |x: $i, y: $i| {
|
||||
let add0 = x.wrapping_add(y);
|
||||
let sub0 = x.wrapping_sub(y);
|
||||
let add1: $i = $fn_add(x, y);
|
||||
let sub1: $i = $fn_sub(x, y);
|
||||
if add0 != add1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn_add), x, y, add0, add1
|
||||
);
|
||||
}
|
||||
if sub0 != sub1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn_sub), x, y, sub0, sub1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! overflowing_sum {
|
||||
($($i:ty, $fn_add:ident, $fn_sub:ident);*;) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fn_add() {
|
||||
use compiler_builtins::int::addsub::{$fn_add, $fn_sub};
|
||||
|
||||
fuzz_2(N, |x: $i, y: $i| {
|
||||
let add0 = x.overflowing_add(y);
|
||||
let sub0 = x.overflowing_sub(y);
|
||||
let add1: ($i, bool) = $fn_add(x, y);
|
||||
let sub1: ($i, bool) = $fn_sub(x, y);
|
||||
if add0.0 != add1.0 || add0.1 != add1.1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn_add), x, y, add0, add1
|
||||
);
|
||||
}
|
||||
if sub0.0 != sub1.0 || sub0.1 != sub1.1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn_sub), x, y, sub0, sub1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
// Integer addition and subtraction is very simple, so 100 fuzzing passes should be plenty.
|
||||
sum!(
|
||||
sum! {
|
||||
u128, __rust_u128_add, __rust_u128_sub;
|
||||
i128, __rust_i128_add, __rust_i128_sub;
|
||||
);
|
||||
overflowing_sum!(
|
||||
}
|
||||
|
||||
overflowing_sum! {
|
||||
u128, __rust_u128_addo, __rust_u128_subo;
|
||||
i128, __rust_i128_addo, __rust_i128_subo;
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! float_sum {
|
||||
($($f:ty, $fn_add:ident, $fn_sub:ident, $apfloat_ty:ident, $sys_available:meta);*;) => {
|
||||
$(
|
||||
fuzz_float_2(N, |x: $f, y: $f| {
|
||||
let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y);
|
||||
let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y);
|
||||
let add1: $f = $fn_add(x, y);
|
||||
let sub1: $f = $fn_sub(x, y);
|
||||
if !Float::eq_repr(add0, add1) {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn_add), x, y, add0, add1
|
||||
);
|
||||
}
|
||||
if !Float::eq_repr(sub0, sub1) {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn_sub), x, y, sub0, sub1
|
||||
);
|
||||
}
|
||||
});
|
||||
#[test]
|
||||
fn $fn_add() {
|
||||
use core::ops::{Add, Sub};
|
||||
use compiler_builtins::float::{{add::$fn_add, sub::$fn_sub}, Float};
|
||||
|
||||
fuzz_float_2(N, |x: $f, y: $f| {
|
||||
let add0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Add::add, x, y);
|
||||
let sub0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Sub::sub, x, y);
|
||||
let add1: $f = $fn_add(x, y);
|
||||
let sub1: $f = $fn_sub(x, y);
|
||||
if !Float::eq_repr(add0, add1) {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn_add), x, y, add0, add1
|
||||
);
|
||||
}
|
||||
if !Float::eq_repr(sub0, sub1) {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn_sub), x, y, sub0, sub1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
|
||||
#[test]
|
||||
fn float_addsub() {
|
||||
use compiler_builtins::float::{
|
||||
add::{__adddf3, __addsf3},
|
||||
sub::{__subdf3, __subsf3},
|
||||
Float,
|
||||
};
|
||||
use core::ops::{Add, Sub};
|
||||
mod float_addsub {
|
||||
use super::*;
|
||||
|
||||
float_sum!(
|
||||
float_sum! {
|
||||
f32, __addsf3, __subsf3, Single, all();
|
||||
f64, __adddf3, __subdf3, Double, all();
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
{
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
use compiler_builtins::float::{add::__addkf3 as __addtf3, sub::__subkf3 as __subtf3};
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
use compiler_builtins::float::{add::__addtf3, sub::__subtf3};
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
mod float_addsub_f128 {
|
||||
use super::*;
|
||||
|
||||
float_sum!(
|
||||
f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128");
|
||||
);
|
||||
float_sum! {
|
||||
f128, __addtf3, __subtf3, Quad, not(feature = "no-sys-f128");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
mod float_addsub_f128_ppc {
|
||||
use super::*;
|
||||
|
||||
float_sum! {
|
||||
f128, __addkf3, __subkf3, Quad, not(feature = "no-sys-f128");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[test]
|
||||
fn float_addsub_arm() {
|
||||
use compiler_builtins::float::{
|
||||
add::{__adddf3vfp, __addsf3vfp},
|
||||
sub::{__subdf3vfp, __subsf3vfp},
|
||||
Float,
|
||||
};
|
||||
use core::ops::{Add, Sub};
|
||||
mod float_addsub_arm {
|
||||
use super::*;
|
||||
|
||||
float_sum!(
|
||||
float_sum! {
|
||||
f32, __addsf3vfp, __subsf3vfp, Single, all();
|
||||
f64, __adddf3vfp, __subdf3vfp, Double, all();
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,84 +6,96 @@
|
|||
#[cfg(not(target_arch = "powerpc64"))]
|
||||
use testcrate::*;
|
||||
|
||||
macro_rules! cmp {
|
||||
(
|
||||
$f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta,
|
||||
$($unordered_val:expr, $fn:ident);*;
|
||||
) => {
|
||||
$(
|
||||
let cmp0 = if apfloat_fallback!(
|
||||
$f, $apfloat_ty, $sys_available,
|
||||
|x: FloatTy| x.is_nan() => no_convert,
|
||||
$x
|
||||
) || apfloat_fallback!(
|
||||
$f, $apfloat_ty, $sys_available,
|
||||
|y: FloatTy| y.is_nan() => no_convert,
|
||||
$y
|
||||
)
|
||||
{
|
||||
$unordered_val
|
||||
} else if apfloat_fallback!(
|
||||
$f, $apfloat_ty, $sys_available,
|
||||
|x, y| x < y => no_convert,
|
||||
$x, $y
|
||||
) {
|
||||
-1
|
||||
} else if apfloat_fallback!(
|
||||
$f, $apfloat_ty, $sys_available,
|
||||
|x, y| x == y => no_convert,
|
||||
$x, $y
|
||||
) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
let cmp1 = $fn($x, $y);
|
||||
if cmp0 != cmp1 {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn), $x, $y, cmp0, cmp1
|
||||
);
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
|
||||
#[cfg(not(target_arch = "powerpc64"))]
|
||||
#[test]
|
||||
fn float_comparisons() {
|
||||
use compiler_builtins::float::cmp::{
|
||||
__eqdf2, __eqsf2, __gedf2, __gesf2, __gtdf2, __gtsf2, __ledf2, __lesf2, __ltdf2, __ltsf2,
|
||||
__nedf2, __nesf2, __unorddf2, __unordsf2,
|
||||
};
|
||||
mod float_comparisons {
|
||||
use super::*;
|
||||
|
||||
fuzz_float_2(N, |x: f32, y: f32| {
|
||||
assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan());
|
||||
cmp!(f32, x, y, Single, all(),
|
||||
1, __ltsf2;
|
||||
1, __lesf2;
|
||||
1, __eqsf2;
|
||||
-1, __gesf2;
|
||||
-1, __gtsf2;
|
||||
1, __nesf2;
|
||||
);
|
||||
});
|
||||
fuzz_float_2(N, |x: f64, y: f64| {
|
||||
assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan());
|
||||
cmp!(f64, x, y, Double, all(),
|
||||
1, __ltdf2;
|
||||
1, __ledf2;
|
||||
1, __eqdf2;
|
||||
-1, __gedf2;
|
||||
-1, __gtdf2;
|
||||
1, __nedf2;
|
||||
);
|
||||
});
|
||||
macro_rules! cmp {
|
||||
(
|
||||
$f:ty, $x:ident, $y:ident, $apfloat_ty:ident, $sys_available:meta,
|
||||
$($unordered_val:expr, $fn:ident);*;
|
||||
) => {
|
||||
$(
|
||||
let cmp0 = if apfloat_fallback!(
|
||||
$f, $apfloat_ty, $sys_available,
|
||||
|x: FloatTy| x.is_nan() => no_convert,
|
||||
$x
|
||||
) || apfloat_fallback!(
|
||||
$f, $apfloat_ty, $sys_available,
|
||||
|y: FloatTy| y.is_nan() => no_convert,
|
||||
$y
|
||||
)
|
||||
{
|
||||
$unordered_val
|
||||
} else if apfloat_fallback!(
|
||||
$f, $apfloat_ty, $sys_available,
|
||||
|x, y| x < y => no_convert,
|
||||
$x, $y
|
||||
) {
|
||||
-1
|
||||
} else if apfloat_fallback!(
|
||||
$f, $apfloat_ty, $sys_available,
|
||||
|x, y| x == y => no_convert,
|
||||
$x, $y
|
||||
) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
let cmp1 = $fn($x, $y);
|
||||
if cmp0 != cmp1 {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn), $x, $y, cmp0, cmp1
|
||||
);
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmp_f32() {
|
||||
use compiler_builtins::float::cmp::{
|
||||
__eqsf2, __gesf2, __gtsf2, __lesf2, __ltsf2, __nesf2, __unordsf2,
|
||||
};
|
||||
|
||||
fuzz_float_2(N, |x: f32, y: f32| {
|
||||
assert_eq!(__unordsf2(x, y) != 0, x.is_nan() || y.is_nan());
|
||||
cmp!(f32, x, y, Single, all(),
|
||||
1, __ltsf2;
|
||||
1, __lesf2;
|
||||
1, __eqsf2;
|
||||
-1, __gesf2;
|
||||
-1, __gtsf2;
|
||||
1, __nesf2;
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmp_f64() {
|
||||
use compiler_builtins::float::cmp::{
|
||||
__eqdf2, __gedf2, __gtdf2, __ledf2, __ltdf2, __nedf2, __unorddf2,
|
||||
};
|
||||
|
||||
fuzz_float_2(N, |x: f64, y: f64| {
|
||||
assert_eq!(__unorddf2(x, y) != 0, x.is_nan() || y.is_nan());
|
||||
cmp!(f64, x, y, Double, all(),
|
||||
1, __ltdf2;
|
||||
1, __ledf2;
|
||||
1, __eqdf2;
|
||||
-1, __gedf2;
|
||||
-1, __gtdf2;
|
||||
1, __nedf2;
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
{
|
||||
fn cmp_f128() {
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
use compiler_builtins::float::cmp::{
|
||||
__eqkf2 as __eqtf2, __gekf2 as __getf2, __gtkf2 as __gttf2, __lekf2 as __letf2,
|
||||
|
|
@ -121,60 +133,71 @@ fn float_comparisons() {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! cmp2 {
|
||||
($x:ident, $y:ident, $($unordered_val:expr, $fn_std:expr, $fn_builtins:ident);*;) => {
|
||||
$(
|
||||
let cmp0: i32 = if $x.is_nan() || $y.is_nan() {
|
||||
$unordered_val
|
||||
} else {
|
||||
$fn_std as i32
|
||||
};
|
||||
let cmp1: i32 = $fn_builtins($x, $y);
|
||||
if cmp0 != cmp1 {
|
||||
panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1);
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[test]
|
||||
fn float_comparisons_arm() {
|
||||
use compiler_builtins::float::cmp::{
|
||||
__aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt,
|
||||
__aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt, __eqdf2vfp,
|
||||
__eqsf2vfp, __gedf2vfp, __gesf2vfp, __gtdf2vfp, __gtsf2vfp, __ledf2vfp, __lesf2vfp,
|
||||
__ltdf2vfp, __ltsf2vfp, __nedf2vfp, __nesf2vfp,
|
||||
};
|
||||
mod float_comparisons_arm {
|
||||
use super::*;
|
||||
|
||||
fuzz_float_2(N, |x: f32, y: f32| {
|
||||
cmp2!(x, y,
|
||||
0, x < y, __aeabi_fcmplt;
|
||||
0, x <= y, __aeabi_fcmple;
|
||||
0, x == y, __aeabi_fcmpeq;
|
||||
0, x >= y, __aeabi_fcmpge;
|
||||
0, x > y, __aeabi_fcmpgt;
|
||||
0, x < y, __ltsf2vfp;
|
||||
0, x <= y, __lesf2vfp;
|
||||
0, x == y, __eqsf2vfp;
|
||||
0, x >= y, __gesf2vfp;
|
||||
0, x > y, __gtsf2vfp;
|
||||
1, x != y, __nesf2vfp;
|
||||
);
|
||||
});
|
||||
fuzz_float_2(N, |x: f64, y: f64| {
|
||||
cmp2!(x, y,
|
||||
0, x < y, __aeabi_dcmplt;
|
||||
0, x <= y, __aeabi_dcmple;
|
||||
0, x == y, __aeabi_dcmpeq;
|
||||
0, x >= y, __aeabi_dcmpge;
|
||||
0, x > y, __aeabi_dcmpgt;
|
||||
0, x < y, __ltdf2vfp;
|
||||
0, x <= y, __ledf2vfp;
|
||||
0, x == y, __eqdf2vfp;
|
||||
0, x >= y, __gedf2vfp;
|
||||
0, x > y, __gtdf2vfp;
|
||||
1, x != y, __nedf2vfp;
|
||||
);
|
||||
});
|
||||
macro_rules! cmp2 {
|
||||
($x:ident, $y:ident, $($unordered_val:expr, $fn_std:expr, $fn_builtins:ident);*;) => {
|
||||
$(
|
||||
let cmp0: i32 = if $x.is_nan() || $y.is_nan() {
|
||||
$unordered_val
|
||||
} else {
|
||||
$fn_std as i32
|
||||
};
|
||||
let cmp1: i32 = $fn_builtins($x, $y);
|
||||
if cmp0 != cmp1 {
|
||||
panic!("{}({}, {}): std: {}, builtins: {}", stringify!($fn_builtins), $x, $y, cmp0, cmp1);
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmp_f32() {
|
||||
use compiler_builtins::float::cmp::{
|
||||
__aeabi_fcmpeq, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmple, __aeabi_fcmplt,
|
||||
__eqsf2vfp, __gesf2vfp, __gtsf2vfp, __lesf2vfp, __ltsf2vfp, __nesf2vfp,
|
||||
};
|
||||
|
||||
fuzz_float_2(N, |x: f32, y: f32| {
|
||||
cmp2!(x, y,
|
||||
0, x < y, __aeabi_fcmplt;
|
||||
0, x <= y, __aeabi_fcmple;
|
||||
0, x == y, __aeabi_fcmpeq;
|
||||
0, x >= y, __aeabi_fcmpge;
|
||||
0, x > y, __aeabi_fcmpgt;
|
||||
0, x < y, __ltsf2vfp;
|
||||
0, x <= y, __lesf2vfp;
|
||||
0, x == y, __eqsf2vfp;
|
||||
0, x >= y, __gesf2vfp;
|
||||
0, x > y, __gtsf2vfp;
|
||||
1, x != y, __nesf2vfp;
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmp_f64() {
|
||||
use compiler_builtins::float::cmp::{
|
||||
__aeabi_dcmpeq, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmple, __aeabi_dcmplt,
|
||||
__eqdf2vfp, __gedf2vfp, __gtdf2vfp, __ledf2vfp, __ltdf2vfp, __nedf2vfp,
|
||||
};
|
||||
|
||||
fuzz_float_2(N, |x: f64, y: f64| {
|
||||
cmp2!(x, y,
|
||||
0, x < y, __aeabi_dcmplt;
|
||||
0, x <= y, __aeabi_dcmple;
|
||||
0, x == y, __aeabi_dcmpeq;
|
||||
0, x >= y, __aeabi_dcmpge;
|
||||
0, x > y, __aeabi_dcmpgt;
|
||||
0, x < y, __ltdf2vfp;
|
||||
0, x <= y, __ledf2vfp;
|
||||
0, x == y, __eqdf2vfp;
|
||||
0, x >= y, __gedf2vfp;
|
||||
0, x > y, __gtdf2vfp;
|
||||
1, x != y, __nedf2vfp;
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,84 +2,83 @@
|
|||
#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))]
|
||||
// makes configuration easier
|
||||
#![allow(unused_macros)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use compiler_builtins::float::Float;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
use rustc_apfloat::ieee::{Half, Quad};
|
||||
use rustc_apfloat::{Float as _, FloatConvert as _};
|
||||
use testcrate::*;
|
||||
|
||||
macro_rules! i_to_f {
|
||||
($($from:ty, $into:ty, $fn:ident);*;) => {
|
||||
$(
|
||||
fuzz(N, |x: $from| {
|
||||
let f0 = x as $into;
|
||||
let f1: $into = $fn(x);
|
||||
// This makes sure that the conversion produced the best rounding possible, and does
|
||||
// this independent of `x as $into` rounding correctly.
|
||||
// This assumes that float to integer conversion is correct.
|
||||
let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from;
|
||||
let y = f1 as $from;
|
||||
let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from;
|
||||
let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x);
|
||||
let error = <$from as Int>::abs_diff(y, x);
|
||||
let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x);
|
||||
// The first two conditions check that none of the two closest float values are
|
||||
// strictly closer in representation to `x`. The second makes sure that rounding is
|
||||
// towards even significand if two float values are equally close to the integer.
|
||||
if error_minus < error
|
||||
|| error_plus < error
|
||||
|| ((error_minus == error || error_plus == error)
|
||||
&& ((f0.to_bits() & 1) != 0))
|
||||
{
|
||||
if !cfg!(any(
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
panic!(
|
||||
"incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})",
|
||||
stringify!($fn),
|
||||
x,
|
||||
f1.to_bits(),
|
||||
y_minus_ulp,
|
||||
y,
|
||||
y_plus_ulp,
|
||||
error_minus,
|
||||
error,
|
||||
error_plus,
|
||||
);
|
||||
}
|
||||
}
|
||||
// Test against native conversion. We disable testing on all `x86` because of
|
||||
// rounding bugs with `i686`. `powerpc` also has the same rounding bug.
|
||||
if f0 != f1 && !cfg!(any(
|
||||
target_arch = "x86",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
panic!(
|
||||
"{}({}): std: {}, builtins: {}",
|
||||
stringify!($fn),
|
||||
x,
|
||||
f0,
|
||||
f1,
|
||||
);
|
||||
}
|
||||
});
|
||||
)*
|
||||
};
|
||||
}
|
||||
mod int_to_float {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn int_to_float() {
|
||||
use compiler_builtins::float::conv::{
|
||||
__floatdidf, __floatdisf, __floatsidf, __floatsisf, __floattidf, __floattisf,
|
||||
__floatundidf, __floatundisf, __floatunsidf, __floatunsisf, __floatuntidf, __floatuntisf,
|
||||
};
|
||||
use compiler_builtins::int::Int;
|
||||
macro_rules! i_to_f {
|
||||
($($from:ty, $into:ty, $fn:ident);*;) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::float::conv::$fn;
|
||||
use compiler_builtins::int::Int;
|
||||
|
||||
i_to_f!(
|
||||
fuzz(N, |x: $from| {
|
||||
let f0 = x as $into;
|
||||
let f1: $into = $fn(x);
|
||||
// This makes sure that the conversion produced the best rounding possible, and does
|
||||
// this independent of `x as $into` rounding correctly.
|
||||
// This assumes that float to integer conversion is correct.
|
||||
let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from;
|
||||
let y = f1 as $from;
|
||||
let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from;
|
||||
let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x);
|
||||
let error = <$from as Int>::abs_diff(y, x);
|
||||
let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x);
|
||||
// The first two conditions check that none of the two closest float values are
|
||||
// strictly closer in representation to `x`. The second makes sure that rounding is
|
||||
// towards even significand if two float values are equally close to the integer.
|
||||
if error_minus < error
|
||||
|| error_plus < error
|
||||
|| ((error_minus == error || error_plus == error)
|
||||
&& ((f0.to_bits() & 1) != 0))
|
||||
{
|
||||
if !cfg!(any(
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
panic!(
|
||||
"incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})",
|
||||
stringify!($fn),
|
||||
x,
|
||||
f1.to_bits(),
|
||||
y_minus_ulp,
|
||||
y,
|
||||
y_plus_ulp,
|
||||
error_minus,
|
||||
error,
|
||||
error_plus,
|
||||
);
|
||||
}
|
||||
}
|
||||
// Test against native conversion. We disable testing on all `x86` because of
|
||||
// rounding bugs with `i686`. `powerpc` also has the same rounding bug.
|
||||
if f0 != f1 && !cfg!(any(
|
||||
target_arch = "x86",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64"
|
||||
)) {
|
||||
panic!(
|
||||
"{}({}): std: {}, builtins: {}",
|
||||
stringify!($fn),
|
||||
x,
|
||||
f0,
|
||||
f1,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
i_to_f! {
|
||||
u32, f32, __floatunsisf;
|
||||
u32, f64, __floatunsidf;
|
||||
i32, f32, __floatsisf;
|
||||
|
|
@ -92,53 +91,64 @@ fn int_to_float() {
|
|||
u128, f64, __floatuntidf;
|
||||
i128, f32, __floattisf;
|
||||
i128, f64, __floattidf;
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! f_to_i {
|
||||
($x:ident, $($f:ty, $fn:ident);*;) => {
|
||||
$(
|
||||
// it is undefined behavior in the first place to do conversions with NaNs
|
||||
if !$x.is_nan() {
|
||||
let conv0 = $x as $f;
|
||||
let conv1: $f = $fn($x);
|
||||
if conv0 != conv1 {
|
||||
panic!("{}({}): std: {}, builtins: {}", stringify!($fn), $x, conv0, conv1);
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
|
||||
#[cfg(not(target_arch = "powerpc64"))]
|
||||
#[test]
|
||||
fn float_to_int() {
|
||||
use compiler_builtins::float::conv::{
|
||||
__fixdfdi, __fixdfsi, __fixdfti, __fixsfdi, __fixsfsi, __fixsfti, __fixunsdfdi,
|
||||
__fixunsdfsi, __fixunsdfti, __fixunssfdi, __fixunssfsi, __fixunssfti,
|
||||
};
|
||||
mod f_to_i {
|
||||
use super::*;
|
||||
|
||||
fuzz_float(N, |x: f32| {
|
||||
f_to_i!(x,
|
||||
u32, __fixunssfsi;
|
||||
u64, __fixunssfdi;
|
||||
u128, __fixunssfti;
|
||||
i32, __fixsfsi;
|
||||
i64, __fixsfdi;
|
||||
i128, __fixsfti;
|
||||
);
|
||||
});
|
||||
fuzz_float(N, |x: f64| {
|
||||
f_to_i!(x,
|
||||
u32, __fixunsdfsi;
|
||||
u64, __fixunsdfdi;
|
||||
u128, __fixunsdfti;
|
||||
i32, __fixdfsi;
|
||||
i64, __fixdfdi;
|
||||
i128, __fixdfti;
|
||||
);
|
||||
});
|
||||
macro_rules! f_to_i {
|
||||
($x:ident, $($f:ty, $fn:ident);*;) => {
|
||||
$(
|
||||
// it is undefined behavior in the first place to do conversions with NaNs
|
||||
if !$x.is_nan() {
|
||||
let conv0 = $x as $f;
|
||||
let conv1: $f = $fn($x);
|
||||
if conv0 != conv1 {
|
||||
panic!("{}({}): std: {}, builtins: {}", stringify!($fn), $x, conv0, conv1);
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f32_to_int() {
|
||||
use compiler_builtins::float::conv::{
|
||||
__fixsfdi, __fixsfsi, __fixsfti, __fixunssfdi, __fixunssfsi, __fixunssfti,
|
||||
};
|
||||
|
||||
fuzz_float(N, |x: f32| {
|
||||
f_to_i!(x,
|
||||
u32, __fixunssfsi;
|
||||
u64, __fixunssfdi;
|
||||
u128, __fixunssfti;
|
||||
i32, __fixsfsi;
|
||||
i64, __fixsfdi;
|
||||
i128, __fixsfti;
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f64_to_int() {
|
||||
use compiler_builtins::float::conv::{
|
||||
__fixdfdi, __fixdfsi, __fixdfti, __fixunsdfdi, __fixunsdfsi, __fixunsdfti,
|
||||
};
|
||||
|
||||
fuzz_float(N, |x: f64| {
|
||||
f_to_i!(x,
|
||||
u32, __fixunsdfsi;
|
||||
u64, __fixunsdfdi;
|
||||
u128, __fixunsdfti;
|
||||
i32, __fixdfsi;
|
||||
i64, __fixdfdi;
|
||||
i128, __fixdfti;
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! conv {
|
||||
|
|
@ -161,40 +171,54 @@ macro_rules! conv {
|
|||
|
||||
macro_rules! extend {
|
||||
($fX:ident, $fD:ident, $fn:ident) => {
|
||||
fuzz_float(N, |x: $fX| {
|
||||
let tmp0 = x as $fD;
|
||||
let tmp1: $fD = $fn(x);
|
||||
if !Float::eq_repr(tmp0, tmp1) {
|
||||
panic!(
|
||||
"{}({}): std: {}, builtins: {}",
|
||||
stringify!($fn),
|
||||
x,
|
||||
tmp0,
|
||||
tmp1
|
||||
);
|
||||
}
|
||||
});
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::float::extend::$fn;
|
||||
|
||||
fuzz_float(N, |x: $fX| {
|
||||
let tmp0 = x as $fD;
|
||||
let tmp1: $fD = $fn(x);
|
||||
if !Float::eq_repr(tmp0, tmp1) {
|
||||
panic!(
|
||||
"{}({}): std: {}, builtins: {}",
|
||||
stringify!($fn),
|
||||
x,
|
||||
tmp0,
|
||||
tmp1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
|
||||
#[cfg(not(target_arch = "powerpc64"))]
|
||||
#[test]
|
||||
fn float_extend() {
|
||||
use compiler_builtins::float::extend::__extendsfdf2;
|
||||
mod float_extend {
|
||||
use super::*;
|
||||
|
||||
extend!(f32, f64, __extendsfdf2);
|
||||
conv!(f32, f64, __extendsfdf2, Single, Double);
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
{
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::extend::__extendsfdf2;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
|
||||
conv!(f32, f64, __extendsfdf2, Single, Double);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
mod float_extend_f128 {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::extend::{
|
||||
__extenddfkf2 as __extenddftf2, __extendhfkf2 as __extendhftf2,
|
||||
__extendsfkf2 as __extendsftf2,
|
||||
__extenddftf2, __extendhfsf2, __extendhftf2, __extendsftf2, __gnu_h2f_ieee,
|
||||
};
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
use compiler_builtins::float::extend::{__extenddftf2, __extendhftf2, __extendsftf2};
|
||||
use compiler_builtins::float::extend::{__extendhfsf2, __gnu_h2f_ieee};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
|
||||
// FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly
|
||||
conv!(f16, f32, __extendhfsf2, Half, Single);
|
||||
|
|
@ -205,49 +229,91 @@ fn float_extend() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
mod float_extend_f128_ppc {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::extend::{
|
||||
__extenddfkf2, __extendhfkf2, __extendhfsf2, __extendsfkf2, __gnu_h2f_ieee,
|
||||
};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
|
||||
// FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly
|
||||
conv!(f16, f32, __extendhfsf2, Half, Single);
|
||||
conv!(f16, f32, __gnu_h2f_ieee, Half, Single);
|
||||
conv!(f16, f128, __extendhfkf2, Half, Quad);
|
||||
conv!(f32, f128, __extendsfkf2, Single, Quad);
|
||||
conv!(f64, f128, __extenddfkf2, Double, Quad);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[test]
|
||||
fn float_extend_arm() {
|
||||
use compiler_builtins::float::extend::__extendsfdf2vfp;
|
||||
mod float_extend_arm {
|
||||
use super::*;
|
||||
|
||||
extend!(f32, f64, __extendsfdf2vfp);
|
||||
conv!(f32, f64, __extendsfdf2vfp, Single, Double);
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::extend::__extendsfdf2vfp;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
|
||||
conv!(f32, f64, __extendsfdf2vfp, Single, Double);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! trunc {
|
||||
($fX:ident, $fD:ident, $fn:ident) => {
|
||||
fuzz_float(N, |x: $fX| {
|
||||
let tmp0 = x as $fD;
|
||||
let tmp1: $fD = $fn(x);
|
||||
if !Float::eq_repr(tmp0, tmp1) {
|
||||
panic!(
|
||||
"{}({}): std: {}, builtins: {}",
|
||||
stringify!($fn),
|
||||
x,
|
||||
tmp0,
|
||||
tmp1
|
||||
);
|
||||
}
|
||||
});
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::float::trunc::$fn;
|
||||
|
||||
fuzz_float(N, |x: $fX| {
|
||||
let tmp0 = x as $fD;
|
||||
let tmp1: $fD = $fn(x);
|
||||
if !Float::eq_repr(tmp0, tmp1) {
|
||||
panic!(
|
||||
"{}({}): std: {}, builtins: {}",
|
||||
stringify!($fn),
|
||||
x,
|
||||
tmp0,
|
||||
tmp1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn float_trunc() {
|
||||
use compiler_builtins::float::trunc::__truncdfsf2;
|
||||
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
|
||||
#[cfg(not(target_arch = "powerpc64"))]
|
||||
mod float_trunc {
|
||||
use super::*;
|
||||
|
||||
trunc!(f64, f32, __truncdfsf2);
|
||||
conv!(f64, f32, __truncdfsf2, Double, Single);
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
{
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::trunc::__truncdfsf2;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
|
||||
conv!(f64, f32, __truncdfsf2, Double, Single);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
mod float_trunc_f128 {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2};
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
use compiler_builtins::float::trunc::{
|
||||
__trunckfdf2 as __trunctfdf2, __trunckfhf2 as __trunctfhf2,
|
||||
__trunckfsf2 as __trunctfsf2,
|
||||
};
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
use compiler_builtins::float::trunc::{__trunctfdf2, __trunctfhf2, __trunctfsf2};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
|
||||
// FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly
|
||||
conv!(f32, f16, __truncsfhf2, Single, Half);
|
||||
|
|
@ -259,11 +325,38 @@ fn float_trunc() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
mod float_trunc_f128_ppc {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2};
|
||||
use compiler_builtins::float::trunc::{__trunckfdf2, __trunckfhf2, __trunckfsf2};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
|
||||
// FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly
|
||||
conv!(f32, f16, __truncsfhf2, Single, Half);
|
||||
conv!(f32, f16, __gnu_f2h_ieee, Single, Half);
|
||||
conv!(f64, f16, __truncdfhf2, Double, Half);
|
||||
conv!(f128, f16, __trunckfhf2, Quad, Half);
|
||||
conv!(f128, f32, __trunckfsf2, Quad, Single);
|
||||
conv!(f128, f64, __trunckfdf2, Quad, Double);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[test]
|
||||
fn float_trunc_arm() {
|
||||
use compiler_builtins::float::trunc::__truncdfsf2vfp;
|
||||
mod float_trunc_arm {
|
||||
use super::*;
|
||||
|
||||
trunc!(f64, f32, __truncdfsf2vfp);
|
||||
conv!(f64, f32, __truncdfsf2vfp, Double, Single)
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::trunc::__truncdfsf2vfp;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
|
||||
conv!(f64, f32, __truncdfsf2vfp, Double, Single)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,24 +107,15 @@ fn divide_sparc() {
|
|||
macro_rules! float {
|
||||
($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => {
|
||||
$(
|
||||
fuzz_float_2(N, |x: $f, y: $f| {
|
||||
let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y);
|
||||
let quo1: $f = $fn(x, y);
|
||||
#[cfg(not(target_arch = "arm"))]
|
||||
if !Float::eq_repr(quo0, quo1) {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn),
|
||||
x,
|
||||
y,
|
||||
quo0,
|
||||
quo1
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::float::{div::$fn, Float};
|
||||
use core::ops::Div;
|
||||
|
||||
// ARM SIMD instructions always flush subnormals to zero
|
||||
#[cfg(target_arch = "arm")]
|
||||
if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) {
|
||||
fuzz_float_2(N, |x: $f, y: $f| {
|
||||
let quo0: $f = apfloat_fallback!($f, $apfloat_ty, $sys_available, Div::div, x, y);
|
||||
let quo1: $f = $fn(x, y);
|
||||
#[cfg(not(target_arch = "arm"))]
|
||||
if !Float::eq_repr(quo0, quo1) {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
|
|
@ -135,38 +126,43 @@ macro_rules! float {
|
|||
quo1
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ARM SIMD instructions always flush subnormals to zero
|
||||
#[cfg(target_arch = "arm")]
|
||||
if !(Float::is_subnormal(quo0) || Float::is_subnormal(quo1)) {
|
||||
if !Float::eq_repr(quo0, quo1) {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn),
|
||||
x,
|
||||
y,
|
||||
quo0,
|
||||
quo1
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
|
||||
#[test]
|
||||
fn float_div() {
|
||||
use compiler_builtins::float::{
|
||||
div::{__divdf3, __divsf3},
|
||||
Float,
|
||||
};
|
||||
use core::ops::Div;
|
||||
mod float_div {
|
||||
use super::*;
|
||||
|
||||
float!(
|
||||
float! {
|
||||
f32, __divsf3, Single, all();
|
||||
f64, __divdf3, Double, all();
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[test]
|
||||
fn float_div_arm() {
|
||||
use compiler_builtins::float::{
|
||||
div::{__divdf3vfp, __divsf3vfp},
|
||||
Float,
|
||||
};
|
||||
use core::ops::Div;
|
||||
mod float_div_arm {
|
||||
use super::*;
|
||||
|
||||
float!(
|
||||
float! {
|
||||
f32, __divsf3vfp, Single, all();
|
||||
f64, __divdf3vfp, Double, all();
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,49 +98,52 @@ fn leading_zeros() {
|
|||
macro_rules! pow {
|
||||
($($f:ty, $tolerance:expr, $fn:ident);*;) => {
|
||||
$(
|
||||
fuzz_float_2(N, |x: $f, y: $f| {
|
||||
if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) {
|
||||
let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK;
|
||||
let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS;
|
||||
let n = n as i32;
|
||||
let tmp0: $f = x.powi(n);
|
||||
let tmp1: $f = $fn(x, n);
|
||||
let (a, b) = if tmp0 < tmp1 {
|
||||
(tmp0, tmp1)
|
||||
} else {
|
||||
(tmp1, tmp0)
|
||||
};
|
||||
let good = {
|
||||
if a == b {
|
||||
// handles infinity equality
|
||||
true
|
||||
} else if a < $tolerance {
|
||||
b < $tolerance
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::float::pow::$fn;
|
||||
use compiler_builtins::float::Float;
|
||||
fuzz_float_2(N, |x: $f, y: $f| {
|
||||
if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) {
|
||||
let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK;
|
||||
let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS;
|
||||
let n = n as i32;
|
||||
let tmp0: $f = x.powi(n);
|
||||
let tmp1: $f = $fn(x, n);
|
||||
let (a, b) = if tmp0 < tmp1 {
|
||||
(tmp0, tmp1)
|
||||
} else {
|
||||
let quo = b / a;
|
||||
(quo < (1. + $tolerance)) && (quo > (1. - $tolerance))
|
||||
(tmp1, tmp0)
|
||||
};
|
||||
let good = {
|
||||
if a == b {
|
||||
// handles infinity equality
|
||||
true
|
||||
} else if a < $tolerance {
|
||||
b < $tolerance
|
||||
} else {
|
||||
let quo = b / a;
|
||||
(quo < (1. + $tolerance)) && (quo > (1. - $tolerance))
|
||||
}
|
||||
};
|
||||
if !good {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn), x, n, tmp0, tmp1
|
||||
);
|
||||
}
|
||||
};
|
||||
if !good {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn), x, n, tmp0, tmp1
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
|
||||
#[test]
|
||||
fn float_pow() {
|
||||
use compiler_builtins::float::pow::{__powidf2, __powisf2};
|
||||
use compiler_builtins::float::Float;
|
||||
mod float_pow {
|
||||
use super::*;
|
||||
|
||||
pow!(
|
||||
pow! {
|
||||
f32, 1e-4, __powisf2;
|
||||
f64, 1e-12, __powidf2;
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,146 +4,164 @@
|
|||
|
||||
use testcrate::*;
|
||||
|
||||
macro_rules! mul {
|
||||
($($i:ty, $fn:ident);*;) => {
|
||||
$(
|
||||
fuzz_2(N, |x: $i, y: $i| {
|
||||
let mul0 = x.wrapping_mul(y);
|
||||
let mul1: $i = $fn(x, y);
|
||||
if mul0 != mul1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn), x, y, mul0, mul1
|
||||
);
|
||||
mod int_mul {
|
||||
use super::*;
|
||||
|
||||
macro_rules! mul {
|
||||
($($i:ty, $fn:ident);*;) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::int::mul::$fn;
|
||||
|
||||
fuzz_2(N, |x: $i, y: $i| {
|
||||
let mul0 = x.wrapping_mul(y);
|
||||
let mul1: $i = $fn(x, y);
|
||||
if mul0 != mul1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn), x, y, mul0, mul1
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
)*
|
||||
};
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mul() {
|
||||
use compiler_builtins::int::mul::{__muldi3, __multi3};
|
||||
|
||||
mul!(
|
||||
mul! {
|
||||
u64, __muldi3;
|
||||
i128, __multi3;
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! overflowing_mul {
|
||||
($($i:ty, $fn:ident);*;) => {
|
||||
$(
|
||||
fuzz_2(N, |x: $i, y: $i| {
|
||||
let (mul0, o0) = x.overflowing_mul(y);
|
||||
let mut o1 = 0i32;
|
||||
let mul1: $i = $fn(x, y, &mut o1);
|
||||
let o1 = o1 != 0;
|
||||
if mul0 != mul1 || o0 != o1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: ({}, {}), builtins: ({}, {})",
|
||||
stringify!($fn), x, y, mul0, o0, mul1, o1
|
||||
);
|
||||
mod int_overflowing_mul {
|
||||
use super::*;
|
||||
|
||||
macro_rules! overflowing_mul {
|
||||
($($i:ty, $fn:ident);*;) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::int::mul::$fn;
|
||||
|
||||
fuzz_2(N, |x: $i, y: $i| {
|
||||
let (mul0, o0) = x.overflowing_mul(y);
|
||||
let mut o1 = 0i32;
|
||||
let mul1: $i = $fn(x, y, &mut o1);
|
||||
let o1 = o1 != 0;
|
||||
if mul0 != mul1 || o0 != o1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: ({}, {}), builtins: ({}, {})",
|
||||
stringify!($fn), x, y, mul0, o0, mul1, o1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
)*
|
||||
};
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overflowing_mul() {
|
||||
use compiler_builtins::int::mul::{
|
||||
__mulodi4, __mulosi4, __muloti4, __rust_i128_mulo, __rust_u128_mulo,
|
||||
};
|
||||
|
||||
overflowing_mul!(
|
||||
overflowing_mul! {
|
||||
i32, __mulosi4;
|
||||
i64, __mulodi4;
|
||||
i128, __muloti4;
|
||||
);
|
||||
fuzz_2(N, |x: u128, y: u128| {
|
||||
let (mul0, o0) = x.overflowing_mul(y);
|
||||
let (mul1, o1) = __rust_u128_mulo(x, y);
|
||||
if mul0 != mul1 || o0 != o1 {
|
||||
panic!(
|
||||
"__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})",
|
||||
x, y, mul0, o0, mul1, o1
|
||||
);
|
||||
}
|
||||
let x = x as i128;
|
||||
let y = y as i128;
|
||||
let (mul0, o0) = x.overflowing_mul(y);
|
||||
let (mul1, o1) = __rust_i128_mulo(x, y);
|
||||
if mul0 != mul1 || o0 != o1 {
|
||||
panic!(
|
||||
"__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})",
|
||||
x, y, mul0, o0, mul1, o1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overflowing_mul_u128() {
|
||||
use compiler_builtins::int::mul::{__rust_i128_mulo, __rust_u128_mulo};
|
||||
|
||||
fuzz_2(N, |x: u128, y: u128| {
|
||||
let (mul0, o0) = x.overflowing_mul(y);
|
||||
let (mul1, o1) = __rust_u128_mulo(x, y);
|
||||
if mul0 != mul1 || o0 != o1 {
|
||||
panic!(
|
||||
"__rust_u128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})",
|
||||
x, y, mul0, o0, mul1, o1
|
||||
);
|
||||
}
|
||||
let x = x as i128;
|
||||
let y = y as i128;
|
||||
let (mul0, o0) = x.overflowing_mul(y);
|
||||
let (mul1, o1) = __rust_i128_mulo(x, y);
|
||||
if mul0 != mul1 || o0 != o1 {
|
||||
panic!(
|
||||
"__rust_i128_mulo({}, {}): std: ({}, {}), builtins: ({}, {})",
|
||||
x, y, mul0, o0, mul1, o1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! float_mul {
|
||||
($($f:ty, $fn:ident, $apfloat_ty:ident, $sys_available:meta);*;) => {
|
||||
$(
|
||||
fuzz_float_2(N, |x: $f, y: $f| {
|
||||
let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y);
|
||||
let mul1: $f = $fn(x, y);
|
||||
// multiplication of subnormals is not currently handled
|
||||
if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) {
|
||||
if !Float::eq_repr(mul0, mul1) {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn), x, y, mul0, mul1
|
||||
);
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::float::{mul::$fn, Float};
|
||||
use core::ops::Mul;
|
||||
|
||||
fuzz_float_2(N, |x: $f, y: $f| {
|
||||
let mul0 = apfloat_fallback!($f, $apfloat_ty, $sys_available, Mul::mul, x, y);
|
||||
let mul1: $f = $fn(x, y);
|
||||
// multiplication of subnormals is not currently handled
|
||||
if !(Float::is_subnormal(mul0) || Float::is_subnormal(mul1)) {
|
||||
if !Float::eq_repr(mul0, mul1) {
|
||||
panic!(
|
||||
"{}({:?}, {:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn), x, y, mul0, mul1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
|
||||
#[test]
|
||||
fn float_mul() {
|
||||
use compiler_builtins::float::{
|
||||
mul::{__muldf3, __mulsf3},
|
||||
Float,
|
||||
};
|
||||
use core::ops::Mul;
|
||||
mod float_mul {
|
||||
use super::*;
|
||||
|
||||
float_mul!(
|
||||
float_mul! {
|
||||
f32, __mulsf3, Single, all();
|
||||
f64, __muldf3, Double, all();
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
{
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
use compiler_builtins::float::mul::__mulkf3 as __multf3;
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
use compiler_builtins::float::mul::__multf3;
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
mod float_mul_f128 {
|
||||
use super::*;
|
||||
|
||||
float_mul!(
|
||||
f128, __multf3, Quad,
|
||||
// FIXME(llvm): there is a bug in LLVM rt.
|
||||
// See <https://github.com/llvm/llvm-project/issues/91840>.
|
||||
not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux")));
|
||||
);
|
||||
float_mul! {
|
||||
f128, __multf3, Quad,
|
||||
// FIXME(llvm): there is a bug in LLVM rt.
|
||||
// See <https://github.com/llvm/llvm-project/issues/91840>.
|
||||
not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux")));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
mod float_mul_f128_ppc {
|
||||
use super::*;
|
||||
|
||||
float_mul! {
|
||||
f128, __mulkf3, Quad, not(feature = "no-sys-f128");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[test]
|
||||
fn float_mul_arm() {
|
||||
use compiler_builtins::float::{
|
||||
mul::{__muldf3vfp, __mulsf3vfp},
|
||||
Float,
|
||||
};
|
||||
use core::ops::Mul;
|
||||
mod float_mul_arm {
|
||||
use super::*;
|
||||
|
||||
float_mul!(
|
||||
float_mul! {
|
||||
f32, __mulsf3vfp, Single, all();
|
||||
f64, __muldf3vfp, Double, all();
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,35 +3,33 @@ use testcrate::*;
|
|||
macro_rules! shift {
|
||||
($($i:ty, $fn_std:ident, $fn_builtins:ident);*;) => {
|
||||
$(
|
||||
fuzz_shift(|x: $i, s: u32| {
|
||||
let tmp0: $i = x.$fn_std(s);
|
||||
let tmp1: $i = $fn_builtins(x, s);
|
||||
if tmp0 != tmp1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn_builtins), x, s, tmp0, tmp1
|
||||
);
|
||||
}
|
||||
});
|
||||
#[test]
|
||||
fn $fn_builtins() {
|
||||
use compiler_builtins::int::shift::$fn_builtins;
|
||||
|
||||
fuzz_shift(|x: $i, s: u32| {
|
||||
let tmp0: $i = x.$fn_std(s);
|
||||
let tmp1: $i = $fn_builtins(x, s);
|
||||
if tmp0 != tmp1 {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn_builtins), x, s, tmp0, tmp1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shift() {
|
||||
use compiler_builtins::int::shift::{
|
||||
__ashldi3, __ashlsi3, __ashlti3, __ashrdi3, __ashrsi3, __ashrti3, __lshrdi3, __lshrsi3,
|
||||
__lshrti3,
|
||||
};
|
||||
shift!(
|
||||
u32, wrapping_shl, __ashlsi3;
|
||||
u64, wrapping_shl, __ashldi3;
|
||||
u128, wrapping_shl, __ashlti3;
|
||||
i32, wrapping_shr, __ashrsi3;
|
||||
i64, wrapping_shr, __ashrdi3;
|
||||
i128, wrapping_shr, __ashrti3;
|
||||
u32, wrapping_shr, __lshrsi3;
|
||||
u64, wrapping_shr, __lshrdi3;
|
||||
u128, wrapping_shr, __lshrti3;
|
||||
);
|
||||
shift! {
|
||||
u32, wrapping_shl, __ashlsi3;
|
||||
u64, wrapping_shl, __ashldi3;
|
||||
u128, wrapping_shl, __ashlti3;
|
||||
i32, wrapping_shr, __ashrsi3;
|
||||
i64, wrapping_shr, __ashrdi3;
|
||||
i128, wrapping_shr, __ashrti3;
|
||||
u32, wrapping_shr, __lshrsi3;
|
||||
u64, wrapping_shr, __lshrdi3;
|
||||
u128, wrapping_shr, __lshrti3;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue