Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement comparesf2/comparedf2 intrinsics #222

Merged
merged 7 commits into from
Jan 13, 2018
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,20 @@ features = ["c"]
## Contributing

1. Pick one or more intrinsics from the [pending list](#progress).
2. Fork this repository
3. Port the intrinsic(s) and their corresponding [unit tests][1] from their [C implementation][2] to
Rust.
4. Send a Pull Request (PR)
5. Once the PR passes our extensive [testing infrastructure][3], we'll merge it!
2. Fork this repository.
3. Port the intrinsic(s) and their corresponding [unit tests][1] from their
[C implementation][2] to Rust.
4. Implement a [test generator][3] to compare the behavior of the ported intrinsic(s)
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:

[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
[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

Expand Down Expand Up @@ -133,6 +137,8 @@ features = ["c"]
- [ ] arm/unordsf2vfp.S
- [x] ashldi3.c
- [x] ashrdi3.c
- [x] comparedf2.c
- [x] comparesf2.c
- [x] divdf3.c
- [x] divdi3.c
- [x] divmoddi4.c
Expand Down Expand Up @@ -301,8 +307,6 @@ These builtins are never called by LLVM.
- ~~clzti2.c~~
- ~~cmpdi2.c~~
- ~~cmpti2.c~~
- ~~comparedf2.c~~
- ~~comparesf2.c~~
- ~~ctzdi2.c~~
- ~~ctzsi2.c~~
- ~~ctzti2.c~~
Expand Down
321 changes: 318 additions & 3 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ mod tests {
Adddf3,
Addsf3,

// float/cmp.rs
Gedf2,
Gesf2,
Ledf2,
Lesf2,

// float/conv.rs
Fixdfdi,
Fixdfsi,
Expand Down Expand Up @@ -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)]
pub struct Moddi3 {
a: i64,
Expand Down Expand Up @@ -4982,8 +5300,6 @@ mod c {
"clzdi2.c",
"clzsi2.c",
"cmpdi2.c",
"comparedf2.c",
"comparesf2.c",
"ctzdi2.c",
"ctzsi2.c",
"divdc3.c",
Expand Down Expand Up @@ -5127,7 +5443,6 @@ mod c {
"arm/bswapsi2.S",
"arm/clzdi2.S",
"arm/clzsi2.S",
"arm/comparesf2.S",
"arm/divmodsi4.S",
"arm/modsi3.S",
"arm/switch16.S",
Expand Down
Loading