Merge pull request #615 from tgross35/test-refactoring

Rework the test crate to separate individual tests
This commit is contained in:
Amanieu d'Antras 2024-05-21 01:08:47 +02:00 committed by GitHub
commit b07accb2c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 750 additions and 609 deletions

View file

@ -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();
);
}
}

View file

@ -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;
);
});
}
}

View file

@ -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)
}
}

View file

@ -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();
);
}
}

View file

@ -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;
);
}
}

View file

@ -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();
);
}
}

View file

@ -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;
}