Move crates to crates folder
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "cb"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,9 @@
|
||||
//! Fake compiler-builtins crate
|
||||
//!
|
||||
//! This is used to test that we can source import `libm` into the compiler-builtins crate.
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![no_std]
|
||||
|
||||
#[path = "../../../src/math/mod.rs"]
|
||||
mod libm;
|
||||
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "input-generator"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
|
||||
[dependencies]
|
||||
rand = "0.5.4"
|
||||
@@ -0,0 +1,189 @@
|
||||
extern crate rand;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::error::Error;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
|
||||
use rand::{RngCore, SeedableRng, XorShiftRng};
|
||||
|
||||
const NTESTS: usize = 10_000;
|
||||
|
||||
fn main() -> Result<(), Box<Error>> {
|
||||
let mut rng = XorShiftRng::from_rng(&mut rand::thread_rng())?;
|
||||
|
||||
fs::remove_dir_all("bin").ok();
|
||||
fs::create_dir_all("bin/input")?;
|
||||
fs::create_dir_all("bin/output")?;
|
||||
|
||||
f32(&mut rng)?;
|
||||
f32f32(&mut rng)?;
|
||||
f32f32f32(&mut rng)?;
|
||||
f32i16(&mut rng)?;
|
||||
f64(&mut rng)?;
|
||||
f64f64(&mut rng)?;
|
||||
f64f64f64(&mut rng)?;
|
||||
f64i16(&mut rng)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut set = BTreeSet::new();
|
||||
|
||||
while set.len() < NTESTS {
|
||||
let f = f32::from_bits(rng.next_u32());
|
||||
|
||||
if f.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
set.insert(f.to_bits());
|
||||
}
|
||||
|
||||
let mut f = File::create("bin/input/f32")?;
|
||||
for i in set {
|
||||
f.write_all(&i.to_le_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f32f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f32f32")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f32::from_bits(rng.next_u32());
|
||||
let x1 = f32::from_bits(rng.next_u32());
|
||||
|
||||
if x0.is_nan() || x1.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_le_bytes())?;
|
||||
f.write_all(&x1.to_bits().to_le_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f32i16(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f32i16")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f32::from_bits(rng.next_u32());
|
||||
let x1 = rng.next_u32() as i16;
|
||||
|
||||
if x0.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_le_bytes())?;
|
||||
f.write_all(&x1.to_le_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f32f32f32(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f32f32f32")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f32::from_bits(rng.next_u32());
|
||||
let x1 = f32::from_bits(rng.next_u32());
|
||||
let x2 = f32::from_bits(rng.next_u32());
|
||||
|
||||
if x0.is_nan() || x1.is_nan() || x2.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_le_bytes())?;
|
||||
f.write_all(&x1.to_bits().to_le_bytes())?;
|
||||
f.write_all(&x2.to_bits().to_le_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut set = BTreeSet::new();
|
||||
|
||||
while set.len() < NTESTS {
|
||||
let f = f64::from_bits(rng.next_u64());
|
||||
|
||||
if f.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
set.insert(f.to_bits());
|
||||
}
|
||||
|
||||
let mut f = File::create("bin/input/f64")?;
|
||||
for i in set {
|
||||
f.write_all(&i.to_le_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f64f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f64f64")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f64::from_bits(rng.next_u64());
|
||||
let x1 = f64::from_bits(rng.next_u64());
|
||||
|
||||
if x0.is_nan() || x1.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_le_bytes())?;
|
||||
f.write_all(&x1.to_bits().to_le_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f64f64f64(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f64f64f64")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f64::from_bits(rng.next_u64());
|
||||
let x1 = f64::from_bits(rng.next_u64());
|
||||
let x2 = f64::from_bits(rng.next_u64());
|
||||
|
||||
if x0.is_nan() || x1.is_nan() || x2.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_le_bytes())?;
|
||||
f.write_all(&x1.to_bits().to_le_bytes())?;
|
||||
f.write_all(&x2.to_bits().to_le_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn f64i16(rng: &mut XorShiftRng) -> Result<(), Box<Error>> {
|
||||
let mut f = File::create("bin/input/f64i16")?;
|
||||
let mut i = 0;
|
||||
while i < NTESTS {
|
||||
let x0 = f64::from_bits(rng.next_u64());
|
||||
let x1 = rng.next_u32() as i16;
|
||||
|
||||
if x0.is_nan() {
|
||||
continue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
f.write_all(&x0.to_bits().to_le_bytes())?;
|
||||
f.write_all(&x1.to_le_bytes())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "musl-generator"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.0.2"
|
||||
shared = { path = "../shared" }
|
||||
libm = { path = ".." }
|
||||
@@ -0,0 +1,191 @@
|
||||
macro_rules! f32 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f32) -> f32 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for x in shared::F32.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f32) -> f32;
|
||||
}
|
||||
|
||||
$fun(*x)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_le_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f32f32 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f32, f32) -> f32 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1) in shared::F32F32.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f32, _: f32) -> f32;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_le_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f32f32f32 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f32, f32, f32) -> f32 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1, x2) in shared::F32F32F32.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f32, _: f32, _: f32) -> f32;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1, *x2)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_le_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f32i32 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f32, i32) -> f32 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1) in shared::F32I32.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f32, _: i32) -> f32;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1 as i32)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_le_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f64 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f64) -> f64 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for x in shared::F64.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f64) -> f64;
|
||||
}
|
||||
|
||||
$fun(*x)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_le_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f64f64 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f64, f64) -> f64 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1) in shared::F64F64.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f64, _: f64) -> f64;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_le_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f64f64f64 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f64, f64, f64) -> f64 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1, x2) in shared::F64F64F64.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f64, _: f64, _: f64) -> f64;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1, *x2)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_le_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! f64i32 {
|
||||
($($fun:ident,)+) => {{
|
||||
$(
|
||||
// check type signature
|
||||
let _: fn(f64, i32) -> f64 = libm::$fun;
|
||||
let mut $fun = File::create(concat!("bin/output/musl.", stringify!($fun)))?;
|
||||
)+
|
||||
|
||||
for (x0, x1) in shared::F64I32.iter() {
|
||||
$(
|
||||
let y = unsafe {
|
||||
extern "C" {
|
||||
fn $fun(_: f64, _: i32) -> f64;
|
||||
}
|
||||
|
||||
$fun(*x0, *x1 as i32)
|
||||
};
|
||||
|
||||
$fun.write_all(&y.to_bits().to_le_bytes())?;
|
||||
)+
|
||||
}
|
||||
}};
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
extern crate libm;
|
||||
extern crate shared;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
fn main() -> Result<(), Box<Error>> {
|
||||
f32! {
|
||||
acosf,
|
||||
asinf,
|
||||
atanf,
|
||||
cbrtf,
|
||||
ceilf,
|
||||
cosf,
|
||||
coshf,
|
||||
exp2f,
|
||||
expf,
|
||||
expm1f,
|
||||
fabsf,
|
||||
floorf,
|
||||
log10f,
|
||||
log1pf,
|
||||
log2f,
|
||||
logf,
|
||||
roundf,
|
||||
sinf,
|
||||
sinhf,
|
||||
sqrtf,
|
||||
tanf,
|
||||
tanhf,
|
||||
truncf,
|
||||
}
|
||||
|
||||
f32f32! {
|
||||
atan2f,
|
||||
fdimf,
|
||||
fmodf,
|
||||
hypotf,
|
||||
powf,
|
||||
}
|
||||
|
||||
f32i32! {
|
||||
scalbnf,
|
||||
}
|
||||
|
||||
f32f32f32! {
|
||||
fmaf,
|
||||
}
|
||||
|
||||
f64! {
|
||||
acos,
|
||||
asin,
|
||||
atan,
|
||||
cbrt,
|
||||
ceil,
|
||||
cos,
|
||||
cosh,
|
||||
exp,
|
||||
exp2,
|
||||
expm1,
|
||||
fabs,
|
||||
floor,
|
||||
log,
|
||||
log10,
|
||||
log1p,
|
||||
log2,
|
||||
round,
|
||||
sin,
|
||||
sinh,
|
||||
sqrt,
|
||||
tan,
|
||||
tanh,
|
||||
trunc,
|
||||
}
|
||||
|
||||
f64f64! {
|
||||
atan2,
|
||||
fdim,
|
||||
fmod,
|
||||
hypot,
|
||||
pow,
|
||||
}
|
||||
|
||||
f64i32! {
|
||||
scalbn,
|
||||
}
|
||||
|
||||
f64f64f64! {
|
||||
fma,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "newlib-generator"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
|
||||
[dependencies]
|
||||
shared = { path = "../shared" }
|
||||
@@ -0,0 +1,245 @@
|
||||
macro_rules! f32 {
|
||||
($($fun:ident,)+) => {
|
||||
$(
|
||||
let fun = stringify!($fun);
|
||||
|
||||
fs::create_dir_all("math/src")?;
|
||||
|
||||
let main = format!("
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate qemu_arm_rt as rt;
|
||||
|
||||
use core::u32;
|
||||
|
||||
use rt::{{io, process}};
|
||||
|
||||
entry!(main);
|
||||
|
||||
fn main() {{
|
||||
run().unwrap_or_else(|e| {{
|
||||
eprintln!(\"error: {{}}\", e);
|
||||
process::exit(1);
|
||||
}})
|
||||
}}
|
||||
|
||||
fn run() -> Result<(), usize> {{
|
||||
#[link(name = \"m\")]
|
||||
extern \"C\" {{
|
||||
fn {0}(_: f32) -> f32;
|
||||
}}
|
||||
|
||||
let mut buf = [0; 4];
|
||||
while let Ok(()) = io::Stdin.read_exact(&mut buf) {{
|
||||
let x = f32::from_bits(u32::from_bytes(buf));
|
||||
let y = unsafe {{ {0}(x) }};
|
||||
|
||||
io::Stdout.write_all(&y.to_bits().to_bytes())?;
|
||||
}}
|
||||
|
||||
Ok(())
|
||||
}}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn __errno() -> *mut i32 {{
|
||||
static mut ERRNO: i32 = 0;
|
||||
unsafe {{ &mut ERRNO }}
|
||||
}}
|
||||
", fun);
|
||||
|
||||
File::create("math/src/main.rs")?.write_all(main.as_bytes())?;
|
||||
|
||||
assert!(
|
||||
Command::new("cross")
|
||||
.args(&["build", "--target", "thumbv7em-none-eabi", "--release"])
|
||||
.current_dir("math")
|
||||
.status()?
|
||||
.success()
|
||||
);
|
||||
|
||||
let mut qemu = Command::new("qemu-arm")
|
||||
.arg("math/target/thumbv7em-none-eabi/release/math")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?;
|
||||
|
||||
qemu.stdin.as_mut().take().unwrap().write_all(F32)?;
|
||||
|
||||
let output = qemu.wait_with_output()?;
|
||||
|
||||
File::create(concat!("bin/output/newlib.", stringify!($fun)))?
|
||||
.write_all(&output.stdout)?;
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! f32f32 {
|
||||
($($fun:ident,)+) => {
|
||||
$(
|
||||
let fun = stringify!($fun);
|
||||
|
||||
fs::create_dir_all("math/src")?;
|
||||
|
||||
let main = format!("
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate qemu_arm_rt as rt;
|
||||
|
||||
use core::u32;
|
||||
|
||||
use rt::{{io, process}};
|
||||
|
||||
entry!(main);
|
||||
|
||||
fn main() {{
|
||||
run().unwrap_or_else(|e| {{
|
||||
eprintln!(\"error: {{}}\", e);
|
||||
process::exit(1);
|
||||
}})
|
||||
}}
|
||||
|
||||
fn run() -> Result<(), usize> {{
|
||||
#[link(name = \"m\")]
|
||||
extern \"C\" {{
|
||||
fn {0}(_: f32, _: f32) -> f32;
|
||||
}}
|
||||
|
||||
let mut chunk = [0; 8];
|
||||
while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(&chunk[..4]);
|
||||
let x0 = f32::from_bits(u32::from_bytes(buf));
|
||||
|
||||
buf.copy_from_slice(&chunk[4..]);
|
||||
let x1 = f32::from_bits(u32::from_bytes(buf));
|
||||
|
||||
let y = unsafe {{ {0}(x0, x1) }};
|
||||
|
||||
io::Stdout.write_all(&y.to_bits().to_bytes())?;
|
||||
}}
|
||||
|
||||
Ok(())
|
||||
}}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn __errno() -> *mut i32 {{
|
||||
static mut ERRNO: i32 = 0;
|
||||
unsafe {{ &mut ERRNO }}
|
||||
}}
|
||||
", fun);
|
||||
|
||||
File::create("math/src/main.rs")?.write_all(main.as_bytes())?;
|
||||
|
||||
assert!(
|
||||
Command::new("cross")
|
||||
.args(&["build", "--target", "thumbv7em-none-eabi", "--release"])
|
||||
.current_dir("math")
|
||||
.status()?
|
||||
.success()
|
||||
);
|
||||
|
||||
let mut qemu = Command::new("qemu-arm")
|
||||
.arg("math/target/thumbv7em-none-eabi/release/math")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?;
|
||||
|
||||
qemu.stdin.as_mut().take().unwrap().write_all(F32)?;
|
||||
|
||||
let output = qemu.wait_with_output()?;
|
||||
|
||||
File::create(concat!("bin/output/newlib.", stringify!($fun)))?
|
||||
.write_all(&output.stdout)?;
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! f32f32f32 {
|
||||
($($fun:ident,)+) => {
|
||||
$(
|
||||
let fun = stringify!($fun);
|
||||
|
||||
fs::create_dir_all("math/src")?;
|
||||
|
||||
let main = format!("
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate qemu_arm_rt as rt;
|
||||
|
||||
use core::u32;
|
||||
|
||||
use rt::{{io, process}};
|
||||
|
||||
entry!(main);
|
||||
|
||||
fn main() {{
|
||||
run().unwrap_or_else(|e| {{
|
||||
eprintln!(\"error: {{}}\", e);
|
||||
process::exit(1);
|
||||
}})
|
||||
}}
|
||||
|
||||
fn run() -> Result<(), usize> {{
|
||||
#[link(name = \"m\")]
|
||||
extern \"C\" {{
|
||||
fn {0}(_: f32, _: f32, _: f32) -> f32;
|
||||
}}
|
||||
|
||||
let mut chunk = [0; 12];
|
||||
while let Ok(()) = io::Stdin.read_exact(&mut chunk) {{
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(&chunk[..4]);
|
||||
let x0 = f32::from_bits(u32::from_bytes(buf));
|
||||
|
||||
buf.copy_from_slice(&chunk[4..8]);
|
||||
let x1 = f32::from_bits(u32::from_bytes(buf));
|
||||
|
||||
buf.copy_from_slice(&chunk[8..]);
|
||||
let x2 = f32::from_bits(u32::from_bytes(buf));
|
||||
|
||||
let y = unsafe {{ {0}(x0, x1, x2) }};
|
||||
|
||||
io::Stdout.write_all(&y.to_bits().to_bytes())?;
|
||||
}}
|
||||
|
||||
Ok(())
|
||||
}}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn __errno() -> *mut i32 {{
|
||||
static mut ERRNO: i32 = 0;
|
||||
unsafe {{ &mut ERRNO }}
|
||||
}}
|
||||
", fun);
|
||||
|
||||
File::create("math/src/main.rs")?.write_all(main.as_bytes())?;
|
||||
|
||||
assert!(
|
||||
Command::new("cross")
|
||||
.args(&["build", "--target", "thumbv7em-none-eabi", "--release"])
|
||||
.current_dir("math")
|
||||
.status()?
|
||||
.success()
|
||||
);
|
||||
|
||||
let mut qemu = Command::new("qemu-arm")
|
||||
.arg("math/target/thumbv7em-none-eabi/release/math")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?;
|
||||
|
||||
qemu.stdin.as_mut().take().unwrap().write_all(F32)?;
|
||||
|
||||
let output = qemu.wait_with_output()?;
|
||||
|
||||
File::create(concat!("bin/output/newlib.", stringify!($fun)))?
|
||||
.write_all(&output.stdout)?;
|
||||
)+
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
extern crate shared;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
fn main() -> Result<(), Box<Error>> {
|
||||
const F32: &[u8] = include_bytes!("../../bin/input/f32");
|
||||
|
||||
f32! {
|
||||
asinf,
|
||||
cbrtf,
|
||||
cosf,
|
||||
exp2f,
|
||||
sinf,
|
||||
tanf,
|
||||
}
|
||||
|
||||
f32f32! {
|
||||
hypotf,
|
||||
}
|
||||
|
||||
f32f32f32! {
|
||||
fmaf,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "shared"
|
||||
version = "0.1.0"
|
||||
authors = ["Jorge Aparicio <jorge@japaric.io>"]
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.0.2"
|
||||
@@ -0,0 +1,469 @@
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref F32: Vec<f32> = {
|
||||
let bytes = include_bytes!("../../bin/input/f32");
|
||||
|
||||
bytes
|
||||
.chunks_exact(4)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(chunk);
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(buf)))
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F32F32: Vec<(f32, f32)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f32f32");
|
||||
|
||||
bytes
|
||||
.chunks_exact(8)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 4];
|
||||
let mut x1 = [0; 4];
|
||||
x0.copy_from_slice(&chunk[..4]);
|
||||
x1.copy_from_slice(&chunk[4..]);
|
||||
|
||||
(
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(x0))),
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(x1))),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F32F32F32: Vec<(f32, f32, f32)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f32f32f32");
|
||||
|
||||
bytes
|
||||
.chunks_exact(12)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 4];
|
||||
let mut x1 = [0; 4];
|
||||
let mut x2 = [0; 4];
|
||||
x0.copy_from_slice(&chunk[..4]);
|
||||
x1.copy_from_slice(&chunk[4..8]);
|
||||
x2.copy_from_slice(&chunk[8..]);
|
||||
|
||||
(
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(x0))),
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(x1))),
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(x2))),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F32I32: Vec<(f32, i32)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f32i16");
|
||||
|
||||
bytes
|
||||
.chunks_exact(6)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 4];
|
||||
let mut x1 = [0; 2];
|
||||
x0.copy_from_slice(&chunk[..4]);
|
||||
x1.copy_from_slice(&chunk[4..]);
|
||||
|
||||
(
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(x0))),
|
||||
i16::from_le(i16::from_le_bytes(x1)) as i32,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F64: Vec<f64> = {
|
||||
let bytes = include_bytes!("../../bin/input/f64");
|
||||
|
||||
bytes
|
||||
.chunks_exact(8)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 8];
|
||||
buf.copy_from_slice(chunk);
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(buf)))
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F64F64: Vec<(f64, f64)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f64f64");
|
||||
|
||||
bytes
|
||||
.chunks_exact(16)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 8];
|
||||
let mut x1 = [0; 8];
|
||||
x0.copy_from_slice(&chunk[..8]);
|
||||
x1.copy_from_slice(&chunk[8..]);
|
||||
|
||||
(
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(x0))),
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(x1))),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F64F64F64: Vec<(f64, f64, f64)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f64f64f64");
|
||||
|
||||
bytes
|
||||
.chunks_exact(24)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 8];
|
||||
let mut x1 = [0; 8];
|
||||
let mut x2 = [0; 8];
|
||||
x0.copy_from_slice(&chunk[..8]);
|
||||
x1.copy_from_slice(&chunk[8..16]);
|
||||
x2.copy_from_slice(&chunk[16..]);
|
||||
|
||||
(
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(x0))),
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(x1))),
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(x2))),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
pub static ref F64I32: Vec<(f64, i32)> = {
|
||||
let bytes = include_bytes!("../../bin/input/f64i16");
|
||||
|
||||
bytes
|
||||
.chunks_exact(10)
|
||||
.map(|chunk| {
|
||||
let mut x0 = [0; 8];
|
||||
let mut x1 = [0; 2];
|
||||
x0.copy_from_slice(&chunk[..8]);
|
||||
x1.copy_from_slice(&chunk[8..]);
|
||||
|
||||
(
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(x0))),
|
||||
i16::from_le(i16::from_le_bytes(x1)) as i32,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f32 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.chunks_exact(4)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(chunk);
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (input, expected) in $crate::F32.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) {
|
||||
if let Err(error) = libm::_eqf(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
input.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
input.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f32f32 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.chunks_exact(4)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(chunk);
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1), expected) in $crate::F32F32.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) {
|
||||
if let Err(error) = libm::_eqf(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f32f32f32 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.chunks_exact(4)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(chunk);
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1, i2), expected) in $crate::F32F32F32.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) {
|
||||
if let Err(error) = libm::_eqf(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
i2.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f32i32 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.chunks_exact(4)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 4];
|
||||
buf.copy_from_slice(chunk);
|
||||
f32::from_bits(u32::from_le(u32::from_le_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1), expected) in $crate::F32I32.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) {
|
||||
if let Err(error) = libm::_eqf(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1,
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1,
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f64 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.chunks_exact(8)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 8];
|
||||
buf.copy_from_slice(chunk);
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (input, expected) in shared::F64.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*input)) {
|
||||
if let Err(error) = libm::_eq(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: {:#x}, OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
input.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: {:#x}, OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
input.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f64f64 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.chunks_exact(8)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 8];
|
||||
buf.copy_from_slice(chunk);
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1), expected) in shared::F64F64.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) {
|
||||
if let Err(error) = libm::_eq(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f64f64f64 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.chunks_exact(8)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 8];
|
||||
buf.copy_from_slice(chunk);
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1, i2), expected) in shared::F64F64F64.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1, *i2)) {
|
||||
if let Err(error) = libm::_eq(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
i2.to_bits(),
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1.to_bits(),
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! f64i32 {
|
||||
($lib:expr, $($fun:ident),+) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $fun() {
|
||||
let expected = include_bytes!(concat!("../bin/output/", $lib, ".", stringify!($fun)))
|
||||
.chunks_exact(8)
|
||||
.map(|chunk| {
|
||||
let mut buf = [0; 8];
|
||||
buf.copy_from_slice(chunk);
|
||||
f64::from_bits(u64::from_le(u64::from_le_bytes(buf)))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((i0, i1), expected) in shared::F64I32.iter().zip(&expected) {
|
||||
if let Ok(output) = panic::catch_unwind(|| libm::$fun(*i0, *i1)) {
|
||||
if let Err(error) = libm::_eq(output, *expected) {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: {:#x}, EXPECTED: {:#x}, ERROR: {}",
|
||||
i0.to_bits(),
|
||||
i1,
|
||||
output.to_bits(),
|
||||
expected.to_bits(),
|
||||
error
|
||||
);
|
||||
}
|
||||
} else {
|
||||
panic!(
|
||||
"INPUT: ({:#x}, {:#x}), OUTPUT: PANIC!, EXPECTED: {:#x}",
|
||||
i0.to_bits(),
|
||||
i1,
|
||||
expected.to_bits()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user