Auto merge of #82 - mattico:add_pow, r=japaric
Add pow functions I still want to clean up the commit history, but otherwise I think this is complete. ~~Can you run the tests on it?~~
This commit is contained in:
commit
8652c66bdc
|
@ -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
|
||||||
|
|
2
build.rs
2
build.rs
|
@ -164,8 +164,6 @@ fn main() {
|
||||||
"paritysi2.c",
|
"paritysi2.c",
|
||||||
"popcountdi2.c",
|
"popcountdi2.c",
|
||||||
"popcountsi2.c",
|
"popcountsi2.c",
|
||||||
"powidf2.c",
|
|
||||||
"powisf2.c",
|
|
||||||
"powixf2.c",
|
"powixf2.c",
|
||||||
"subdf3.c",
|
"subdf3.c",
|
||||||
"subsf3.c",
|
"subsf3.c",
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue