Implement powi_f2

This commit is contained in:
Matt Ickstadt 2016-09-30 17:15:44 -05:00 committed by Matt Ickstadt
parent 954e3b7095
commit 6622c49be6
6 changed files with 91 additions and 28 deletions

View File

@ -159,8 +159,8 @@ porting that particular intrinsic.
- [x] mulodi4.c - [x] mulodi4.c
- [x] mulosi4.c - [x] mulosi4.c
- [ ] mulsf3.c - [ ] mulsf3.c
- [ ] powidf2.c - [x] powidf2.c
- [ ] powisf2.c - [x] powisf2.c
- [ ] subdf3.c - [ ] subdf3.c
- [ ] subsf3.c - [ ] subsf3.c
- [ ] truncdfhf2.c - [ ] truncdfhf2.c

View File

@ -58,6 +58,8 @@ fn main() {
"udivmodsi4.c", "udivmodsi4.c",
"adddf3.c", "adddf3.c",
"addsf3.c", "addsf3.c",
"powidf2.c",
"powisf2.c",
]); ]);
for src in sources.files.iter() { for src in sources.files.iter() {

View File

@ -22,6 +22,8 @@ extern {
fn __umodsi3(); fn __umodsi3();
fn __addsf3(); fn __addsf3();
fn __adddf3(); fn __adddf3();
fn __powisf2();
fn __powidf2();
} }
macro_rules! declare { macro_rules! declare {
@ -53,6 +55,8 @@ declare!(___umoddi3, __umoddi3);
declare!(___umodsi3, __umodsi3); declare!(___umodsi3, __umodsi3);
declare!(___addsf3, __addsf3); declare!(___addsf3, __addsf3);
declare!(___adddf3, __adddf3); declare!(___adddf3, __adddf3);
declare!(___powisf2, __powisf2);
declare!(___powidf2, __powidf2);
#[lang = "eh_personality"] #[lang = "eh_personality"]
fn eh_personality() {} fn eh_personality() {}

View File

@ -186,35 +186,10 @@ add!(__adddf3: f64);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use core::{f32, f64}; use core::{f32, f64};
use core::fmt;
use float::Float; use float::{Float, FRepr};
use qc::{U32, U64}; use qc::{U32, U64};
// TODO: Move this to F32/F64 in qc.rs
#[derive(Copy, Clone)]
struct FRepr<F>(F);
impl<F: Float> PartialEq for FRepr<F> {
fn eq(&self, other: &FRepr<F>) -> 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<F: fmt::Debug> fmt::Debug for FRepr<F> {
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) // TODO: Add F32/F64 to qc so that they print the right values (at the very least)
check! { check! {
fn __addsf3(f: extern fn(f32, f32) -> f32, fn __addsf3(f: extern fn(f32, f32) -> f32,

View File

@ -1,6 +1,8 @@
use core::mem; use core::mem;
use core::fmt;
pub mod add; pub mod add;
pub mod pow;
/// Trait for some basic operations on floats /// Trait for some basic operations on floats
pub trait Float: Sized + Copy { pub trait Float: Sized + Copy {
@ -85,3 +87,30 @@ impl Float for f64 {
(1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) (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>(F);
#[cfg(test)]
impl<F: Float> PartialEq for FRepr<F> {
fn eq(&self, other: &FRepr<F>) -> 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<F: fmt::Debug> fmt::Debug for FRepr<F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}

53
src/float/pow.rs Normal file
View File

@ -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<FRepr<f32> > {
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<FRepr<f64> > {
let (a, b) = (f64::from_repr(a.0), b.0);
Some(FRepr(f(a, b)))
}
}
}