Browse Source

Implement comparesf2/comparedf2 intrinsics.

whitequark 7 years ago
parent
commit
f5d86476a8
3 changed files with 169 additions and 2 deletions
  1. 2 2
      README.md
  2. 166 0
      src/float/cmp.rs
  3. 1 0
      src/float/mod.rs

+ 2 - 2
README.md

@@ -133,8 +133,8 @@ features = ["c"]
 - [ ] arm/unordsf2vfp.S
 - [ ] arm/unordsf2vfp.S
 - [x] ashldi3.c
 - [x] ashldi3.c
 - [x] ashrdi3.c
 - [x] ashrdi3.c
-- [ ] comparedf2.c
-- [ ] comparesf2.c
+- [x] comparedf2.c
+- [x] comparesf2.c
 - [x] divdf3.c
 - [x] divdf3.c
 - [x] divdi3.c
 - [x] divdi3.c
 - [x] divmoddi4.c
 - [x] divmoddi4.c

+ 166 - 0
src/float/cmp.rs

@@ -0,0 +1,166 @@
+use int::{Int, CastInto};
+use float::Float;
+
+#[derive(Clone, Copy)]
+enum Result {
+    Less,
+    Equal,
+    Greater,
+    Unordered
+}
+
+impl Result {
+    fn to_le_abi(self) -> i32 {
+        match self {
+            Result::Less      => -1,
+            Result::Equal     => 0,
+            Result::Greater   => 1,
+            Result::Unordered => 1
+        }
+    }
+
+    fn to_ge_abi(self) -> i32 {
+        match self {
+            Result::Less      => -1,
+            Result::Equal     => 0,
+            Result::Greater   => 1,
+            Result::Unordered => -1
+        }
+    }
+}
+
+fn cmp<F: Float>(a: F, b: F) -> Result where
+    u32: CastInto<F::Int>,
+    F::Int: CastInto<u32>,
+    i32: CastInto<F::Int>,
+    F::Int: CastInto<i32>,
+{
+    let one = F::Int::ONE;
+    let zero = F::Int::ZERO;
+
+    let sign_bit =      F::SIGN_MASK as F::Int;
+    let abs_mask =      sign_bit - one;
+    let exponent_mask = F::EXPONENT_MASK;
+    let inf_rep =       exponent_mask;
+
+    let a_rep = a.repr();
+    let b_rep = b.repr();
+    let a_abs = a_rep & abs_mask;
+    let b_abs = b_rep & abs_mask;
+
+    // If either a or b is NaN, they are unordered.
+    if a_abs > inf_rep || b_abs > inf_rep {
+        return Result::Unordered
+    }
+
+    // If a and b are both zeros, they are equal.
+    if a_abs | b_abs == zero {
+        return Result::Equal
+    }
+
+    // If at least one of a and b is positive, we get the same result comparing
+    // a and b as signed integers as we would with a fp_ting-point compare.
+    if a_rep & b_rep >= zero {
+        if a_rep < b_rep {
+            return Result::Less
+        } else if a_rep == b_rep {
+            return Result::Equal
+        } else {
+            return Result::Greater
+        }
+    }
+
+    // Otherwise, both are negative, so we need to flip the sense of the
+    // comparison to get the correct result.  (This assumes a twos- or ones-
+    // complement integer representation; if integers are represented in a
+    // sign-magnitude representation, then this flip is incorrect).
+    else {
+        if a_rep > b_rep {
+            return Result::Less
+        } else if a_rep == b_rep {
+            return Result::Equal
+        } else {
+            return Result::Greater
+        }
+    }
+}
+fn unord<F: Float>(a: F, b: F) -> bool where
+    u32: CastInto<F::Int>,
+    F::Int: CastInto<u32>,
+    i32: CastInto<F::Int>,
+    F::Int: CastInto<i32>,
+{
+    let one = F::Int::ONE;
+
+    let sign_bit =      F::SIGN_MASK as F::Int;
+    let abs_mask =      sign_bit - one;
+    let exponent_mask = F::EXPONENT_MASK;
+    let inf_rep =       exponent_mask;
+
+    let a_rep = a.repr();
+    let b_rep = b.repr();
+    let a_abs = a_rep & abs_mask;
+    let b_abs = b_rep & abs_mask;
+
+    a_abs > inf_rep || b_abs > inf_rep
+}
+
+intrinsics! {
+    pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 {
+        cmp(a, b).to_le_abi()
+    }
+
+    pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 {
+        cmp(a, b).to_ge_abi()
+    }
+
+    #[arm_aeabi_alias = fcmpun]
+    pub extern "C" fn __unordsf2(a: f32, b: f32) -> bool {
+        unord(a, b)
+    }
+
+    pub extern "C" fn __eqsf2(a: f32, b: f32) -> bool {
+        cmp(a, b).to_le_abi() != 0
+    }
+
+    pub extern "C" fn __ltsf2(a: f32, b: f32) -> bool {
+        cmp(a, b).to_le_abi() != 0
+    }
+
+    pub extern "C" fn __nesf2(a: f32, b: f32) -> bool {
+        cmp(a, b).to_le_abi() != 0
+    }
+
+    pub extern "C" fn __gtsf2(a: f32, b: f32) -> bool {
+        cmp(a, b).to_ge_abi() != 0
+    }
+
+    pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 {
+        cmp(a, b).to_le_abi()
+    }
+
+    pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 {
+        cmp(a, b).to_ge_abi()
+    }
+
+    #[arm_aeabi_alias = dcmpun]
+    pub extern "C" fn __unorddf2(a: f64, b: f64) -> bool {
+        unord(a, b)
+    }
+
+    pub extern "C" fn __eqdf2(a: f64, b: f64) -> bool {
+        cmp(a, b).to_le_abi() != 0
+    }
+
+    pub extern "C" fn __ltdf2(a: f64, b: f64) -> bool {
+        cmp(a, b).to_le_abi() != 0
+    }
+
+    pub extern "C" fn __nedf2(a: f64, b: f64) -> bool {
+        cmp(a, b).to_le_abi() != 0
+    }
+
+    pub extern "C" fn __gtdf2(a: f32, b: f32) -> bool {
+        cmp(a, b).to_ge_abi() != 0
+    }
+}

+ 1 - 0
src/float/mod.rs

@@ -4,6 +4,7 @@ use core::ops;
 use super::int::Int;
 use super::int::Int;
 
 
 pub mod conv;
 pub mod conv;
+pub mod cmp;
 pub mod add;
 pub mod add;
 pub mod pow;
 pub mod pow;
 pub mod sub;
 pub mod sub;