Merge pull request #222 from whitequark/master
Implement comparesf2/comparedf2 intrinsics
This commit is contained in:
commit
bf912e607e
20
README.md
20
README.md
|
@ -52,16 +52,20 @@ features = ["c"]
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
1. Pick one or more intrinsics from the [pending list](#progress).
|
1. Pick one or more intrinsics from the [pending list](#progress).
|
||||||
2. Fork this repository
|
2. Fork this repository.
|
||||||
3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to
|
3. Port the intrinsic(s) and their corresponding [unit tests][1] from their
|
||||||
Rust.
|
[C implementation][2] to Rust.
|
||||||
4. Send a Pull Request (PR)
|
4. Implement a [test generator][3] to compare the behavior of the ported intrinsic(s)
|
||||||
5. Once the PR passes our extensive [testing infrastructure][3], we'll merge it!
|
with their implementation on the testing host. Note that randomized compiler-builtin tests
|
||||||
|
should be run using `cargo test --features gen-tests`.
|
||||||
|
4. Send a Pull Request (PR).
|
||||||
|
5. Once the PR passes our extensive [testing infrastructure][4], we'll merge it!
|
||||||
6. Celebrate :tada:
|
6. Celebrate :tada:
|
||||||
|
|
||||||
[1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit
|
[1]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/test/builtins/Unit
|
||||||
[2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins
|
[2]: https://github.com/rust-lang/compiler-rt/tree/8598065bd965d9713bfafb6c1e766d63a7b17b89/lib/builtins
|
||||||
[3]: https://travis-ci.org/rust-lang-nursery/compiler-builtins
|
[3]: https://github.com/rust-lang-nursery/compiler-builtins/blob/0ba07e49264a54cb5bbd4856fcea083bb3fbec15/build.rs#L180-L265
|
||||||
|
[4]: https://travis-ci.org/rust-lang-nursery/compiler-builtins
|
||||||
|
|
||||||
### Porting Reminders
|
### Porting Reminders
|
||||||
|
|
||||||
|
@ -133,6 +137,8 @@ features = ["c"]
|
||||||
- [ ] arm/unordsf2vfp.S
|
- [ ] arm/unordsf2vfp.S
|
||||||
- [x] ashldi3.c
|
- [x] ashldi3.c
|
||||||
- [x] ashrdi3.c
|
- [x] ashrdi3.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
|
||||||
|
@ -301,8 +307,6 @@ These builtins are never called by LLVM.
|
||||||
- ~~clzti2.c~~
|
- ~~clzti2.c~~
|
||||||
- ~~cmpdi2.c~~
|
- ~~cmpdi2.c~~
|
||||||
- ~~cmpti2.c~~
|
- ~~cmpti2.c~~
|
||||||
- ~~comparedf2.c~~
|
|
||||||
- ~~comparesf2.c~~
|
|
||||||
- ~~ctzdi2.c~~
|
- ~~ctzdi2.c~~
|
||||||
- ~~ctzsi2.c~~
|
- ~~ctzsi2.c~~
|
||||||
- ~~ctzti2.c~~
|
- ~~ctzti2.c~~
|
||||||
|
|
321
build.rs
321
build.rs
|
@ -89,6 +89,12 @@ mod tests {
|
||||||
Adddf3,
|
Adddf3,
|
||||||
Addsf3,
|
Addsf3,
|
||||||
|
|
||||||
|
// float/cmp.rs
|
||||||
|
Gedf2,
|
||||||
|
Gesf2,
|
||||||
|
Ledf2,
|
||||||
|
Lesf2,
|
||||||
|
|
||||||
// float/conv.rs
|
// float/conv.rs
|
||||||
Fixdfdi,
|
Fixdfdi,
|
||||||
Fixdfsi,
|
Fixdfsi,
|
||||||
|
@ -2529,6 +2535,318 @@ fn floatuntidf() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct Gedf2 {
|
||||||
|
a: u64,
|
||||||
|
b: u64,
|
||||||
|
c: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCase for Gedf2 {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"gedf2"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let a = gen_f64(rng);
|
||||||
|
let b = gen_f64(rng);
|
||||||
|
// 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() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c;
|
||||||
|
if a.is_nan() || b.is_nan() {
|
||||||
|
c = -1;
|
||||||
|
} else if a < b {
|
||||||
|
c = -1;
|
||||||
|
} else if a > b {
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Gedf2 { a: to_u64(a), b: to_u64(b), 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 {
|
||||||
|
"
|
||||||
|
use std::mem;
|
||||||
|
use compiler_builtins::float::cmp::__gedf2;
|
||||||
|
|
||||||
|
fn to_f64(x: u64) -> f64 {
|
||||||
|
unsafe { mem::transmute(x) }
|
||||||
|
}
|
||||||
|
|
||||||
|
static TEST_CASES: &[((u64, u64), i32)] = &[
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn epilogue() -> &'static str {
|
||||||
|
"
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gedf2() {
|
||||||
|
for &((a, b), c) in TEST_CASES {
|
||||||
|
let c_ = __gedf2(to_f64(a), to_f64(b));
|
||||||
|
assert_eq!(((a, b), c), ((a, b), c_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct Gesf2 {
|
||||||
|
a: u32,
|
||||||
|
b: u32,
|
||||||
|
c: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCase for Gesf2 {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"gesf2"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let a = gen_f32(rng);
|
||||||
|
let b = gen_f32(rng);
|
||||||
|
// 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() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c;
|
||||||
|
if a.is_nan() || b.is_nan() {
|
||||||
|
c = -1;
|
||||||
|
} else if a < b {
|
||||||
|
c = -1;
|
||||||
|
} else if a > b {
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Gesf2 { a: to_u32(a), b: to_u32(b), 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 {
|
||||||
|
"
|
||||||
|
use std::mem;
|
||||||
|
use compiler_builtins::float::cmp::__gesf2;
|
||||||
|
|
||||||
|
fn to_f32(x: u32) -> f32 {
|
||||||
|
unsafe { mem::transmute(x) }
|
||||||
|
}
|
||||||
|
|
||||||
|
static TEST_CASES: &[((u32, u32), i32)] = &[
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn epilogue() -> &'static str {
|
||||||
|
"
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gesf2() {
|
||||||
|
for &((a, b), c) in TEST_CASES {
|
||||||
|
let c_ = __gesf2(to_f32(a), to_f32(b));
|
||||||
|
assert_eq!(((a, b), c), ((a, b), c_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct Ledf2 {
|
||||||
|
a: u64,
|
||||||
|
b: u64,
|
||||||
|
c: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCase for Ledf2 {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"ledf2"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let a = gen_f64(rng);
|
||||||
|
let b = gen_f64(rng);
|
||||||
|
// 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() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c;
|
||||||
|
if a.is_nan() || b.is_nan() {
|
||||||
|
c = 1;
|
||||||
|
} else if a < b {
|
||||||
|
c = -1;
|
||||||
|
} else if a > b {
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Ledf2 { a: to_u64(a), b: to_u64(b), 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 {
|
||||||
|
"
|
||||||
|
use std::mem;
|
||||||
|
use compiler_builtins::float::cmp::__ledf2;
|
||||||
|
|
||||||
|
fn to_f64(x: u64) -> f64 {
|
||||||
|
unsafe { mem::transmute(x) }
|
||||||
|
}
|
||||||
|
|
||||||
|
static TEST_CASES: &[((u64, u64), i32)] = &[
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn epilogue() -> &'static str {
|
||||||
|
"
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ledf2() {
|
||||||
|
for &((a, b), c) in TEST_CASES {
|
||||||
|
let c_ = __ledf2(to_f64(a), to_f64(b));
|
||||||
|
assert_eq!(((a, b), c), ((a, b), c_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
|
pub struct Lesf2 {
|
||||||
|
a: u32,
|
||||||
|
b: u32,
|
||||||
|
c: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCase for Lesf2 {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"lesf2"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate<R>(rng: &mut R) -> Option<Self>
|
||||||
|
where
|
||||||
|
R: Rng,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let a = gen_f32(rng);
|
||||||
|
let b = gen_f32(rng);
|
||||||
|
// 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() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c;
|
||||||
|
if a.is_nan() || b.is_nan() {
|
||||||
|
c = 1;
|
||||||
|
} else if a < b {
|
||||||
|
c = -1;
|
||||||
|
} else if a > b {
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Lesf2 { a: to_u32(a), b: to_u32(b), 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 {
|
||||||
|
"
|
||||||
|
use std::mem;
|
||||||
|
use compiler_builtins::float::cmp::__lesf2;
|
||||||
|
|
||||||
|
fn to_f32(x: u32) -> f32 {
|
||||||
|
unsafe { mem::transmute(x) }
|
||||||
|
}
|
||||||
|
|
||||||
|
static TEST_CASES: &[((u32, u32), i32)] = &[
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn epilogue() -> &'static str {
|
||||||
|
"
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lesf2() {
|
||||||
|
for &((a, b), c) in TEST_CASES {
|
||||||
|
let c_ = __lesf2(to_f32(a), to_f32(b));
|
||||||
|
assert_eq!(((a, b), c), ((a, b), c_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq)]
|
#[derive(Eq, Hash, PartialEq)]
|
||||||
pub struct Moddi3 {
|
pub struct Moddi3 {
|
||||||
a: i64,
|
a: i64,
|
||||||
|
@ -4982,8 +5300,6 @@ mod c {
|
||||||
"clzdi2.c",
|
"clzdi2.c",
|
||||||
"clzsi2.c",
|
"clzsi2.c",
|
||||||
"cmpdi2.c",
|
"cmpdi2.c",
|
||||||
"comparedf2.c",
|
|
||||||
"comparesf2.c",
|
|
||||||
"ctzdi2.c",
|
"ctzdi2.c",
|
||||||
"ctzsi2.c",
|
"ctzsi2.c",
|
||||||
"divdc3.c",
|
"divdc3.c",
|
||||||
|
@ -5127,7 +5443,6 @@ mod c {
|
||||||
"arm/bswapsi2.S",
|
"arm/bswapsi2.S",
|
||||||
"arm/clzdi2.S",
|
"arm/clzdi2.S",
|
||||||
"arm/clzsi2.S",
|
"arm/clzsi2.S",
|
||||||
"arm/comparesf2.S",
|
|
||||||
"arm/divmodsi4.S",
|
"arm/divmodsi4.S",
|
||||||
"arm/modsi3.S",
|
"arm/modsi3.S",
|
||||||
"arm/switch16.S",
|
"arm/switch16.S",
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
#![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<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 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<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) -> 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 = 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: f32, b: f32) -> i32 {
|
||||||
|
cmp(a, b).to_ge_abi()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
@ -25,6 +26,9 @@ pub trait Float:
|
||||||
/// A uint of the same with as the float
|
/// A uint of the same with as the float
|
||||||
type Int: Int;
|
type Int: Int;
|
||||||
|
|
||||||
|
/// A int of the same with as the float
|
||||||
|
type SignedInt: Int;
|
||||||
|
|
||||||
const ZERO: Self;
|
const ZERO: Self;
|
||||||
const ONE: Self;
|
const ONE: Self;
|
||||||
|
|
||||||
|
@ -58,6 +62,9 @@ pub trait Float:
|
||||||
/// Returns `self` transmuted to `Self::Int`
|
/// Returns `self` transmuted to `Self::Int`
|
||||||
fn repr(self) -> Self::Int;
|
fn repr(self) -> Self::Int;
|
||||||
|
|
||||||
|
/// Returns `self` transmuted to `Self::SignedInt`
|
||||||
|
fn signed_repr(self) -> Self::SignedInt;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
|
/// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
|
||||||
/// represented in multiple different ways. This method returns `true` if two NaNs are
|
/// represented in multiple different ways. This method returns `true` if two NaNs are
|
||||||
|
@ -77,9 +84,10 @@ pub trait Float:
|
||||||
// FIXME: Some of this can be removed if RFC Issue #1424 is resolved
|
// FIXME: Some of this can be removed if RFC Issue #1424 is resolved
|
||||||
// https://github.com/rust-lang/rfcs/issues/1424
|
// https://github.com/rust-lang/rfcs/issues/1424
|
||||||
macro_rules! float_impl {
|
macro_rules! float_impl {
|
||||||
($ty:ident, $ity:ident, $bits:expr, $significand_bits:expr) => {
|
($ty:ident, $ity:ident, $sity:ident, $bits:expr, $significand_bits:expr) => {
|
||||||
impl Float for $ty {
|
impl Float for $ty {
|
||||||
type Int = $ity;
|
type Int = $ity;
|
||||||
|
type SignedInt = $sity;
|
||||||
const ZERO: Self = 0.0;
|
const ZERO: Self = 0.0;
|
||||||
const ONE: Self = 1.0;
|
const ONE: Self = 1.0;
|
||||||
|
|
||||||
|
@ -94,6 +102,9 @@ macro_rules! float_impl {
|
||||||
fn repr(self) -> Self::Int {
|
fn repr(self) -> Self::Int {
|
||||||
unsafe { mem::transmute(self) }
|
unsafe { mem::transmute(self) }
|
||||||
}
|
}
|
||||||
|
fn signed_repr(self) -> Self::SignedInt {
|
||||||
|
unsafe { mem::transmute(self) }
|
||||||
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn eq_repr(self, rhs: Self) -> bool {
|
fn eq_repr(self, rhs: Self) -> bool {
|
||||||
if self.is_nan() && rhs.is_nan() {
|
if self.is_nan() && rhs.is_nan() {
|
||||||
|
@ -119,5 +130,5 @@ macro_rules! float_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float_impl!(f32, u32, 32, 23);
|
float_impl!(f32, u32, i32, 32, 23);
|
||||||
float_impl!(f64, u64, 64, 52);
|
float_impl!(f64, u64, i64, 64, 52);
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#![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)]
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/gedf2.rs"));
|
|
@ -0,0 +1,7 @@
|
||||||
|
#![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)]
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/gesf2.rs"));
|
|
@ -0,0 +1,7 @@
|
||||||
|
#![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)]
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/ledf2.rs"));
|
|
@ -0,0 +1,7 @@
|
||||||
|
#![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)]
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/lesf2.rs"));
|
Loading…
Reference in New Issue