mirror of
https://github.com/rust-lang/rust.git
synced 2025-11-17 18:26:00 +00:00
Rework the test crate to separate individual tests
Currently, tests of the same kind are grouped together across all types into a single function. This makes it difficult to understand exactly what failed in CI. Change test macros to create separate functions for separate types so failures are more fine grained.
This commit is contained in:
parent
f8b72ede7e
commit
f82e1f14fc
@ -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…
x
Reference in New Issue
Block a user