From f5d86476a89a84add78900db092f29a20c31db16 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 03:41:14 +0000 Subject: [PATCH] Implement comparesf2/comparedf2 intrinsics. --- README.md | 4 +- src/float/cmp.rs | 166 +++++++++++++++++++++++++++++++++++++++++++++++ src/float/mod.rs | 1 + 3 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 src/float/cmp.rs diff --git a/README.md b/README.md index 533850b..6123fe4 100644 --- a/README.md +++ b/README.md @@ -133,8 +133,8 @@ features = ["c"] - [ ] arm/unordsf2vfp.S - [x] ashldi3.c - [x] ashrdi3.c -- [ ] comparedf2.c -- [ ] comparesf2.c +- [x] comparedf2.c +- [x] comparesf2.c - [x] divdf3.c - [x] divdi3.c - [x] divmoddi4.c diff --git a/src/float/cmp.rs b/src/float/cmp.rs new file mode 100644 index 0000000..f10860c --- /dev/null +++ b/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(a: F, b: F) -> Result where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, +{ + 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(a: F, b: F) -> bool where + u32: CastInto, + F::Int: CastInto, + i32: CastInto, + F::Int: CastInto, +{ + 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 + } +} diff --git a/src/float/mod.rs b/src/float/mod.rs index 6daf7b8..f13256d 100644 --- a/src/float/mod.rs +++ b/src/float/mod.rs @@ -4,6 +4,7 @@ use core::ops; use super::int::Int; pub mod conv; +pub mod cmp; pub mod add; pub mod pow; pub mod sub;