#![allow(unreachable_code)] 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 szero = F::SignedInt::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 } let a_srep = a.signed_repr(); let b_srep = b.signed_repr(); // 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_srep & b_srep >= szero { if a_srep < b_srep { return Result::Less } else if a_srep == b_srep { 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_srep > b_srep { return Result::Less } else if a_srep == b_srep { 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 = __aeabi_fcmpun] pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 { unord(a, b) as i32 } pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 { cmp(a, b).to_le_abi() } pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 { cmp(a, b).to_ge_abi() } 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 = __aeabi_dcmpun] pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 { unord(a, b) as i32 } pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 { cmp(a, b).to_le_abi() } pub extern "C" fn __gtdf2(a: f64, b: f64) -> i32 { cmp(a, b).to_ge_abi() } } #[cfg(target_arch = "arm")] intrinsics! { pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { (__lesf2(a, b) < 0) as i32 } pub extern "aapcs" fn __aeabi_fcmpge(a: f32, b: f32) -> i32 { (__gesf2(a, b) >= 0) as i32 } pub extern "aapcs" fn __aeabi_fcmpeq(a: f32, b: f32) -> i32 { (__eqsf2(a, b) == 0) as i32 } pub extern "aapcs" fn __aeabi_fcmplt(a: f32, b: f32) -> i32 { (__ltsf2(a, b) < 0) as i32 } pub extern "aapcs" fn __aeabi_fcmpgt(a: f32, b: f32) -> i32 { (__gtsf2(a, b) > 0) as i32 } pub extern "aapcs" fn __aeabi_dcmple(a: f64, b: f64) -> i32 { (__ledf2(a, b) <= 0) as i32 } pub extern "aapcs" fn __aeabi_dcmpge(a: f64, b: f64) -> i32 { (__gedf2(a, b) >= 0) as i32 } pub extern "aapcs" fn __aeabi_dcmpeq(a: f64, b: f64) -> i32 { (__eqdf2(a, b) == 0) as i32 } pub extern "aapcs" fn __aeabi_dcmplt(a: f64, b: f64) -> i32 { (__ltdf2(a, b) < 0) as i32 } pub extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { (__gtdf2(a, b) > 0) as i32 } }