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

Commit 8c06185

Browse files
committed
Add exhaustive testing of the 32-bit APIs
1 parent dd17777 commit 8c06185

File tree

4 files changed

+122
-11
lines changed

4 files changed

+122
-11
lines changed

crates/libm-test/build.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,23 @@ use std::env;
22

33
fn main() {
44
println!("cargo:rerun-if-changed=build.rs");
5-
5+
let target = env::var("TARGET").expect("TARGET was not set");
6+
let profile = env::var("PROFILE").unwrap_or(String::new());
7+
let opt_level: i32 = env::var("OPT_LEVEL").unwrap().parse().unwrap();
68
if !cfg!(feature = "checked") {
7-
let lvl = env::var("OPT_LEVEL").unwrap();
8-
if lvl != "0" {
9+
if opt_level != 0 {
910
println!("cargo:rustc-cfg=assert_no_panic");
1011
}
1112
}
13+
14+
if profile == "release" || opt_level > 0 {
15+
match target.as_str() {
16+
"x86_64-unknown-linux-gnu" |
17+
"x86_64-apple-darwin" |
18+
"x86_64-pc-windows-msvc" => {
19+
println!("cargo:rustc-cfg=exhaustive32");
20+
}
21+
_ => (),
22+
}
23+
}
1224
}

crates/libm-test/src/lib.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,20 @@ macro_rules! adjust_input {
101101
// to execute, so check if their higher bits are set and
102102
// zero them:
103103
let p = &mut $arg as *mut _ as *mut i32;
104-
unsafe { p.write(p.read() & 0xff_ffff) }
104+
unsafe { p.write(p.read() & 0xffff) }
105105
};
106106
}
107+
108+
#[macro_export]
109+
macro_rules! assert_approx_eq {
110+
($result:ident == $expected:ident,
111+
id: $id:ident, arg: $arg:ident, ulp: $ulps:expr) => {
112+
if !$crate::WithinUlps::within_ulps($result, $expected, $ulps) {
113+
let f = format!(
114+
"{}{:?} returns = {:?} != {:?} (expected)",
115+
stringify!($id), $arg, $result, $expected
116+
);
117+
panic!(f);
118+
}
119+
}
120+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//! Exhaustively test unary APIs taking 32-bit wide arguments.
2+
#![cfg(test)]
3+
#![cfg(exhaustive32)]
4+
use libm_test::{assert_approx_eq};
5+
6+
macro_rules! exhaustive32 {
7+
// Skip those parts of the API that are not
8+
// exposed by the system libm library:
9+
//
10+
// FIXME: maybe we can skip them as part of libm-analyze?
11+
(
12+
id: j0f;
13+
arg_tys: $($arg_tys:ty),*;
14+
arg_ids: $($arg_ids:ident),*;
15+
ret_ty: $ret_ty:ty;
16+
) => {};
17+
(
18+
id: j1f;
19+
arg_tys: $($arg_tys:ty),*;
20+
arg_ids: $($arg_ids:ident),*;
21+
ret_ty: $ret_ty:ty;
22+
) => {};
23+
(
24+
id: y0f;
25+
arg_tys: $($arg_tys:ty),*;
26+
arg_ids: $($arg_ids:ident),*;
27+
ret_ty: $ret_ty:ty;
28+
) => {};
29+
(
30+
id: y1f;
31+
arg_tys: $($arg_tys:ty),*;
32+
arg_ids: $($arg_ids:ident),*;
33+
ret_ty: $ret_ty:ty;
34+
) => {};
35+
(
36+
id: exp10f;
37+
arg_tys: $($arg_tys:ty),*;
38+
arg_ids: $($arg_ids:ident),*;
39+
ret_ty: $ret_ty:ty;
40+
) => {};
41+
// Too expensive:
42+
(
43+
id: jn;
44+
arg_tys: $($arg_tys:ty),*;
45+
arg_ids: $($arg_ids:ident),*;
46+
ret_ty: $ret_ty:ty;
47+
) => {};
48+
// match only unary functions taking f32:
49+
(
50+
id: $id:ident;
51+
arg_tys: f32;
52+
arg_ids: $arg_id:ident;
53+
ret_ty: $ret_ty:ty;
54+
) => {
55+
#[test]
56+
#[allow(unused)]
57+
fn $id() {
58+
extern "C" {
59+
// The system's libm function:
60+
fn $id($arg_id: f32) -> $ret_ty;
61+
}
62+
63+
for i in 0..u32::max_value() {
64+
let arg: f32 = unsafe { std::mem::transmute(i) };
65+
let result = libm::$id(arg);
66+
let expected = unsafe { $id(arg) };
67+
assert_approx_eq!(
68+
result == expected,
69+
id: $id, arg: arg, ulp: 4
70+
);
71+
}
72+
}
73+
};
74+
(
75+
id: $id:ident;
76+
arg_tys: $($arg_tys:ty),*;
77+
arg_ids: $($arg_ids:ident),*;
78+
ret_ty: $ret_ty:ty;
79+
) => {};
80+
}
81+
82+
libm_analyze::for_each_api!(exhaustive32);

crates/libm-test/tests/system_libm.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#![cfg(test)]
33
#![cfg(feature = "system_libm")]
44

5-
use libm_test::{adjust_input, Call, WithinUlps};
5+
use libm_test::{adjust_input, Call, assert_approx_eq};
66

77
// Number of tests to generate for each function
88
const NTESTS: usize = 500;
@@ -77,7 +77,9 @@ macro_rules! system_libm {
7777
let mut rng = rand::thread_rng();
7878
for _ in 0..NTESTS {
7979
// Type of the system libm fn:
80-
type FnTy = unsafe extern "C" fn ($($arg_ids: $arg_tys),*) -> $ret_ty;
80+
type FnTy
81+
= unsafe extern "C" fn ($($arg_ids: $arg_tys),*) -> $ret_ty;
82+
8183
// FIXME: extern "C" wrapper over our libm functions
8284
// Shouldn't be needed once they are all extern "C"
8385
extern "C" fn libm_fn($($arg_ids: $arg_tys),*) -> $ret_ty {
@@ -89,18 +91,19 @@ macro_rules! system_libm {
8991
}
9092

9193
// Generate a tuple of arguments containing random values:
92-
let mut args: ( $($arg_tys,)+ ) = ( $(<$arg_tys as Rand>::gen(&mut rng),)+ );
94+
let mut args: ( $($arg_tys,)+ )
95+
= ( $(<$arg_tys as Rand>::gen(&mut rng),)+ );
9396

9497
// Some APIs need their inputs to be "adjusted" (see macro):
9598
// correct_input!(fn: $id, input: args);
9699
adjust_input!(fn: $id, input: args);
97100

98101
let result = args.call(libm_fn as FnTy);
99102
let expected = args.call($id as FnTy);
100-
if !result.within_ulps(expected, ULP_TOL) {
101-
eprintln!("{}{:?} returns = {:?} != {:?} (expected)", stringify!($id), args, result, expected);
102-
panic!();
103-
}
103+
assert_approx_eq!(
104+
result == expected,
105+
id: $id, arg: args, ulp: ULP_TOL
106+
);
104107
}
105108
}
106109
}

0 commit comments

Comments
 (0)