Browse Source

Merge pull request #225 from paoloteti/armhf

Add support for mul[s/d]f3vfp and div[s/d]f3vfp
Alex Crichton 7 năm trước cách đây
mục cha
commit
93977e65a0
8 tập tin đã thay đổi với 414 bổ sung8 xóa
  1. 4 4
      README.md
  2. 359 4
      build.rs
  3. 9 0
      src/float/div.rs
  4. 10 0
      src/float/mul.rs
  5. 8 0
      tests/divdf3vfp.rs
  6. 8 0
      tests/divsf3vfp.rs
  7. 8 0
      tests/muldf3vfp.rs
  8. 8 0
      tests/mulsf3vfp.rs

+ 4 - 4
README.md

@@ -96,9 +96,9 @@ features = ["c"]
 - [x] arm/aeabi_memset.S
 - [x] arm/aeabi_uidivmod.S
 - [x] arm/aeabi_uldivmod.S
-- [ ] arm/divdf3vfp.S
+- [x] arm/divdf3vfp.S
 - [ ] arm/divmodsi4.S (generic version is done)
-- [ ] arm/divsf3vfp.S
+- [x] arm/divsf3vfp.S
 - [ ] arm/divsi3.S (generic version is done)
 - [ ] arm/eqdf2vfp.S
 - [ ] arm/eqsf2vfp.S
@@ -120,8 +120,8 @@ features = ["c"]
 - [ ] arm/ltdf2vfp.S
 - [ ] arm/ltsf2vfp.S
 - [ ] arm/modsi3.S (generic version is done)
-- [ ] arm/muldf3vfp.S
-- [ ] arm/mulsf3vfp.S
+- [x] arm/muldf3vfp.S
+- [x] arm/mulsf3vfp.S
 - [ ] arm/nedf2vfp.S
 - [ ] arm/negdf2vfp.S
 - [ ] arm/negsf2vfp.S

+ 359 - 4
build.rs

