From 6622c49be6ba8385fd306872141d0793d50f0d9b Mon Sep 17 00:00:00 2001 From: Matt Ickstadt Date: Fri, 30 Sep 2016 17:15:44 -0500 Subject: [PATCH] Implement powi_f2 --- README.md | 4 +- compiler-rt/compiler-rt-cdylib/build.rs | 2 + compiler-rt/compiler-rt-cdylib/src/lib.rs | 4 ++ src/float/add.rs | 27 +----------- src/float/mod.rs | 29 +++++++++++++ src/float/pow.rs | 53 +++++++++++++++++++++++ 6 files changed, 91 insertions(+), 28 deletions(-) create mode 100644 src/float/pow.rs diff --git a/README.md b/README.md index 28d8604..20b153d 100644 --- a/README.md +++ b/README.md @@ -159,8 +159,8 @@ porting that particular intrinsic. - [x] mulodi4.c - [x] mulosi4.c - [ ] mulsf3.c -- [ ] powidf2.c -- [ ] powisf2.c +- [x] powidf2.c +- [x] powisf2.c - [ ] subdf3.c - [ ] subsf3.c - [ ] truncdfhf2.c diff --git a/compiler-rt/compiler-rt-cdylib/build.rs b/compiler-rt/compiler-rt-cdylib/build.rs index b9b56a6..4eb7638 100644 --- a/compiler-rt/compiler-rt-cdylib/build.rs +++ b/compiler-rt/compiler-rt-cdylib/build.rs @@ -58,6 +58,8 @@ fn main() { "udivmodsi4.c", "adddf3.c", "addsf3.c", + "powidf2.c", + "powisf2.c", ]); for src in sources.files.iter() { diff --git a/compiler-rt/compiler-rt-cdylib/src/lib.rs b/compiler-rt/compiler-rt-cdylib/src/lib.rs index 5758483..81affa2 100644 --- a/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -22,6 +22,8 @@ extern { fn __umodsi3(); fn __addsf3(); fn __adddf3(); + fn __powisf2(); + fn __powidf2(); } macro_rules! declare { @@ -53,6 +55,8 @@ declare!(___umoddi3, __umoddi3); declare!(___umodsi3, __umodsi3); declare!(___addsf3, __addsf3); declare!(___adddf3, __adddf3); +declare!(___powisf2, __powisf2); +declare!(___powidf2, __powidf2); #[lang = "eh_personality"] fn eh_personality() {} diff --git a/src/float/add.rs b/src/float/add.rs index 63baf00..243c391 100644 --- a/src/float/add.rs +++ b/src/float/add.rs @@ -186,35 +186,10 @@ add!(__adddf3: f64); #[cfg(test)] mod tests { use core::{f32, f64}; - use core::fmt; - use float::Float; + use float::{Float, FRepr}; use qc::{U32, U64}; - // TODO: Move this to F32/F64 in qc.rs - #[derive(Copy, Clone)] - struct FRepr(F); - - impl PartialEq for FRepr { - fn eq(&self, other: &FRepr) -> bool { - // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't - // match the output of its gcc_s counterpart. Until we investigate further, we'll - // just avoid testing against gcc_s on those targets. Do note that our - // implementation matches the output of the FPU instruction on *hard* float targets - // and matches its gcc_s counterpart on *soft* float targets. - if cfg!(gnueabihf) { - return true - } - self.0.eq_repr(other.0) - } - } - - impl fmt::Debug for FRepr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } - } - // TODO: Add F32/F64 to qc so that they print the right values (at the very least) check! { fn __addsf3(f: extern fn(f32, f32) -> f32, diff --git a/src/float/mod.rs b/src/float/mod.rs index cee2b73..8bd574d 100644 --- a/src/float/mod.rs +++ b/src/float/mod.rs @@ -1,6 +1,8 @@ use core::mem; +use core::fmt; pub mod add; +pub mod pow; /// Trait for some basic operations on floats pub trait Float: Sized + Copy { @@ -85,3 +87,30 @@ impl Float for f64 { (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } } + +// TODO: Move this to F32/F64 in qc.rs +#[cfg(test)] +#[derive(Copy, Clone)] +pub struct FRepr(F); + +#[cfg(test)] +impl PartialEq for FRepr { + fn eq(&self, other: &FRepr) -> bool { + // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't + // match the output of its gcc_s counterpart. Until we investigate further, we'll + // just avoid testing against gcc_s on those targets. Do note that our + // implementation matches the output of the FPU instruction on *hard* float targets + // and matches its gcc_s counterpart on *soft* float targets. + if cfg!(gnueabihf) { + return true + } + self.0.eq_repr(other.0) + } +} + +#[cfg(test)] +impl fmt::Debug for FRepr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} diff --git a/src/float/pow.rs b/src/float/pow.rs new file mode 100644 index 0000000..14b3b9a --- /dev/null +++ b/src/float/pow.rs @@ -0,0 +1,53 @@ + +macro_rules! pow { + ($intrinsic:ident: $fty:ty, $ity:ty) => { + /// Returns `a` raised to the power `b` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $fty, b: $ity) -> $fty { + let (mut a, mut b) = (a, b); + let recip = b < 0; + let mut r: $fty = 1.0; + loop { + if (b & 1) != 0 { + r *= a; + } + b /= 2; + if b == 0 { + break; + } + a *= a; + } + + if recip { + 1.0 / r + } else { + r + } + } + } +} + +pow!(__powisf2: f32, i32); +pow!(__powidf2: f64, i32); + +#[cfg(test)] +mod tests { + use float::{Float, FRepr}; + use qc::{I32, U32, U64}; + + check! { + fn __powisf2(f: extern fn(f32, i32) -> f32, + a: U32, + b: I32) -> Option > { + let (a, b) = (f32::from_repr(a.0), b.0); + Some(FRepr(f(a, b))) + } + + fn __powidf2(f: extern fn(f64, i32) -> f64, + a: U64, + b: I32) -> Option > { + let (a, b) = (f64::from_repr(a.0), b.0); + Some(FRepr(f(a, b))) + } + } +}