2017-12-29 15:49:45 +08:00
|
|
|
#![allow(unreachable_code)]
|
|
|
|
|
2017-12-28 11:41:14 +08:00
|
|
|
use float::Float;
|
2019-05-15 05:33:08 +08:00
|
|
|
use int::{CastInto, Int};
|
2017-12-28 11:41:14 +08:00
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
enum Result {
|
|
|
|
Less,
|
|
|
|
Equal,
|
|
|
|
Greater,
|
2019-05-15 05:33:08 +08:00
|
|
|
Unordered,
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Result {
|
|
|
|
fn to_le_abi(self) -> i32 {
|
|
|
|
match self {
|
2019-05-15 05:33:08 +08:00
|
|
|
Result::Less => -1,
|
|
|
|
Result::Equal => 0,
|
|
|
|
Result::Greater => 1,
|
|
|
|
Result::Unordered => 1,
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_ge_abi(self) -> i32 {
|
|
|
|
match self {
|
2019-05-15 05:33:08 +08:00
|
|
|
Result::Less => -1,
|
|
|
|
Result::Equal => 0,
|
|
|
|
Result::Greater => 1,
|
|
|
|
Result::Unordered => -1,
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-15 05:33:08 +08:00
|
|
|
fn cmp<F: Float>(a: F, b: F) -> Result
|
|
|
|
where
|
2017-12-28 11:41:14 +08:00
|
|
|
u32: CastInto<F::Int>,
|
|
|
|
F::Int: CastInto<u32>,
|
|
|
|
i32: CastInto<F::Int>,
|
|
|
|
F::Int: CastInto<i32>,
|
|
|
|
{
|
2019-05-15 05:33:08 +08:00
|
|
|
let one = F::Int::ONE;
|
|
|
|
let zero = F::Int::ZERO;
|
2017-12-29 15:49:45 +08:00
|
|
|
let szero = F::SignedInt::ZERO;
|
2017-12-28 11:41:14 +08:00
|
|
|
|
2019-05-15 05:33:08 +08:00
|
|
|
let sign_bit = F::SIGN_MASK as F::Int;
|
|
|
|
let abs_mask = sign_bit - one;
|
2017-12-28 11:41:14 +08:00
|
|
|
let exponent_mask = F::EXPONENT_MASK;
|
2019-05-15 05:33:08 +08:00
|
|
|
let inf_rep = exponent_mask;
|
2017-12-28 11:41:14 +08:00
|
|
|
|
2019-05-15 05:33:08 +08:00
|
|
|
let a_rep = a.repr();
|
|
|
|
let b_rep = b.repr();
|
|
|
|
let a_abs = a_rep & abs_mask;
|
|
|
|
let b_abs = b_rep & abs_mask;
|
2017-12-28 11:41:14 +08:00
|
|
|
|
|
|
|
// If either a or b is NaN, they are unordered.
|
|
|
|
if a_abs > inf_rep || b_abs > inf_rep {
|
2019-05-15 05:33:08 +08:00
|
|
|
return Result::Unordered;
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If a and b are both zeros, they are equal.
|
|
|
|
if a_abs | b_abs == zero {
|
2019-05-15 05:33:08 +08:00
|
|
|
return Result::Equal;
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
2017-12-29 15:49:45 +08:00
|
|
|
let a_srep = a.signed_repr();
|
|
|
|
let b_srep = b.signed_repr();
|
|
|
|
|
2017-12-28 11:41:14 +08:00
|
|
|
// 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.
|
2017-12-29 15:49:45 +08:00
|
|
|
if a_srep & b_srep >= szero {
|
|
|
|
if a_srep < b_srep {
|
2019-05-15 05:33:08 +08:00
|
|
|
return Result::Less;
|
2017-12-29 15:49:45 +08:00
|
|
|
} else if a_srep == b_srep {
|
2019-05-15 05:33:08 +08:00
|
|
|
return Result::Equal;
|
2017-12-28 11:41:14 +08:00
|
|
|
} else {
|
2019-05-15 05:33:08 +08:00
|
|
|
return Result::Greater;
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// 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 {
|
2017-12-29 15:49:45 +08:00
|
|
|
if a_srep > b_srep {
|
2019-05-15 05:33:08 +08:00
|
|
|
return Result::Less;
|
2017-12-29 15:49:45 +08:00
|
|
|
} else if a_srep == b_srep {
|
2019-05-15 05:33:08 +08:00
|
|
|
return Result::Equal;
|
2017-12-28 11:41:14 +08:00
|
|
|
} else {
|
2019-05-15 05:33:08 +08:00
|
|
|
return Result::Greater;
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-15 05:33:08 +08:00
|
|
|
fn unord<F: Float>(a: F, b: F) -> bool
|
|
|
|
where
|
2017-12-28 11:41:14 +08:00
|
|
|
u32: CastInto<F::Int>,
|
|
|
|
F::Int: CastInto<u32>,
|
|
|
|
i32: CastInto<F::Int>,
|
|
|
|
F::Int: CastInto<i32>,
|
|
|
|
{
|
|
|
|
let one = F::Int::ONE;
|
|
|
|
|
2019-05-15 05:33:08 +08:00
|
|
|
let sign_bit = F::SIGN_MASK as F::Int;
|
|
|
|
let abs_mask = sign_bit - one;
|
2017-12-28 11:41:14 +08:00
|
|
|
let exponent_mask = F::EXPONENT_MASK;
|
2019-05-15 05:33:08 +08:00
|
|
|
let inf_rep = exponent_mask;
|
2017-12-28 11:41:14 +08:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2018-01-25 07:20:48 +08:00
|
|
|
#[arm_aeabi_alias = __aeabi_fcmpun]
|
2017-12-29 14:14:51 +08:00
|
|
|
pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 {
|
|
|
|
unord(a, b) as i32
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
2017-12-29 14:14:51 +08:00
|
|
|
pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 {
|
|
|
|
cmp(a, b).to_le_abi()
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
2017-12-29 14:14:51 +08:00
|
|
|
pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 {
|
|
|
|
cmp(a, b).to_le_abi()
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
2017-12-29 14:14:51 +08:00
|
|
|
pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 {
|
|
|
|
cmp(a, b).to_le_abi()
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
2017-12-29 14:14:51 +08:00
|
|
|
pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 {
|
|
|
|
cmp(a, b).to_ge_abi()
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2018-01-25 07:20:48 +08:00
|
|
|
#[arm_aeabi_alias = __aeabi_dcmpun]
|
2017-12-29 14:14:51 +08:00
|
|
|
pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 {
|
|
|
|
unord(a, b) as i32
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
2017-12-29 14:14:51 +08:00
|
|
|
pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 {
|
|
|
|
cmp(a, b).to_le_abi()
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
2017-12-29 14:14:51 +08:00
|
|
|
pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 {
|
|
|
|
cmp(a, b).to_le_abi()
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
2017-12-29 14:14:51 +08:00
|
|
|
pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 {
|
|
|
|
cmp(a, b).to_le_abi()
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
|
2018-01-25 07:20:48 +08:00
|
|
|
pub extern "C" fn __gtdf2(a: f64, b: f64) -> i32 {
|
2017-12-29 14:14:51 +08:00
|
|
|
cmp(a, b).to_ge_abi()
|
2017-12-28 11:41:14 +08:00
|
|
|
}
|
|
|
|
}
|
2018-01-25 07:20:48 +08:00
|
|
|
|
|
|
|
#[cfg(target_arch = "arm")]
|
|
|
|
intrinsics! {
|
|
|
|
pub extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 {
|
2018-02-04 16:48:06 +08:00
|
|
|
(__lesf2(a, b) <= 0) as i32
|
2018-01-25 07:20:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2018-02-12 06:46:56 +08:00
|
|
|
|
|
|
|
// On hard-float targets LLVM will use native instructions
|
|
|
|
// for all VFP intrinsics below
|
|
|
|
|
|
|
|
pub extern "C" fn __gesf2vfp(a: f32, b: f32) -> i32 {
|
|
|
|
(a >= b) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
pub extern "C" fn __gedf2vfp(a: f64, b: f64) -> i32 {
|
|
|
|
(a >= b) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
pub extern "C" fn __gtsf2vfp(a: f32, b: f32) -> i32 {
|
|
|
|
(a > b) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
pub extern "C" fn __gtdf2vfp(a: f64, b: f64) -> i32 {
|
|
|
|
(a > b) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
pub extern "C" fn __ltsf2vfp(a: f32, b: f32) -> i32 {
|
|
|
|
(a < b) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
pub extern "C" fn __ltdf2vfp(a: f64, b: f64) -> i32 {
|
|
|
|
(a < b) as i32
|
|
|
|
}
|
|
|
|
|
2018-02-26 00:50:56 +08:00
|
|
|
pub extern "C" fn __lesf2vfp(a: f32, b: f32) -> i32 {
|
|
|
|
(a <= b) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
pub extern "C" fn __ledf2vfp(a: f64, b: f64) -> i32 {
|
|
|
|
(a <= b) as i32
|
|
|
|
}
|
|
|
|
|
2018-02-12 06:46:56 +08:00
|
|
|
pub extern "C" fn __nesf2vfp(a: f32, b: f32) -> i32 {
|
|
|
|
(a != b) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
pub extern "C" fn __nedf2vfp(a: f64, b: f64) -> i32 {
|
|
|
|
(a != b) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
pub extern "C" fn __eqsf2vfp(a: f32, b: f32) -> i32 {
|
|
|
|
(a == b) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
pub extern "C" fn __eqdf2vfp(a: f64, b: f64) -> i32 {
|
|
|
|
(a == b) as i32
|
|
|
|
}
|
2018-01-25 07:20:48 +08:00
|
|
|
}
|