Преглед изворни кода

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?~~
homunkulus пре 8 година
родитељ
комит
8652c66bdc
7 измењених фајлова са 91 додато и 30 уклоњено
  1. 2 2
      README.md
  2. 0 2
      build.rs
  3. 2 0
      compiler-rt/compiler-rt-cdylib/build.rs
  4. 4 0
      compiler-rt/compiler-rt-cdylib/src/lib.rs
  5. 1 26
      src/float/add.rs
  6. 29 0
      src/float/mod.rs
  7. 53 0
      src/float/pow.rs

+ 2 - 2
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

+ 0 - 2
build.rs

@@ -164,8 +164,6 @@ fn main() {
                          "paritysi2.c",
                          "popcountdi2.c",
                          "popcountsi2.c",
-                         "powidf2.c",
-                         "powisf2.c",
                          "powixf2.c",
                          "subdf3.c",
                          "subsf3.c",

+ 2 - 0
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() {

+ 4 - 0
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() {}

+ 1 - 26
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>(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)
     check! {
         fn __addsf3(f: extern fn(f32, f32) -> f32,

+ 29 - 0
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>(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 - 0
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<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)))
+        }
+    }
+}