Files
rust/library/compiler-builtins/libm/test-generator/src/main.rs

742 lines
23 KiB
Rust
Raw Normal View History

2018-07-12 00:44:28 -05:00
// NOTE we intentionally avoid using the `quote` crate here because it doesn't work with the
// `x86_64-unknown-linux-musl` target.
// NOTE usually the only thing you need to do to test a new math function is to add it to one of the
// macro invocations found in the bottom of this file.
extern crate rand;
use std::error::Error;
use std::fmt::Write as _0;
use std::fs::{self, File};
use std::io::Write as _1;
use std::{i16, u16, u32, u64, u8};
2018-07-12 00:44:28 -05:00
use rand::{Rng, SeedableRng, XorShiftRng};
// Number of test cases to generate
const NTESTS: usize = 10_000;
// TODO tweak these functions to generate edge cases (zero, infinity, NaN) more often
2018-07-12 00:44:28 -05:00
fn f32(rng: &mut XorShiftRng) -> f32 {
let sign = if rng.gen_bool(0.5) { 1 << 31 } else { 0 };
let exponent = (rng.gen_range(0, u8::MAX) as u32) << 23;
let mantissa = rng.gen_range(0, u32::MAX) & ((1 << 23) - 1);
f32::from_bits(sign + exponent + mantissa)
}
fn f64(rng: &mut XorShiftRng) -> f64 {
let sign = if rng.gen_bool(0.5) { 1 << 63 } else { 0 };
let exponent = (rng.gen_range(0, u16::MAX) as u64 & ((1 << 11) - 1)) << 52;
let mantissa = rng.gen_range(0, u64::MAX) & ((1 << 52) - 1);
f64::from_bits(sign + exponent + mantissa)
}
2018-07-12 00:44:28 -05:00
// fn(f32) -> f32
macro_rules! f32_f32 {
($($intr:ident,)*) => {
2018-07-12 00:44:28 -05:00
fn f32_f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
// MUSL C implementation of the function to test
extern "C" {
$(fn $intr(_: f32) -> f32;)*
2018-07-12 00:44:28 -05:00
}
$(
let mut cases = String::new();
for _ in 0..NTESTS {
let inp = f32(rng);
let out = unsafe { $intr(inp) };
let inp = inp.to_bits();
let out = out.to_bits();
write!(cases, "({}, {})", inp, out).unwrap();
cases.push(',');
}
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
write!(f, "
2018-07-12 15:30:32 -05:00
#![deny(warnings)]
2018-07-12 00:44:28 -05:00
extern crate libm;
use std::panic;
2018-07-12 00:44:28 -05:00
#[test]
fn {0}() {{
const CASES: &[(u32, u32)] = &[
{1}
];
for case in CASES {{
let (inp, expected) = *case;
if let Ok(outf) =
panic::catch_unwind(|| libm::{0}(f32::from_bits(inp)))
{{
let outi = outf.to_bits();
if !((outf.is_nan() && f32::from_bits(expected).is_nan())
|| libm::_eqf(outi, expected))
{{
panic!(
\"input: {{}}, output: {{}}, expected: {{}}\",
inp, outi, expected,
);
}}
}} else {{
2018-07-12 00:44:28 -05:00
panic!(
\"input: {{}}, output: PANIC, expected: {{}}\",
inp, expected,
2018-07-12 00:44:28 -05:00
);
}}
}}
}}
",
stringify!($intr),
cases)?;
)*
2018-07-12 00:44:28 -05:00
Ok(())
}
}
}
// fn(f32, f32) -> f32
2018-07-12 00:44:28 -05:00
macro_rules! f32f32_f32 {
($($intr:ident,)*) => {
2018-07-12 00:44:28 -05:00
fn f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
extern "C" {
$(fn $intr(_: f32, _: f32) -> f32;)*
2018-07-12 00:44:28 -05:00
}
$(
let mut cases = String::new();
for _ in 0..NTESTS {
let i1 = f32(rng);
let i2 = f32(rng);
let out = unsafe { $intr(i1, i2) };
let i1 = i1.to_bits();
let i2 = i2.to_bits();
let out = out.to_bits();
write!(cases, "(({}, {}), {})", i1, i2, out).unwrap();
cases.push(',');
}
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
write!(f, "
2018-07-12 15:30:32 -05:00
#![deny(warnings)]
2018-07-12 00:44:28 -05:00
extern crate libm;
use std::panic;
2018-07-12 00:44:28 -05:00
#[test]
fn {0}() {{
const CASES: &[((u32, u32), u32)] = &[
{1}
];
for case in CASES {{
let ((i1, i2), expected) = *case;
if let Ok(outf) = panic::catch_unwind(|| {{
libm::{0}(f32::from_bits(i1), f32::from_bits(i2))
}}) {{
let outi = outf.to_bits();
if !((outf.is_nan() && f32::from_bits(expected).is_nan())
|| libm::_eqf(outi, expected))
{{
panic!(
\"input: {{:?}}, output: {{}}, expected: {{}}\",
(i1, i2),
outi,
expected,
);
}}
}} else {{
2018-07-12 00:44:28 -05:00
panic!(
\"input: {{:?}}, output: PANIC, expected: {{}}\",
2018-07-12 00:44:28 -05:00
(i1, i2),
expected,
);
}}
}}
}}
",
stringify!($intr),
cases)?;
)*
2018-07-12 00:44:28 -05:00
Ok(())
}
};
}
2018-07-12 15:30:32 -05:00
// fn(f32, f32, f32) -> f32
macro_rules! f32f32f32_f32 {
($($intr:ident,)*) => {
fn f32f32f32_f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
extern "C" {
$(fn $intr(_: f32, _: f32, _: f32) -> f32;)*
}
$(
let mut cases = String::new();
for _ in 0..NTESTS {
let i1 = f32(rng);
let i2 = f32(rng);
let i3 = f32(rng);
let out = unsafe { $intr(i1, i2, i3) };
let i1 = i1.to_bits();
let i2 = i2.to_bits();
let i3 = i3.to_bits();
let out = out.to_bits();
write!(cases, "(({}, {}, {}), {})", i1, i2, i3, out).unwrap();
cases.push(',');
}
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
write!(f, "
#![deny(warnings)]
extern crate libm;
use std::panic;
2018-07-12 15:30:32 -05:00
#[test]
fn {0}() {{
const CASES: &[((u32, u32, u32), u32)] = &[
{1}
];
for case in CASES {{
let ((i1, i2, i3), expected) = *case;
if let Ok(outf) = panic::catch_unwind(|| {{
libm::{0}(
f32::from_bits(i1),
f32::from_bits(i2),
f32::from_bits(i3),
)
}}) {{
let outi = outf.to_bits();
if !((outf.is_nan() && f32::from_bits(expected).is_nan())
|| libm::_eqf(outi, expected))
{{
panic!(
\"input: {{:?}}, output: {{}}, expected: {{}}\",
(i1, i2, i3),
outi,
expected,
);
}}
}} else {{
2018-07-12 15:30:32 -05:00
panic!(
\"input: {{:?}}, output: PANIC, expected: {{}}\",
2018-07-12 15:30:32 -05:00
(i1, i2, i3),
expected,
);
}}
}}
}}
",
stringify!($intr),
cases)?;
)*
Ok(())
}
};
}
// fn(f32, i32) -> f32
2018-07-12 00:44:28 -05:00
macro_rules! f32i32_f32 {
($($intr:ident,)*) => {
2018-07-12 00:44:28 -05:00
fn f32i32_f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
extern "C" {
$(fn $intr(_: f32, _: i32) -> f32;)*
2018-07-12 00:44:28 -05:00
}
$(
let mut cases = String::new();
for _ in 0..NTESTS {
let i1 = f32(rng);
let i2 = rng.gen_range(i16::MIN, i16::MAX);
let out = unsafe { $intr(i1, i2 as i32) };
let i1 = i1.to_bits();
let out = out.to_bits();
write!(cases, "(({}, {}), {})", i1, i2, out).unwrap();
cases.push(',');
}
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
write!(f, "
2018-07-12 15:30:32 -05:00
#![deny(warnings)]
2018-07-12 00:44:28 -05:00
extern crate libm;
use std::panic;
2018-07-12 00:44:28 -05:00
#[test]
fn {0}() {{
const CASES: &[((u32, i16), u32)] = &[
{1}
];
for case in CASES {{
let ((i1, i2), expected) = *case;
if let Ok(outf) = panic::catch_unwind(|| {{
libm::{0}(f32::from_bits(i1), i2 as i32)
}}) {{
let outi = outf.to_bits();
if !((outf.is_nan() && f32::from_bits(expected).is_nan())
|| libm::_eqf(outi, expected))
{{
panic!(
\"input: {{:?}}, output: {{}}, expected: {{}}\",
(i1, i2),
outi,
expected,
);
}}
}} else {{
2018-07-12 00:44:28 -05:00
panic!(
\"input: {{:?}}, output: PANIC, expected: {{}}\",
2018-07-12 00:44:28 -05:00
(i1, i2),
expected,
);
}}
}}
}}
",
stringify!($intr),
cases)?;
)*
Ok(())
}
};
}
// fn(f64) -> f64
macro_rules! f64_f64 {
($($intr:ident,)*) => {
fn f64_f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
// MUSL C implementation of the function to test
extern "C" {
$(fn $intr(_: f64) -> f64;)*
}
$(
let mut cases = String::new();
for _ in 0..NTESTS {
let inp = f64(rng);
let out = unsafe { $intr(inp) };
let inp = inp.to_bits();
let out = out.to_bits();
write!(cases, "({}, {})", inp, out).unwrap();
cases.push(',');
}
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
write!(f, "
2018-07-12 15:30:32 -05:00
#![deny(warnings)]
extern crate libm;
use std::panic;
#[test]
fn {0}() {{
const CASES: &[(u64, u64)] = &[
{1}
];
for case in CASES {{
let (inp, expected) = *case;
if let Ok(outf) = panic::catch_unwind(|| {{
libm::{0}(f64::from_bits(inp))
}}) {{
let outi = outf.to_bits();
if !((outf.is_nan() && f64::from_bits(expected).is_nan())
|| libm::_eq(outi, expected))
{{
panic!(
\"input: {{}}, output: {{}}, expected: {{}}\",
inp,
outi,
expected,
);
}}
}} else {{
panic!(
\"input: {{}}, output: PANIC, expected: {{}}\",
inp,
expected,
);
}}
}}
}}
",
stringify!($intr),
cases)?;
)*
Ok(())
}
}
}
// fn(f64, f64) -> f64
macro_rules! f64f64_f64 {
($($intr:ident,)*) => {
fn f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
extern "C" {
$(fn $intr(_: f64, _: f64) -> f64;)*
}
$(
let mut cases = String::new();
for _ in 0..NTESTS {
let i1 = f64(rng);
let i2 = f64(rng);
let out = unsafe { $intr(i1, i2) };
let i1 = i1.to_bits();
let i2 = i2.to_bits();
let out = out.to_bits();
write!(cases, "(({}, {}), {})", i1, i2, out).unwrap();
cases.push(',');
}
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
write!(f, "
2018-07-12 15:30:32 -05:00
#![deny(warnings)]
extern crate libm;
use std::panic;
#[test]
fn {0}() {{
const CASES: &[((u64, u64), u64)] = &[
{1}
];
for case in CASES {{
let ((i1, i2), expected) = *case;
if let Ok(outf) = panic::catch_unwind(|| {{
libm::{0}(f64::from_bits(i1), f64::from_bits(i2))
}}) {{
let outi = outf.to_bits();
if !((outf.is_nan() && f64::from_bits(expected).is_nan()) ||
libm::_eq(outi, expected)) {{
panic!(
\"input: {{:?}}, output: {{}}, expected: {{}}\",
(i1, i2),
outi,
expected,
);
}}
}} else {{
panic!(
\"input: {{:?}}, output: PANIC, expected: {{}}\",
(i1, i2),
expected,
);
}}
}}
}}
",
stringify!($intr),
cases)?;
)*
Ok(())
}
};
}
2018-07-12 15:30:32 -05:00
// fn(f64, f64, f64) -> f64
macro_rules! f64f64f64_f64 {
($($intr:ident,)*) => {
fn f64f64f64_f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
extern "C" {
$(fn $intr(_: f64, _: f64, _: f64) -> f64;)*
}
$(
let mut cases = String::new();
for _ in 0..NTESTS {
let i1 = f64(rng);
let i2 = f64(rng);
let i3 = f64(rng);
let out = unsafe { $intr(i1, i2, i3) };
let i1 = i1.to_bits();
let i2 = i2.to_bits();
let i3 = i3.to_bits();
let out = out.to_bits();
write!(cases, "(({}, {}, {}), {})", i1, i2, i3, out).unwrap();
cases.push(',');
}
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
write!(f, "
#![deny(warnings)]
extern crate libm;
use std::panic;
2018-07-12 15:30:32 -05:00
#[test]
fn {0}() {{
const CASES: &[((u64, u64, u64), u64)] = &[
{1}
];
for case in CASES {{
let ((i1, i2, i3), expected) = *case;
if let Ok(outf) = panic::catch_unwind(|| {{
libm::{0}(
f64::from_bits(i1),
f64::from_bits(i2),
f64::from_bits(i3),
)
}}) {{
let outi = outf.to_bits();
if !((outf.is_nan() && f64::from_bits(expected).is_nan())
|| libm::_eq(outi, expected))
{{
panic!(
\"input: {{:?}}, output: {{}}, expected: {{}}\",
(i1, i2, i3),
outi,
expected,
);
}}
}} else {{
2018-07-12 15:30:32 -05:00
panic!(
\"input: {{:?}}, output: PANIC, expected: {{}}\",
2018-07-12 15:30:32 -05:00
(i1, i2, i3),
expected,
);
}}
}}
}}
",
stringify!($intr),
cases)?;
)*
Ok(())
}
};
}
// fn(f64, i32) -> f64
macro_rules! f64i32_f64 {
($($intr:ident,)*) => {
fn f64i32_f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
extern "C" {
$(fn $intr(_: f64, _: i32) -> f64;)*
}
$(
let mut cases = String::new();
for _ in 0..NTESTS {
let i1 = f64(rng);
let i2 = rng.gen_range(i16::MIN, i16::MAX);
let out = unsafe { $intr(i1, i2 as i32) };
let i1 = i1.to_bits();
let out = out.to_bits();
write!(cases, "(({}, {}), {})", i1, i2, out).unwrap();
cases.push(',');
}
let mut f = File::create(concat!("tests/", stringify!($intr), ".rs"))?;
write!(f, "
2018-07-12 15:30:32 -05:00
#![deny(warnings)]
extern crate libm;
use std::panic;
#[test]
fn {0}() {{
const CASES: &[((u64, i16), u64)] = &[
{1}
];
for case in CASES {{
let ((i1, i2), expected) = *case;
if let Ok(outf) = panic::catch_unwind(|| {{
libm::{0}(f64::from_bits(i1), i2 as i32)
}}) {{
let outi = outf.to_bits();
if !((outf.is_nan() && f64::from_bits(expected).is_nan()) ||
libm::_eq(outi, expected)) {{
panic!(
\"input: {{:?}}, output: {{}}, expected: {{}}\",
(i1, i2),
outi,
expected,
);
}}
}} else {{
panic!(
\"input: {{:?}}, output: PANIC, expected: {{}}\",
(i1, i2),
expected,
);
}}
}}
}}
",
stringify!($intr),
cases)?;
)*
2018-07-12 00:44:28 -05:00
Ok(())
}
};
}
fn main() -> Result<(), Box<Error>> {
fs::remove_dir_all("tests").ok();
fs::create_dir("tests")?;
let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?;
f32_f32(&mut rng)?;
f32f32_f32(&mut rng)?;
2018-07-12 15:30:32 -05:00
f32f32f32_f32(&mut rng)?;
2018-07-12 00:44:28 -05:00
f32i32_f32(&mut rng)?;
f64_f64(&mut rng)?;
f64f64_f64(&mut rng)?;
2018-07-12 15:30:32 -05:00
f64f64f64_f64(&mut rng)?;
f64i32_f64(&mut rng)?;
2018-07-12 00:44:28 -05:00
Ok(())
}
/* Functions to test */
// With signature `fn(f32) -> f32`
f32_f32! {
2018-07-12 18:26:39 -05:00
// acosf,
floorf,
2018-07-13 16:04:30 -04:00
truncf,
2018-07-12 18:26:39 -05:00
// asinf,
// atanf,
// cbrtf,
ceilf,
2018-07-12 15:30:32 -05:00
// cosf,
2018-07-12 18:26:39 -05:00
// coshf,
2018-07-12 15:30:32 -05:00
// exp2f,
2018-07-13 11:16:43 -05:00
expf,
2018-07-12 18:26:39 -05:00
// fdimf,
2018-07-14 00:24:22 -04:00
log10f,
2018-07-14 01:28:00 -04:00
log1pf,
2018-07-13 23:40:57 -04:00
log2f,
2018-07-13 11:16:43 -05:00
logf,
2018-07-13 20:46:09 -05:00
roundf,
2018-07-12 15:30:32 -05:00
// sinf,
2018-07-12 18:26:39 -05:00
// sinhf,
// tanf,
// tanhf,
2018-07-12 00:44:28 -05:00
fabsf,
sqrtf,
}
// With signature `fn(f32, f32) -> f32`
f32f32_f32! {
2018-07-12 18:26:39 -05:00
// atan2f,
2018-07-13 17:41:54 -04:00
hypotf,
2018-07-12 03:07:28 -05:00
fmodf,
2018-07-12 00:44:28 -05:00
powf,
}
2018-07-12 15:30:32 -05:00
// With signature `fn(f32, f32, f32) -> f32`
f32f32f32_f32! {
// fmaf,
}
2018-07-12 00:44:28 -05:00
// With signature `fn(f32, i32) -> f32`
f32i32_f32! {
scalbnf,
}
// With signature `fn(f64) -> f64`
f64_f64! {
2018-07-12 15:30:32 -05:00
// acos,
// asin,
// atan,
// cbrt,
2018-07-12 18:26:39 -05:00
// ceil,
2018-07-12 15:30:32 -05:00
// cos,
// cosh,
// exp,
// exp2,
// expm1,
2018-07-13 13:36:59 -05:00
floor,
log,
2018-07-14 00:24:22 -04:00
log10,
2018-07-14 01:28:00 -04:00
log1p,
2018-07-13 23:40:57 -04:00
log2,
2018-07-13 00:40:05 +00:00
round,
2018-07-12 15:30:32 -05:00
// sin,
// sinh,
2018-07-13 18:31:01 -04:00
sqrt,
2018-07-12 15:30:32 -05:00
// tan,
// tanh,
2018-07-13 16:04:30 -04:00
trunc,
fabs,
}
// With signature `fn(f64, f64) -> f64`
f64f64_f64! {
2018-07-12 15:30:32 -05:00
// atan2,
2018-07-12 18:26:39 -05:00
// fdim,
// fmod,
2018-07-13 18:31:01 -04:00
hypot,
2018-07-12 15:30:32 -05:00
// pow,
}
// With signature `fn(f64, f64, f64) -> f64`
f64f64f64_f64! {
// fma,
}
// With signature `fn(f64, i32) -> f64`
f64i32_f64! {
2018-07-13 13:36:59 -05:00
scalbn,
}