@@ -130,10 +130,14 @@ mod tests {
             // float/mul.rs
             Mulsf3,
             Muldf3,
+            Mulsf3vfp,
+            Muldf3vfp,
 
             // float/div.rs
             Divsf3,
             Divdf3,
+            Divsf3vfp,
+            Divdf3vfp,
 
             // int/addsub.rs
             AddU128,
@@ -4203,6 +4207,181 @@ fn muldf3() {
         }
     }
 
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Mulsf3vfp {
+        a: u32,  // f32
+        b: u32,  // f32
+        c: u32,  // f32
+    }
+
+    impl TestCase for Mulsf3vfp {
+        fn name() -> &'static str {
+            "mulsf3vfp"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_large_f32(rng);
+            let b = gen_large_f32(rng);
+            let c = a * b;
+            // TODO accept NaNs. We don't do that right now because we can't check
+            // for NaN-ness on the thumb targets (due to missing intrinsics)
+            if a.is_nan() || b.is_nan() || c.is_nan() {
+                return None;
+            }
+
+            Some(
+                Mulsf3vfp {
+                    a: to_u32(a),
+                    b: to_u32(b),
+                    c: to_u32(c),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::mul::__mulsf3vfp;
+
+fn mk_f32(x: u32) -> f32 {
+    unsafe { mem::transmute(x) }
+}
+
+fn to_u32(x: f32) -> u32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32, u32), u32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn mulsf3vfp() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __mulsf3vfp(mk_f32(a), mk_f32(b));
+        assert_eq!(((a, b), c), ((a, b), to_u32(c_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Muldf3vfp {
+        a: u64,  // f64
+        b: u64,  // f64
+        c: u64,  // f64
+    }
+
+    impl TestCase for Muldf3vfp {
+        fn name() -> &'static str {
+            "muldf3vfp"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_large_f64(rng);
+            let b = gen_large_f64(rng);
+            let c = a * b;
+            // TODO accept NaNs. We don't do that right now because we can't check
+            // for NaN-ness on the thumb targets (due to missing intrinsics)
+            if a.is_nan() || b.is_nan() || c.is_nan() {
+                return None;
+            }
+
+            Some(
+                Muldf3vfp {
+                    a: to_u64(a),
+                    b: to_u64(b),
+                    c: to_u64(c),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::mul::__muldf3vfp;
+
+fn mk_f64(x: u64) -> f64 {
+    unsafe { mem::transmute(x) }
+}
+
+fn to_u64(x: f64) -> u64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u64, u64), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn muldf3vfp() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __muldf3vfp(mk_f64(a), mk_f64(b));
+        assert_eq!(((a, b), c), ((a, b), to_u64(c_)));
+    }
+}
+"
+        }
+    }
+
+
     #[derive(Eq, Hash, PartialEq)]
     pub struct Divsf3 {
         a: u32,  // f32
@@ -4384,6 +4563,186 @@ fn divdf3() {
         }
     }
 
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Divsf3vfp {
+        a: u32,  // f32
+        b: u32,  // f32
+        c: u32,  // f32
+    }
+
+    impl TestCase for Divsf3vfp {
+        fn name() -> &'static str {
+            "divsf3vfp"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_large_f32(rng);
+            let b = gen_large_f32(rng);
+            if b == 0.0 {
+                return None;
+            }
+            let c = a / b;
+            // TODO accept NaNs. We don't do that right now because we can't check
+            // for NaN-ness on the thumb targets (due to missing intrinsics)
+            if a.is_nan() || b.is_nan() || c.is_nan()|| c.abs() <= unsafe { mem::transmute(16777215u32) } {
+                return None;
+            }
+
+            Some(
+                Divsf3vfp {
+                    a: to_u32(a),
+                    b: to_u32(b),
+                    c: to_u32(c),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::div::__divsf3vfp;
+
+fn mk_f32(x: u32) -> f32 {
+    unsafe { mem::transmute(x) }
+}
+
+fn to_u32(x: f32) -> u32 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u32, u32), u32)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn divsf3vfp() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __divsf3vfp(mk_f32(a), mk_f32(b));
+        assert_eq!(((a, b), c), ((a, b), to_u32(c_)));
+    }
+}
+"
+        }
+    }
+
+    #[derive(Eq, Hash, PartialEq)]
+    pub struct Divdf3vfp {
+        a: u64,  // f64
+        b: u64,  // f64
+        c: u64,  // f64
+    }
+
+    impl TestCase for Divdf3vfp {
+        fn name() -> &'static str {
+            "divdf3vfp"
+        }
+
+        fn generate<R>(rng: &mut R) -> Option<Self>
+        where
+            R: Rng,
+            Self: Sized,
+        {
+            let a = gen_large_f64(rng);
+            let b = gen_large_f64(rng);
+            if b == 0.0 {
+                return None;
+            }
+            let c = a / b;
+            // TODO accept NaNs. We don't do that right now because we can't check
+            // for NaN-ness on the thumb targets (due to missing intrinsics)
+            if a.is_nan() || b.is_nan() || c.is_nan()
+                || c.abs() <= unsafe { mem::transmute(4503599627370495u64) } {
+                return None;
+            }
+
+            Some(
+                Divdf3vfp {
+                    a: to_u64(a),
+                    b: to_u64(b),
+                    c: to_u64(c),
+                },
+            )
+        }
+
+        fn to_string(&self, buffer: &mut String) {
+            writeln!(
+                buffer,
+                "(({a}, {b}), {c}),",
+                a = self.a,
+                b = self.b,
+                c = self.c
+            )
+                    .unwrap();
+        }
+
+        fn prologue() -> &'static str {
+            r#"
+#[cfg(all(target_arch = "arm",
+          not(any(target_env = "gnu", target_env = "musl")),
+          target_os = "linux",
+          test))]
+use core::mem;
+#[cfg(not(all(target_arch = "arm",
+              not(any(target_env = "gnu", target_env = "musl")),
+              target_os = "linux",
+              test)))]
+use std::mem;
+use compiler_builtins::float::div::__divdf3vfp;
+
+fn mk_f64(x: u64) -> f64 {
+    unsafe { mem::transmute(x) }
+}
+
+fn to_u64(x: f64) -> u64 {
+    unsafe { mem::transmute(x) }
+}
+
+static TEST_CASES: &[((u64, u64), u64)] = &[
+"#
+        }
+
+        fn epilogue() -> &'static str {
+            "
+];
+
+#[test]
+fn divdf3vfp() {
+    for &((a, b), c) in TEST_CASES {
+        let c_ = __divdf3vfp(mk_f64(a), mk_f64(b));
+        assert_eq!(((a, b), c), ((a, b), to_u64(c_)));
+    }
+}
+"
+        }
+    }
 
     #[derive(Eq, Hash, PartialEq)]
     pub struct Udivdi3 {
@@ -5511,8 +5870,6 @@ mod c {
                     &[
                         "arm/adddf3vfp.S",
                         "arm/addsf3vfp.S",
-                        "arm/divdf3vfp.S",
-                        "arm/divsf3vfp.S",
                         "arm/eqdf2vfp.S",
                         "arm/eqsf2vfp.S",
                         "arm/extendsfdf2vfp.S",
@@ -5532,8 +5889,6 @@ mod c {
                         "arm/lesf2vfp.S",
                         "arm/ltdf2vfp.S",
                         "arm/ltsf2vfp.S",
-                        "arm/muldf3vfp.S",
-                        "arm/mulsf3vfp.S",
                         "arm/nedf2vfp.S",
                         "arm/nesf2vfp.S",
                         "arm/restore_vfp_d8_d15_regs.S",

+ 9 - 0
src/float/div.rs

@@ -454,4 +454,13 @@ intrinsics! {
         div64(a, b)
     }
 
+    #[cfg(target_arch = "arm")]
+    pub extern "C" fn __divsf3vfp(a: f32, b: f32) -> f32 {
+        a / b
+    }
+
+    #[cfg(target_arch = "arm")]
+    pub extern "C" fn __divdf3vfp(a: f64, b: f64) -> f64 {
+        a / b
+    }
 }

+ 10 - 0
src/float/mul.rs

@@ -188,4 +188,14 @@ intrinsics! {
     pub extern "C" fn __muldf3(a: f64, b: f64) -> f64 {
         mul(a, b)
     }
+
+    #[cfg(target_arch = "arm")]
+    pub extern "C" fn __mulsf3vfp(a: f32, b: f32) -> f32 {
+        a * b
+    }
+
+    #[cfg(target_arch = "arm")]
+    pub extern "C" fn __muldf3vfp(a: f64, b: f64) -> f64 {
+        a * b
+    }
 }

+ 8 - 0
tests/divdf3vfp.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
+                 target_os = "linux", test),
+           no_std)]
+
+#[cfg(target_arch = "arm")]
+include!(concat!(env!("OUT_DIR"), "/divdf3vfp.rs"));

+ 8 - 0
tests/divsf3vfp.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
+                 target_os = "linux", test),
+           no_std)]
+
+#[cfg(target_arch = "arm")]
+include!(concat!(env!("OUT_DIR"), "/divsf3vfp.rs"));

+ 8 - 0
tests/muldf3vfp.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
+                 target_os = "linux", test),
+           no_std)]
+
+#[cfg(target_arch = "arm")]
+include!(concat!(env!("OUT_DIR"), "/muldf3vfp.rs"));

+ 8 - 0
tests/mulsf3vfp.rs

@@ -0,0 +1,8 @@
+#![feature(compiler_builtins_lib)]
+#![feature(i128_type)]
+#![cfg_attr(all(target_arch = "arm", not(any(target_env = "gnu", target_env = "musl")),
+                 target_os = "linux", test),
+           no_std)]
+
+#[cfg(target_arch = "arm")]
+include!(concat!(env!("OUT_DIR"), "/mulsf3vfp.rs"));