Skip to content

Commit

Permalink
Add test infrastructure for f16 and f128
Browse files Browse the repository at this point in the history
Update test traits to support `f16` and `f128`, as applicable. Add the
new routines (`fabs` and `copysign` for `f16` and `f128`) to the list of
all operations.
  • Loading branch information
tgross35 committed Jan 3, 2025
1 parent b652314 commit 31a58aa
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 43 deletions.
28 changes: 28 additions & 0 deletions crates/libm-macros/src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ use std::fmt;
use std::sync::LazyLock;

const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])] = &[
(
// `fn(f16) -> f16`
FloatTy::F16,
Signature { args: &[Ty::F16], returns: &[Ty::F16] },
None,
&["fabsf16"],
),
(
// `fn(f32) -> f32`
FloatTy::F32,
Expand All @@ -28,6 +35,20 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
"tgamma", "trunc", "y0", "y1",
],
),
(
// `fn(f128) -> f128`
FloatTy::F128,
Signature { args: &[Ty::F128], returns: &[Ty::F128] },
None,
&["fabsf128"],
),
(
// `(f16, f16) -> f16`
FloatTy::F16,
Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] },
None,
&["copysignf16"],
),
(
// `(f32, f32) -> f32`
FloatTy::F32,
Expand Down Expand Up @@ -64,6 +85,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
"remainder",
],
),
(
// `(f128, f128) -> f128`
FloatTy::F128,
Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] },
None,
&["copysignf128"],
),
(
// `(f32, f32, f32) -> f32`
FloatTy::F32,
Expand Down
2 changes: 1 addition & 1 deletion crates/libm-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ publish = false
default = ["unstable-float"]

# Propagated from libm because this affects which functions we test.
unstable-float = ["libm/unstable-float"]
unstable-float = ["libm/unstable-float", "rug?/nightly-float"]

# Generate tests which are random inputs and the outputs are calculated with
# musl libc.
Expand Down
47 changes: 29 additions & 18 deletions crates/libm-test/benches/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ macro_rules! musl_rand_benches {
(
fn_name: $fn_name:ident,
attrs: [$($attr:meta),*],
fn_extra: $skip_on_i586:expr,
fn_extra: ($skip_on_i586:expr, $musl_fn:expr),
) => {
paste::paste! {
$(#[$attr])*
fn [< musl_bench_ $fn_name >](c: &mut Criterion) {
type Op = libm_test::op::$fn_name::Routine;

#[cfg(feature = "build-musl")]
let musl_extra = MuslExtra {
musl_fn: Some(musl_math_sys::$fn_name as libm_test::OpCFn<Op>),
skip_on_i586: $skip_on_i586
let musl_extra = MuslExtra::<libm_test::OpCFn<Op>> {
musl_fn: $musl_fn,
skip_on_i586: $skip_on_i586,
};

#[cfg(not(feature = "build-musl"))]
let musl_extra = MuslExtra {
musl_fn: None,
skip_on_i586: $skip_on_i586
skip_on_i586: $skip_on_i586,
};

bench_one::<Op>(c, musl_extra);
Expand Down Expand Up @@ -67,7 +67,10 @@ where
break;
}

let musl_res = input.call(musl_extra.musl_fn.unwrap());
let Some(musl_fn) = musl_extra.musl_fn else {
continue;
};
let musl_res = input.call(musl_fn);
let crate_res = input.call(Op::ROUTINE);

crate_res.validate(musl_res, input, &ctx).context(name).unwrap();
Expand All @@ -91,25 +94,33 @@ where
// Don't test against musl if it is not available
#[cfg(feature = "build-musl")]
{
let musl_fn = musl_extra.musl_fn.unwrap();
group.bench_function("musl", |b| {
b.iter(|| {
let f = black_box(musl_fn);
for input in benchvec.iter().copied() {
input.call(f);
}
})
});
if let Some(musl_fn) = musl_extra.musl_fn {
group.bench_function("musl", |b| {
b.iter(|| {
let f = black_box(musl_fn);
for input in benchvec.iter().copied() {
input.call(f);
}
})
});
}
}
}

libm_macros::for_each_function! {
callback: musl_rand_benches,
skip: [],
fn_extra: match MACRO_FN_NAME {
// FIXME(correctness): wrong result on i586
exp10 | exp10f | exp2 | exp2f => true,
_ => false
// We pass a tuple of `(skip_on_i586, musl_fn)`

// FIXME(correctness): exp functions have the wrong result on i586
exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)),

// Musl does not provide `f16` and `f128` functions
copysignf16 | copysignf128 | fabsf16 | fabsf128 => (false, None),

// By default we never skip (false) and always have a musl function available
_ => (false, Some(musl_math_sys::MACRO_FN_NAME))
}
}

Expand Down
12 changes: 12 additions & 0 deletions crates/libm-test/src/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,15 @@ impl HasDomain<f32> for crate::op::lgammaf_r::Routine {
impl HasDomain<f64> for crate::op::lgamma_r::Routine {
const DOMAIN: Domain<f64> = Domain::<f64>::LGAMMA;
}

/* Not all `f16` and `f128` functions exist yet so we can't easily use the macros. */

#[cfg(f16_enabled)]
impl HasDomain<f16> for crate::op::fabsf16::Routine {
const DOMAIN: Domain<f16> = Domain::<f16>::UNBOUNDED;
}

#[cfg(f128_enabled)]
impl HasDomain<f128> for crate::op::fabsf128::Routine {
const DOMAIN: Domain<f128> = Domain::<f128>::UNBOUNDED;
}
4 changes: 4 additions & 0 deletions crates/libm-test/src/gen/extensive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,12 @@ macro_rules! impl_extensive_input {
};
}

#[cfg(f16_enabled)]
impl_extensive_input!(f16);
impl_extensive_input!(f32);
impl_extensive_input!(f64);
#[cfg(f128_enabled)]
impl_extensive_input!(f128);

/// Create a test case iterator for extensive inputs.
pub fn get_test_cases<Op>(
Expand Down
4 changes: 4 additions & 0 deletions crates/libm-test/src/gen/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,12 @@ macro_rules! impl_random_input {
};
}

#[cfg(f16_enabled)]
impl_random_input!(f16);
impl_random_input!(f32);
impl_random_input!(f64);
#[cfg(f128_enabled)]
impl_random_input!(f128);

/// Create a test case iterator.
pub fn get_test_cases<RustArgs: RandomInput>(
Expand Down
77 changes: 53 additions & 24 deletions crates/libm-test/src/mpfloat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ libm_macros::for_each_function! {
fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf,
lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf,
remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf,
copysignf16, copysignf128, fabsf16, fabsf128,
],
fn_extra: match MACRO_FN_NAME {
// Remap function names that are different between mpfr and libm
Expand All @@ -157,10 +158,8 @@ libm_macros::for_each_function! {
/// Implement unary functions that don't have a `_round` version
macro_rules! impl_no_round {
// Unary matcher
($($fn_name:ident, $rug_name:ident;)*) => {
($($fn_name:ident => $rug_name:ident;)*) => {
paste::paste! {
// Implement for both f32 and f64
$( impl_no_round!{ @inner_unary [< $fn_name f >], $rug_name } )*
$( impl_no_round!{ @inner_unary $fn_name, $rug_name } )*
}
};
Expand All @@ -183,33 +182,34 @@ macro_rules! impl_no_round {
}

impl_no_round! {
fabs, abs_mut;
ceil, ceil_mut;
floor, floor_mut;
rint, round_even_mut; // FIXME: respect rounding mode
round, round_mut;
trunc, trunc_mut;
ceil => ceil_mut;
ceilf => ceil_mut;
fabs => abs_mut;
fabsf => abs_mut;
floor => floor_mut;
floorf => floor_mut;
rint => round_even_mut; // FIXME: respect rounding mode
rintf => round_even_mut; // FIXME: respect rounding mode
round => round_mut;
roundf => round_mut;
trunc => trunc_mut;
truncf => trunc_mut;
}

#[cfg(f16_enabled)]
impl_no_round! {
fabsf16 => abs_mut;
}

#[cfg(f128_enabled)]
impl_no_round! {
fabsf128 => abs_mut;
}

/// Some functions are difficult to do in a generic way. Implement them here.
macro_rules! impl_op_for_ty {
($fty:ty, $suffix:literal) => {
paste::paste! {
impl MpOp for crate::op::[<copysign $suffix>]::Routine {
type MpTy = (MpFloat, MpFloat);

fn new_mp() -> Self::MpTy {
(new_mpfloat::<Self::FTy>(), new_mpfloat::<Self::FTy>())
}

fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
this.0.assign(input.0);
this.1.assign(input.1);
this.0.copysign_mut(&this.1);
prep_retval::<Self::RustRet>(&mut this.0, Ordering::Equal)
}
}

impl MpOp for crate::op::[<pow $suffix>]::Routine {
type MpTy = (MpFloat, MpFloat);

Expand Down Expand Up @@ -291,9 +291,38 @@ macro_rules! impl_op_for_ty {
};
}

/// Version of `impl_op_for_ty` with only functions that have `f16` and `f128` implementations.
macro_rules! impl_op_for_ty_all {
($fty:ty, $suffix:literal) => {
paste::paste! {
impl MpOp for crate::op::[<copysign $suffix>]::Routine {
type MpTy = (MpFloat, MpFloat);

fn new_mp() -> Self::MpTy {
(new_mpfloat::<Self::FTy>(), new_mpfloat::<Self::FTy>())
}

fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
this.0.assign(input.0);
this.1.assign(input.1);
this.0.copysign_mut(&this.1);
prep_retval::<Self::RustRet>(&mut this.0, Ordering::Equal)
}
}
}
};
}

impl_op_for_ty!(f32, "f");
impl_op_for_ty!(f64, "");

#[cfg(f16_enabled)]
impl_op_for_ty_all!(f16, "f16");
impl_op_for_ty_all!(f32, "f");
impl_op_for_ty_all!(f64, "");
#[cfg(f128_enabled)]
impl_op_for_ty_all!(f128, "f128");

// `lgamma_r` is not a simple suffix so we can't use the above macro.
impl MpOp for crate::op::lgamma_r::Routine {
type MpTy = MpFloat;
Expand Down
32 changes: 32 additions & 0 deletions crates/libm-test/src/precision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ pub trait MaybeOverride<Input> {
}
}

#[cfg(f16_enabled)]
impl MaybeOverride<(f16,)> for SpecialCase {}

impl MaybeOverride<(f32,)> for SpecialCase {
fn check_float<F: Float>(
input: (f32,),
Expand Down Expand Up @@ -232,6 +235,9 @@ impl MaybeOverride<(f64,)> for SpecialCase {
}
}

#[cfg(f128_enabled)]
impl MaybeOverride<(f128,)> for SpecialCase {}

/// Check NaN bits if the function requires it
fn maybe_check_nan_bits<F: Float>(actual: F, expected: F, ctx: &CheckCtx) -> Option<TestResult> {
if !(ctx.base_name == BaseName::Fabs || ctx.base_name == BaseName::Copysign) {
Expand Down Expand Up @@ -259,6 +265,19 @@ fn maybe_check_nan_bits<F: Float>(actual: F, expected: F, ctx: &CheckCtx) -> Opt
}
}

#[cfg(f16_enabled)]
impl MaybeOverride<(f16, f16)> for SpecialCase {
fn check_float<F: Float>(
input: (f16, f16),
_actual: F,
expected: F,
_ulp: &mut u32,
ctx: &CheckCtx,
) -> Option<TestResult> {
maybe_skip_binop_nan(input, expected, ctx)
}
}

impl MaybeOverride<(f32, f32)> for SpecialCase {
fn check_float<F: Float>(
input: (f32, f32),
Expand All @@ -283,6 +302,19 @@ impl MaybeOverride<(f64, f64)> for SpecialCase {
}
}

#[cfg(f128_enabled)]
impl MaybeOverride<(f128, f128)> for SpecialCase {
fn check_float<F: Float>(
input: (f128, f128),
_actual: F,
expected: F,
_ulp: &mut u32,
ctx: &CheckCtx,
) -> Option<TestResult> {
maybe_skip_binop_nan(input, expected, ctx)
}
}

/// Musl propagates NaNs if one is provided as the input, but we return the other input.
// F1 and F2 are always the same type, this is just to please generics
fn maybe_skip_binop_nan<F1: Float, F2: Float>(
Expand Down
6 changes: 6 additions & 0 deletions crates/libm-test/src/test_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,12 @@ where

impl_float!(f32, f64);

#[cfg(f16_enabled)]
impl_float!(f16);

#[cfg(f128_enabled)]
impl_float!(f128);

/* trait implementations for compound types */

/// Implement `CheckOutput` for combinations of types.
Expand Down
2 changes: 2 additions & 0 deletions crates/libm-test/tests/compare_built_musl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ where

libm_macros::for_each_function! {
callback: musl_rand_tests,
// Musl does not support `f16` and `f128` on all platforms.
skip: [copysignf16, copysignf128, fabsf16, fabsf128],
attributes: [
#[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586
[exp10, exp10f, exp2, exp2f, rint]
Expand Down
2 changes: 2 additions & 0 deletions crates/libm-test/tests/multiprecision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ libm_macros::for_each_function! {
atan2f,
copysign,
copysignf,
copysignf16,
copysignf128,
fdim,
fdimf,
fma,
Expand Down
Loading

0 comments on commit 31a58aa

Please sign in to comment.