Skip to content

Commit e6907f5

Browse files
committed
Add test infrastructure for f16 and f128
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.
1 parent b652314 commit e6907f5

13 files changed

+210
-28
lines changed

crates/libm-macros/src/shared.rs

+28
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ use std::fmt;
44
use std::sync::LazyLock;
55

66
const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])] = &[
7+
(
8+
// `fn(f16) -> f16`
9+
FloatTy::F16,
10+
Signature { args: &[Ty::F16], returns: &[Ty::F16] },
11+
None,
12+
&["fabsf16"],
13+
),
714
(
815
// `fn(f32) -> f32`
916
FloatTy::F32,
@@ -28,6 +35,20 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
2835
"tgamma", "trunc", "y0", "y1",
2936
],
3037
),
38+
(
39+
// `fn(f128) -> f128`
40+
FloatTy::F128,
41+
Signature { args: &[Ty::F128], returns: &[Ty::F128] },
42+
None,
43+
&["fabsf128"],
44+
),
45+
(
46+
// `(f16, f16) -> f16`
47+
FloatTy::F16,
48+
Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] },
49+
None,
50+
&["copysignf16"],
51+
),
3152
(
3253
// `(f32, f32) -> f32`
3354
FloatTy::F32,
@@ -64,6 +85,13 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
6485
"remainder",
6586
],
6687
),
88+
(
89+
// `(f128, f128) -> f128`
90+
FloatTy::F128,
91+
Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] },
92+
None,
93+
&["copysignf128"],
94+
),
6795
(
6896
// `(f32, f32, f32) -> f32`
6997
FloatTy::F32,

crates/libm-test/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ publish = false
88
default = ["unstable-float"]
99

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

1313
# Generate tests which are random inputs and the outputs are calculated with
1414
# musl libc.

crates/libm-test/benches/random.rs

+29-18
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,23 @@ macro_rules! musl_rand_benches {
2020
(
2121
fn_name: $fn_name:ident,
2222
attrs: [$($attr:meta),*],
23-
fn_extra: $skip_on_i586:expr,
23+
fn_extra: ($skip_on_i586:expr, $musl_fn:expr),
2424
) => {
2525
paste::paste! {
2626
$(#[$attr])*
2727
fn [< musl_bench_ $fn_name >](c: &mut Criterion) {
2828
type Op = libm_test::op::$fn_name::Routine;
2929

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

3636
#[cfg(not(feature = "build-musl"))]
3737
let musl_extra = MuslExtra {
3838
musl_fn: None,
39-
skip_on_i586: $skip_on_i586
39+
skip_on_i586: $skip_on_i586,
4040
};
4141

4242
bench_one::<Op>(c, musl_extra);
@@ -67,7 +67,10 @@ where
6767
break;
6868
}
6969

70-
let musl_res = input.call(musl_extra.musl_fn.unwrap());
70+
let Some(musl_fn) = musl_extra.musl_fn else {
71+
continue;
72+
};
73+
let musl_res = input.call(musl_fn);
7174
let crate_res = input.call(Op::ROUTINE);
7275

7376
crate_res.validate(musl_res, input, &ctx).context(name).unwrap();
@@ -91,25 +94,33 @@ where
9194
// Don't test against musl if it is not available
9295
#[cfg(feature = "build-musl")]
9396
{
94-
let musl_fn = musl_extra.musl_fn.unwrap();
95-
group.bench_function("musl", |b| {
96-
b.iter(|| {
97-
let f = black_box(musl_fn);
98-
for input in benchvec.iter().copied() {
99-
input.call(f);
100-
}
101-
})
102-
});
97+
if let Some(musl_fn) = musl_extra.musl_fn {
98+
group.bench_function("musl", |b| {
99+
b.iter(|| {
100+
let f = black_box(musl_fn);
101+
for input in benchvec.iter().copied() {
102+
input.call(f);
103+
}
104+
})
105+
});
106+
}
103107
}
104108
}
105109

106110
libm_macros::for_each_function! {
107111
callback: musl_rand_benches,
108112
skip: [],
109113
fn_extra: match MACRO_FN_NAME {
110-
// FIXME(correctness): wrong result on i586
111-
exp10 | exp10f | exp2 | exp2f => true,
112-
_ => false
114+
// We pass a tuple of `(skip_on_i586, musl_fn)`
115+
116+
// FIXME(correctness): exp functions have the wrong result on i586
117+
exp10 | exp10f | exp2 | exp2f => (true, Some(musl_math_sys::MACRO_FN_NAME)),
118+
119+
// Musl does not provide `f16` and `f128` functions
120+
copysignf16 | copysignf128 | fabsf16 | fabsf128 => (false, None),
121+
122+
// By default we never skip (false) and always have a musl function available
123+
_ => (false, Some(musl_math_sys::MACRO_FN_NAME))
113124
}
114125
}
115126

crates/libm-test/src/domain.rs

+12
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,15 @@ impl HasDomain<f32> for crate::op::lgammaf_r::Routine {
187187
impl HasDomain<f64> for crate::op::lgamma_r::Routine {
188188
const DOMAIN: Domain<f64> = Domain::<f64>::LGAMMA;
189189
}
190+
191+
/* Not all `f16` and `f128` functions exist yet so we can't easily use the macros. */
192+
193+
#[cfg(f16_enabled)]
194+
impl HasDomain<f16> for crate::op::fabsf16::Routine {
195+
const DOMAIN: Domain<f16> = Domain::<f16>::UNBOUNDED;
196+
}
197+
198+
#[cfg(f128_enabled)]
199+
impl HasDomain<f128> for crate::op::fabsf128::Routine {
200+
const DOMAIN: Domain<f128> = Domain::<f128>::UNBOUNDED;
201+
}

crates/libm-test/src/gen/extensive.rs

+4
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,12 @@ macro_rules! impl_extensive_input {
118118
};
119119
}
120120

121+
#[cfg(f16_enabled)]
122+
impl_extensive_input!(f16);
121123
impl_extensive_input!(f32);
122124
impl_extensive_input!(f64);
125+
#[cfg(f128_enabled)]
126+
impl_extensive_input!(f128);
123127

124128
/// Create a test case iterator for extensive inputs.
125129
pub fn get_test_cases<Op>(

crates/libm-test/src/gen/random.rs

+4
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,12 @@ macro_rules! impl_random_input {
9494
};
9595
}
9696

97+
#[cfg(f16_enabled)]
98+
impl_random_input!(f16);
9799
impl_random_input!(f32);
98100
impl_random_input!(f64);
101+
#[cfg(f128_enabled)]
102+
impl_random_input!(f128);
99103

100104
/// Create a test case iterator.
101105
pub fn get_test_cases<RustArgs: RandomInput>(

crates/libm-test/src/mpfloat.rs

+58-9
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ libm_macros::for_each_function! {
137137
fmod, fmodf, frexp, frexpf, ilogb, ilogbf, jn, jnf, ldexp, ldexpf,
138138
lgamma_r, lgammaf_r, modf, modff, nextafter, nextafterf, pow,powf,
139139
remquo, remquof, scalbn, scalbnf, sincos, sincosf, yn, ynf,
140+
copysignf16, copysignf128, fabsf16, fabsf128,
140141
],
141142
fn_extra: match MACRO_FN_NAME {
142143
// Remap function names that are different between mpfr and libm
@@ -157,10 +158,8 @@ libm_macros::for_each_function! {
157158
/// Implement unary functions that don't have a `_round` version
158159
macro_rules! impl_no_round {
159160
// Unary matcher
160-
($($fn_name:ident, $rug_name:ident;)*) => {
161+
($($fn_name:ident => $rug_name:ident;)*) => {
161162
paste::paste! {
162-
// Implement for both f32 and f64
163-
$( impl_no_round!{ @inner_unary [< $fn_name f >], $rug_name } )*
164163
$( impl_no_round!{ @inner_unary $fn_name, $rug_name } )*
165164
}
166165
};
@@ -183,12 +182,28 @@ macro_rules! impl_no_round {
183182
}
184183

185184
impl_no_round! {
186-
fabs, abs_mut;
187-
ceil, ceil_mut;
188-
floor, floor_mut;
189-
rint, round_even_mut; // FIXME: respect rounding mode
190-
round, round_mut;
191-
trunc, trunc_mut;
185+
ceil => ceil_mut;
186+
ceilf => ceil_mut;
187+
fabs => abs_mut;
188+
fabsf => abs_mut;
189+
floor => floor_mut;
190+
floorf => floor_mut;
191+
rint => round_even_mut; // FIXME: respect rounding mode
192+
rintf => round_even_mut; // FIXME: respect rounding mode
193+
round => round_mut;
194+
roundf => round_mut;
195+
trunc => trunc_mut;
196+
truncf => trunc_mut;
197+
}
198+
199+
#[cfg(f16_enabled)]
200+
impl_no_round! {
201+
fabsf16 => abs_mut;
202+
}
203+
204+
#[cfg(f128_enabled)]
205+
impl_no_round! {
206+
fabsf128 => abs_mut;
192207
}
193208

194209
/// Some functions are difficult to do in a generic way. Implement them here.
@@ -324,3 +339,37 @@ impl MpOp for crate::op::lgammaf_r::Routine {
324339
(ret, sign as i32)
325340
}
326341
}
342+
343+
/* Not all `f16` and `f128` functions exist yet so we can't easily use the macros. */
344+
345+
#[cfg(f16_enabled)]
346+
impl MpOp for crate::op::copysignf16::Routine {
347+
type MpTy = (MpFloat, MpFloat);
348+
349+
fn new_mp() -> Self::MpTy {
350+
(new_mpfloat::<f16>(), new_mpfloat::<f16>())
351+
}
352+
353+
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
354+
this.0.assign(input.0);
355+
this.1.assign(input.1);
356+
this.0.copysign_mut(&this.1);
357+
prep_retval::<Self::RustRet>(&mut this.0, Ordering::Equal)
358+
}
359+
}
360+
361+
#[cfg(f128_enabled)]
362+
impl MpOp for crate::op::copysignf128::Routine {
363+
type MpTy = (MpFloat, MpFloat);
364+
365+
fn new_mp() -> Self::MpTy {
366+
(new_mpfloat::<f128>(), new_mpfloat::<f128>())
367+
}
368+
369+
fn run(this: &mut Self::MpTy, input: Self::RustArgs) -> Self::RustRet {
370+
this.0.assign(input.0);
371+
this.1.assign(input.1);
372+
this.0.copysign_mut(&this.1);
373+
prep_retval::<Self::RustRet>(&mut this.0, Ordering::Equal)
374+
}
375+
}

crates/libm-test/src/precision.rs

+32
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ pub trait MaybeOverride<Input> {
9999
}
100100
}
101101

102+
#[cfg(f16_enabled)]
103+
impl MaybeOverride<(f16,)> for SpecialCase {}
104+
102105
impl MaybeOverride<(f32,)> for SpecialCase {
103106
fn check_float<F: Float>(
104107
input: (f32,),
@@ -232,6 +235,9 @@ impl MaybeOverride<(f64,)> for SpecialCase {
232235
}
233236
}
234237

238+
#[cfg(f128_enabled)]
239+
impl MaybeOverride<(f128,)> for SpecialCase {}
240+
235241
/// Check NaN bits if the function requires it
236242
fn maybe_check_nan_bits<F: Float>(actual: F, expected: F, ctx: &CheckCtx) -> Option<TestResult> {
237243
if !(ctx.base_name == BaseName::Fabs || ctx.base_name == BaseName::Copysign) {
@@ -259,6 +265,19 @@ fn maybe_check_nan_bits<F: Float>(actual: F, expected: F, ctx: &CheckCtx) -> Opt
259265
}
260266
}
261267

268+
#[cfg(f16_enabled)]
269+
impl MaybeOverride<(f16, f16)> for SpecialCase {
270+
fn check_float<F: Float>(
271+
input: (f16, f16),
272+
_actual: F,
273+
expected: F,
274+
_ulp: &mut u32,
275+
ctx: &CheckCtx,
276+
) -> Option<TestResult> {
277+
maybe_skip_binop_nan(input, expected, ctx)
278+
}
279+
}
280+
262281
impl MaybeOverride<(f32, f32)> for SpecialCase {
263282
fn check_float<F: Float>(
264283
input: (f32, f32),
@@ -283,6 +302,19 @@ impl MaybeOverride<(f64, f64)> for SpecialCase {
283302
}
284303
}
285304

305+
#[cfg(f128_enabled)]
306+
impl MaybeOverride<(f128, f128)> for SpecialCase {
307+
fn check_float<F: Float>(
308+
input: (f128, f128),
309+
_actual: F,
310+
expected: F,
311+
_ulp: &mut u32,
312+
ctx: &CheckCtx,
313+
) -> Option<TestResult> {
314+
maybe_skip_binop_nan(input, expected, ctx)
315+
}
316+
}
317+
286318
/// Musl propagates NaNs if one is provided as the input, but we return the other input.
287319
// F1 and F2 are always the same type, this is just to please generics
288320
fn maybe_skip_binop_nan<F1: Float, F2: Float>(

crates/libm-test/src/test_traits.rs

+6
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,12 @@ where
303303

304304
impl_float!(f32, f64);
305305

306+
#[cfg(f16_enabled)]
307+
impl_float!(f16);
308+
309+
#[cfg(f128_enabled)]
310+
impl_float!(f128);
311+
306312
/* trait implementations for compound types */
307313

308314
/// Implement `CheckOutput` for combinations of types.

crates/libm-test/tests/compare_built_musl.rs

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ where
4646

4747
libm_macros::for_each_function! {
4848
callback: musl_rand_tests,
49+
// Musl does not support `f16` and `f128` on all platforms.
50+
skip: [copysignf16, copysignf128, fabsf16, fabsf128],
4951
attributes: [
5052
#[cfg_attr(x86_no_sse, ignore)] // FIXME(correctness): wrong result on i586
5153
[exp10, exp10f, exp2, exp2f, rint]

crates/libm-test/tests/multiprecision.rs

+2
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ libm_macros::for_each_function! {
130130
atan2f,
131131
copysign,
132132
copysignf,
133+
copysignf16,
134+
copysignf128,
133135
fdim,
134136
fdimf,
135137
fma,

0 commit comments

Comments
 (0)