Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit 7419a5e

Browse files
authored
Merge pull request #406 from tgross35/musl-domain-tests
Add domain and edge case tests to musl
2 parents bc6b854 + 0164e93 commit 7419a5e

File tree

4 files changed

+123
-2
lines changed

4 files changed

+123
-2
lines changed

crates/libm-test/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ use std::time::SystemTime;
2323
pub use f8_impl::f8;
2424
pub use libm::support::{Float, Int, IntTy, MinInt};
2525
pub use num::{FloatExt, logspace};
26-
pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty};
26+
pub use op::{
27+
BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustFn, OpRustRet, Ty,
28+
};
2729
pub use precision::{MaybeOverride, SpecialCase, default_ulp};
2830
use run_cfg::EXTENSIVE_MAX_ITERATIONS;
2931
pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test};

crates/libm-test/src/op.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ pub type OpFTy<Op> = <Op as MathOp>::FTy;
9696
pub type OpITy<Op> = <<Op as MathOp>::FTy as Float>::Int;
9797
/// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types).
9898
pub type OpCFn<Op> = <Op as MathOp>::CFn;
99+
/// Access the associated `CRet` type from an op (helper to avoid ambiguous associated types).
100+
pub type OpCRet<Op> = <Op as MathOp>::CRet;
99101
/// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types).
100102
pub type OpRustFn<Op> = <Op as MathOp>::RustFn;
101103
/// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types).

crates/libm-test/src/precision.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,11 @@ pub fn default_ulp(ctx: &CheckCtx) -> u32 {
106106
match ctx.fn_ident {
107107
Id::Asinh => ulp = 3,
108108
Id::Asinhf => ulp = 3,
109+
Id::Exp10 | Id::Exp10f => ulp = 1_000_000,
110+
Id::Exp2 | Id::Exp2f => ulp = 10_000_000,
111+
Id::Fmaf => ulp = 1,
109112
Id::Log1p | Id::Log1pf => ulp = 2,
113+
Id::Rint => ulp = 100_000,
110114
Id::Round => ulp = 1,
111115
Id::Tan => ulp = 2,
112116
_ => (),
@@ -270,6 +274,24 @@ impl MaybeOverride<(f64,)> for SpecialCase {
270274
return XFAIL;
271275
}
272276

277+
if (ctx.fn_ident == Identifier::Ceil || ctx.fn_ident == Identifier::Floor)
278+
&& cfg!(x86_no_sse)
279+
&& expected.eq_repr(F::NEG_ZERO)
280+
&& actual.eq_repr(F::ZERO)
281+
{
282+
// FIXME: the x87 implementations do not keep the distinction between -0.0 and 0.0.
283+
// See https://github.com/rust-lang/libm/pull/404#issuecomment-2572399955
284+
return XFAIL;
285+
}
286+
287+
if (ctx.fn_ident == Identifier::Exp10 || ctx.fn_ident == Identifier::Exp2)
288+
&& cfg!(x86_no_sse)
289+
{
290+
// FIXME: i586 has very imprecise results with ULP > u32::MAX for these
291+
// operations so we can't reasonably provide a limit.
292+
return XFAIL;
293+
}
294+
273295
maybe_check_nan_bits(actual, expected, ctx)
274296
}
275297

crates/libm-test/tests/compare_built_musl.rs

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
// There are some targets we can't build musl for
1010
#![cfg(feature = "build-musl")]
1111

12-
use libm_test::gen::random;
12+
use libm_test::domain::HasDomain;
1313
use libm_test::gen::random::RandomInput;
14+
use libm_test::gen::{domain_logspace, edge_cases, random};
1415
use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, TupleCall};
1516

1617
macro_rules! musl_rand_tests {
@@ -53,3 +54,97 @@ libm_macros::for_each_function! {
5354
[exp10, exp10f, exp2, exp2f, rint]
5455
],
5556
}
57+
58+
/// Test against musl with generators from a domain.
59+
macro_rules! musl_domain_tests {
60+
(
61+
fn_name: $fn_name:ident,
62+
attrs: [$($attr:meta),*],
63+
) => {
64+
paste::paste! {
65+
#[test]
66+
$(#[$attr])*
67+
fn [< musl_edge_case_ $fn_name >]() {
68+
type Op = libm_test::op::$fn_name::Routine;
69+
domain_test_runner::<Op, _>(
70+
edge_cases::get_test_cases::<Op, _>,
71+
musl_math_sys::$fn_name,
72+
);
73+
}
74+
75+
#[test]
76+
$(#[$attr])*
77+
fn [< musl_logspace_ $fn_name >]() {
78+
type Op = libm_test::op::$fn_name::Routine;
79+
domain_test_runner::<Op, _>(
80+
domain_logspace::get_test_cases::<Op>,
81+
musl_math_sys::$fn_name,
82+
);
83+
}
84+
}
85+
};
86+
}
87+
88+
/// Test a single routine against domaine-aware inputs.
89+
fn domain_test_runner<Op, I>(gen: impl FnOnce(&CheckCtx) -> I, musl_fn: Op::CFn)
90+
where
91+
Op: MathOp,
92+
Op: HasDomain<Op::FTy>,
93+
I: Iterator<Item = Op::RustArgs>,
94+
{
95+
let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl);
96+
let cases = gen(&ctx);
97+
98+
for input in cases {
99+
let musl_res = input.call(musl_fn);
100+
let crate_res = input.call(Op::ROUTINE);
101+
102+
crate_res.validate(musl_res, input, &ctx).unwrap();
103+
}
104+
}
105+
106+
libm_macros::for_each_function! {
107+
callback: musl_domain_tests,
108+
attributes: [],
109+
skip: [
110+
// Functions with multiple inputs
111+
atan2,
112+
atan2f,
113+
copysign,
114+
copysignf,
115+
copysignf16,
116+
copysignf128,
117+
fdim,
118+
fdimf,
119+
fma,
120+
fmaf,
121+
fmax,
122+
fmaxf,
123+
fmin,
124+
fminf,
125+
fmod,
126+
fmodf,
127+
hypot,
128+
hypotf,
129+
jn,
130+
jnf,
131+
ldexp,
132+
ldexpf,
133+
nextafter,
134+
nextafterf,
135+
pow,
136+
powf,
137+
remainder,
138+
remainderf,
139+
remquo,
140+
remquof,
141+
scalbn,
142+
scalbnf,
143+
yn,
144+
ynf,
145+
146+
// Not provided by musl
147+
fabsf16,
148+
fabsf128,
149+
],
150+
}

0 commit comments

Comments
 (0)