Auto merge of #161 - est31:i128, r=japaric

Implement i128 <-> float conversion functions

Implements {u,i}128 <-> float conversion functions.
master
bors 2017-05-10 02:40:22 +00:00
commit f3ace11071
13 changed files with 664 additions and 45 deletions

View File

@ -5,7 +5,7 @@ name = "compiler_builtins"
version = "0.1.0"
[build-dependencies]
cast = { version = "0.2.0", optional = true }
cast = { version = "0.2.2", features = ["x128"], optional = true }
rand = { version = "0.3.15", optional = true }
[build-dependencies.gcc]

View File

@ -141,22 +141,22 @@ features = ["c"]
- [x] divsi3.c
- [ ] extendhfsf2.c
- [ ] extendsfdf2.c
- [ ] fixdfdi.c
- [ ] fixdfsi.c
- [ ] fixsfdi.c
- [ ] fixsfsi.c
- [ ] fixunsdfdi.c
- [ ] fixunsdfsi.c
- [ ] fixunssfdi.c
- [ ] fixunssfsi.c
- [ ] floatdidf.c
- [x] fixdfdi.c
- [x] fixdfsi.c
- [x] fixsfdi.c
- [x] fixsfsi.c
- [x] fixunsdfdi.c
- [x] fixunsdfsi.c
- [x] fixunssfdi.c
- [x] fixunssfsi.c
- [x] floatdidf.c
- [ ] floatdisf.c
- [ ] floatsidf.c
- [ ] floatsisf.c
- [ ] floatundidf.c
- [x] floatsidf.c
- [x] floatsisf.c
- [x] floatundidf.c
- [ ] floatundisf.c
- [ ] floatunsidf.c
- [ ] floatunsisf.c
- [x] floatunsidf.c
- [x] floatunsisf.c
- [ ] i386/ashldi3.S
- [ ] i386/ashrdi3.S
- [ ] i386/chkstk.S
@ -196,14 +196,14 @@ These builtins are needed to support 128-bit integers, which are in the process
- [x] ashlti3.c
- [x] ashrti3.c
- [x] divti3.c
- [ ] fixdfti.c
- [ ] fixsfti.c
- [ ] fixunsdfti.c
- [ ] fixunssfti.c
- [ ] floattidf.c
- [ ] floattisf.c
- [ ] floatuntidf.c
- [ ] floatuntisf.c
- [x] fixdfti.c
- [x] fixsfti.c
- [x] fixunsdfti.c
- [x] fixunssfti.c
- [x] floattidf.c
- [x] floattisf.c
- [x] floatuntidf.c
- [x] floatuntisf.c
- [x] lshrti3.c
- [x] modti3.c
- [x] muloti4.c

529
build.rs
View File

@ -49,7 +49,7 @@ mod tests {
use std::path::PathBuf;
use std::{env, mem};
use self::cast::{f32, f64, u32, u64, i32, i64};
use self::cast::{f32, f64, u32, u64, u128, i32, i64, i128};
use self::rand::Rng;
const NTESTS: usize = 10_000;
@ -74,16 +74,24 @@ mod tests {
Fixdfsi,
Fixsfdi,
Fixsfsi,
Fixsfti,
Fixdfti,
Fixunsdfdi,
Fixunsdfsi,
Fixunssfdi,
Fixunssfsi,
Fixunssfti,
Fixunsdfti,
Floatdidf,
Floatsidf,
Floatsisf,
Floattisf,
Floattidf,
Floatundidf,
Floatunsidf,
Floatunsisf,
Floatuntisf,
Floatuntidf,
// float/pow.rs
Powidf2,
@ -1084,7 +1092,7 @@ static TEST_CASES: &[((u32,), i32)] = &[
];
#[test]
fn fixsfdi() {
fn fixsfsi() {
for &((a,), b) in TEST_CASES {
let b_ = __fixsfsi(mk_f32(a));
assert_eq!(((a,), b), ((a,), b_));
@ -1094,6 +1102,128 @@ fn fixsfdi() {
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Fixsfti {
a: u32, // f32
b: i128,
}
impl TestCase for Fixsfti {
fn name() -> &'static str {
"fixsfti"
}
fn generate<R>(rng: &mut R) -> Option<Self>
where
R: Rng,
Self: Sized,
{
let a = gen_f32(rng);
i128(a).ok().map(|b| Fixsfti { a: to_u32(a), b })
}
fn to_string(&self, buffer: &mut String) {
writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
}
fn prologue() -> &'static str {
r#"
#[cfg(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test))]
use core::mem;
#[cfg(not(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test)))]
use std::mem;
use compiler_builtins::float::conv::__fixsfti;
fn mk_f32(x: u32) -> f32 {
unsafe { mem::transmute(x) }
}
static TEST_CASES: &[((u32,), i128)] = &[
"#
}
fn epilogue() -> &'static str {
"
];
#[test]
fn fixsfti() {
for &((a,), b) in TEST_CASES {
let b_ = __fixsfti(mk_f32(a));
assert_eq!(((a,), b), ((a,), b_));
}
}
"
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Fixdfti {
a: u64, // f64
b: i128,
}
impl TestCase for Fixdfti {
fn name() -> &'static str {
"fixdfti"
}
fn generate<R>(rng: &mut R) -> Option<Self>
where
R: Rng,
Self: Sized,
{
let a = gen_f64(rng);
i128(a).ok().map(|b| Fixdfti { a: to_u64(a), b })
}
fn to_string(&self, buffer: &mut String) {
writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
}
fn prologue() -> &'static str {
r#"
#[cfg(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test))]
use core::mem;
#[cfg(not(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test)))]
use std::mem;
use compiler_builtins::float::conv::__fixdfti;
fn mk_f64(x: u64) -> f64 {
unsafe { mem::transmute(x) }
}
static TEST_CASES: &[((u64,), i128)] = &[
"#
}
fn epilogue() -> &'static str {
"
];
#[test]
fn fixdfti() {
for &((a,), b) in TEST_CASES {
let b_ = __fixdfti(mk_f64(a));
assert_eq!(((a,), b), ((a,), b_));
}
}
"
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Fixunsdfdi {
a: u64, // f64
@ -1338,6 +1468,128 @@ fn fixunssfsi() {
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Fixunssfti {
a: u32, // f32
b: u128,
}
impl TestCase for Fixunssfti {
fn name() -> &'static str {
"fixunssfti"
}
fn generate<R>(rng: &mut R) -> Option<Self>
where
R: Rng,
Self: Sized,
{
let a = gen_f32(rng);
u128(a).ok().map(|b| Fixunssfti { a: to_u32(a), b })
}
fn to_string(&self, buffer: &mut String) {
writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
}
fn prologue() -> &'static str {
r#"
#[cfg(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test))]
use core::mem;
#[cfg(not(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test)))]
use std::mem;
use compiler_builtins::float::conv::__fixunssfti;
fn mk_f32(x: u32) -> f32 {
unsafe { mem::transmute(x) }
}
static TEST_CASES: &[((u32,), u128)] = &[
"#
}
fn epilogue() -> &'static str {
"
];
#[test]
fn fixunssfti() {
for &((a,), b) in TEST_CASES {
let b_ = __fixunssfti(mk_f32(a));
assert_eq!(((a,), b), ((a,), b_));
}
}
"
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Fixunsdfti {
a: u64, // f64
b: u128,
}
impl TestCase for Fixunsdfti {
fn name() -> &'static str {
"fixunsdfti"
}
fn generate<R>(rng: &mut R) -> Option<Self>
where
R: Rng,
Self: Sized,
{
let a = gen_f64(rng);
u128(a).ok().map(|b| Fixunsdfti { a: to_u64(a), b })
}
fn to_string(&self, buffer: &mut String) {
writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
}
fn prologue() -> &'static str {
r#"
#[cfg(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test))]
use core::mem;
#[cfg(not(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test)))]
use std::mem;
use compiler_builtins::float::conv::__fixunsdfti;
fn mk_f64(x: u64) -> f64 {
unsafe { mem::transmute(x) }
}
static TEST_CASES: &[((u64,), u128)] = &[
"#
}
fn epilogue() -> &'static str {
"
];
#[test]
fn fixunsdfti() {
for &((a,), b) in TEST_CASES {
let b_ = __fixunsdfti(mk_f64(a));
assert_eq!(((a,), b), ((a,), b_));
}
}
"
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Floatdidf {
a: i64,
@ -1536,6 +1788,140 @@ fn floatsisf() {
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Floattisf {
a: i128,
b: u32, // f32
}
impl TestCase for Floattisf {
fn name() -> &'static str {
"floattisf"
}
fn generate<R>(rng: &mut R) -> Option<Self>
where
R: Rng,
Self: Sized,
{
let a = gen_i128(rng);
Some(
Floattisf {
a,
b: to_u32(f32(a)),
},
)
}
fn to_string(&self, buffer: &mut String) {
writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
}
fn prologue() -> &'static str {
r#"
#[cfg(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test))]
use core::mem;
#[cfg(not(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test)))]
use std::mem;
use compiler_builtins::float::conv::__floattisf;
fn to_u32(x: f32) -> u32 {
unsafe { mem::transmute(x) }
}
static TEST_CASES: &[((i128,), u32)] = &[
"#
}
fn epilogue() -> &'static str {
"
];
#[test]
fn floattisf() {
for &((a,), b) in TEST_CASES {
let b_ = __floattisf(a);
assert_eq!(((a,), b), ((a,), to_u32(b_)));
}
}
"
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Floattidf {
a: i128,
b: u64, // f64
}
impl TestCase for Floattidf {
fn name() -> &'static str {
"floattidf"
}
fn generate<R>(rng: &mut R) -> Option<Self>
where
R: Rng,
Self: Sized,
{
let a = gen_i128(rng);
Some(
Floattidf {
a,
b: to_u64(f64(a)),
},
)
}
fn to_string(&self, buffer: &mut String) {
writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
}
fn prologue() -> &'static str {
r#"
#[cfg(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test))]
use core::mem;
#[cfg(not(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test)))]
use std::mem;
use compiler_builtins::float::conv::__floattidf;
fn to_u64(x: f64) -> u64 {
unsafe { mem::transmute(x) }
}
static TEST_CASES: &[((i128,), u64)] = &[
"#
}
fn epilogue() -> &'static str {
"
];
#[test]
fn floattidf() {
for &((a,), b) in TEST_CASES {
let b_ = __floattidf(a);
let g_b = to_u64(b_);
let diff = if g_b > b { g_b - b } else { b - g_b };
assert_eq!(((a,), b, g_b, true), ((a,), b, g_b, diff <= 1));
}
}
"
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Floatundidf {
a: u64,
@ -1734,6 +2120,141 @@ fn floatunsisf() {
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Floatuntisf {
a: u128,
b: u32, // f32
}
impl TestCase for Floatuntisf {
fn name() -> &'static str {
"floatuntisf"
}
fn generate<R>(rng: &mut R) -> Option<Self>
where
R: Rng,
Self: Sized,
{
let a = gen_u128(rng);
let f_a = f32(a);
f_a.ok().map(|f| {
Floatuntisf {
a,
b: to_u32(f),
}
})
}
fn to_string(&self, buffer: &mut String) {
writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
}
fn prologue() -> &'static str {
r#"
#[cfg(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test))]
use core::mem;
#[cfg(not(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test)))]
use std::mem;
use compiler_builtins::float::conv::__floatuntisf;
fn to_u32(x: f32) -> u32 {
unsafe { mem::transmute(x) }
}
static TEST_CASES: &[((u128,), u32)] = &[
"#
}
fn epilogue() -> &'static str {
"
];
#[test]
fn floatuntisf() {
for &((a,), b) in TEST_CASES {
let b_ = __floatuntisf(a);
assert_eq!(((a,), b), ((a,), to_u32(b_)));
}
}
"
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Floatuntidf {
a: u128,
b: u64, // f64
}
impl TestCase for Floatuntidf {
fn name() -> &'static str {
"floatuntidf"
}
fn generate<R>(rng: &mut R) -> Option<Self>
where
R: Rng,
Self: Sized,
{
let a = gen_u128(rng);
Some(
Floatuntidf {
a,
b: to_u64(f64(a)),
},
)
}
fn to_string(&self, buffer: &mut String) {
writeln!(buffer, "(({a},), {b}),", a = self.a, b = self.b).unwrap();
}
fn prologue() -> &'static str {
r#"
#[cfg(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test))]
use core::mem;
#[cfg(not(all(target_arch = "arm",
not(any(target_env = "gnu", target_env = "musl")),
target_os = "linux",
test)))]
use std::mem;
use compiler_builtins::float::conv::__floatuntidf;
fn to_u64(x: f64) -> u64 {
unsafe { mem::transmute(x) }
}
static TEST_CASES: &[((u128,), u64)] = &[
"#
}
fn epilogue() -> &'static str {
"
];
#[test]
fn floatuntidf() {
for &((a,), b) in TEST_CASES {
let b_ = __floatuntidf(a);
let g_b = to_u64(b_);
let diff = if g_b > b { g_b - b } else { b - g_b };
assert_eq!(((a,), b, g_b, true), ((a,), b, g_b, diff <= 1));
}
}
"
}
}
#[derive(Eq, Hash, PartialEq)]
pub struct Moddi3 {
a: i64,
@ -3417,7 +3938,9 @@ macro_rules! panic {
let rng = &mut rand::thread_rng();
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let out_file = out_dir.join(format!("{}.rs", T::name()));
let out_file_name = format!("{}.rs", T::name());
let out_file = out_dir.join(&out_file_name);
println!("Generating {}", out_file_name);
let contents = mk_tests::<T, _>(NTESTS, rng);
File::create(out_file)

View File

@ -12,10 +12,13 @@ macro_rules! fp_overflow {
}
}
macro_rules! fp_convert {
macro_rules! int_to_float {
($intrinsic:ident: $ity:ty, $fty:ty) => {
int_to_float!($intrinsic: $ity, $fty, "C");
};
($intrinsic:ident: $ity:ty, $fty:ty, $abi:tt) => {
pub extern "C" fn $intrinsic(i: $ity) -> $fty {
pub extern $abi fn $intrinsic(i: $ity) -> $fty {
if i == 0 {
return 0.0
}
@ -82,12 +85,25 @@ macro_rules! fp_convert {
}
}
fp_convert!(__floatsisf: i32, f32);
fp_convert!(__floatsidf: i32, f64);
fp_convert!(__floatdidf: i64, f64);
fp_convert!(__floatunsisf: u32, f32);
fp_convert!(__floatunsidf: u32, f64);
fp_convert!(__floatundidf: u64, f64);
macro_rules! int_to_float_unadj_on_win {
($intrinsic:ident: $ity:ty, $fty:ty) => {
#[cfg(all(windows, target_pointer_width="64"))]
int_to_float!($intrinsic: $ity, $fty, "unadjusted");
#[cfg(not(all(windows, target_pointer_width="64")))]
int_to_float!($intrinsic: $ity, $fty, "C");
};
}
int_to_float!(__floatsisf: i32, f32);
int_to_float!(__floatsidf: i32, f64);
int_to_float!(__floatdidf: i64, f64);
int_to_float_unadj_on_win!(__floattisf: i128, f32);
int_to_float_unadj_on_win!(__floattidf: i128, f64);
int_to_float!(__floatunsisf: u32, f32);
int_to_float!(__floatunsidf: u32, f64);
int_to_float!(__floatundidf: u64, f64);
int_to_float_unadj_on_win!(__floatuntisf: u128, f32);
int_to_float_unadj_on_win!(__floatuntidf: u128, f64);
#[derive(PartialEq, Debug)]
enum Sign {
@ -95,9 +111,12 @@ enum Sign {
Negative
}
macro_rules! fp_fix {
macro_rules! float_to_int {
($intrinsic:ident: $fty:ty, $ity:ty) => {
pub extern "C" fn $intrinsic(f: $fty) -> $ity {
float_to_int!($intrinsic: $fty, $ity, "C");
};
($intrinsic:ident: $fty:ty, $ity:ty, $abi:tt) => {
pub extern $abi fn $intrinsic(f: $fty) -> $ity {
let fixint_min = <$ity>::min_value();
let fixint_max = <$ity>::max_value();
let fixint_bits = <$ity>::bits() as usize;
@ -147,12 +166,25 @@ macro_rules! fp_fix {
}
}
fp_fix!(__fixsfsi: f32, i32);
fp_fix!(__fixsfdi: f32, i64);
fp_fix!(__fixdfsi: f64, i32);
fp_fix!(__fixdfdi: f64, i64);
macro_rules! float_to_int_unadj_on_win {
($intrinsic:ident: $fty:ty, $ity:ty) => {
#[cfg(all(windows, target_pointer_width="64"))]
float_to_int!($intrinsic: $fty, $ity, "unadjusted");
#[cfg(not(all(windows, target_pointer_width="64")))]
float_to_int!($intrinsic: $fty, $ity, "C");
};
}
fp_fix!(__fixunssfsi: f32, u32);
fp_fix!(__fixunssfdi: f32, u64);
fp_fix!(__fixunsdfsi: f64, u32);
fp_fix!(__fixunsdfdi: f64, u64);
float_to_int!(__fixsfsi: f32, i32);
float_to_int!(__fixsfdi: f32, i64);
float_to_int_unadj_on_win!(__fixsfti: f32, i128);
float_to_int!(__fixdfsi: f64, i32);
float_to_int!(__fixdfdi: f64, i64);
float_to_int_unadj_on_win!(__fixdfti: f64, i128);
float_to_int!(__fixunssfsi: f32, u32);
float_to_int!(__fixunssfdi: f32, u64);
float_to_int_unadj_on_win!(__fixunssfti: f32, u128);
float_to_int!(__fixunsdfsi: f64, u32);
float_to_int!(__fixunsdfdi: f64, u64);
float_to_int_unadj_on_win!(__fixunsdfti: f64, u128);

View File

@ -63,7 +63,7 @@ macro_rules! int_impl {
fn extract_sign(self) -> (bool, $uty) {
if self < 0 {
(true, !(self as $uty) + 1)
(true, (!(self as $uty)).wrapping_add(1))
} else {
(false, self as $uty)
}

8
tests/fixdfti.rs Normal file
View File

@ -0,0 +1,8 @@
#![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"), "/fixdfti.rs"));

8
tests/fixsfti.rs Normal file
View File

@ -0,0 +1,8 @@
#![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"), "/fixsfti.rs"));

8
tests/fixunsdfti.rs Normal file
View File

@ -0,0 +1,8 @@
#![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"), "/fixunsdfti.rs"));

8
tests/fixunssfti.rs Normal file
View File

@ -0,0 +1,8 @@
#![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"), "/fixunssfti.rs"));

8
tests/floattidf.rs Normal file
View File

@ -0,0 +1,8 @@
#![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"), "/floattidf.rs"));

8
tests/floattisf.rs Normal file
View File

@ -0,0 +1,8 @@
#![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"), "/floattisf.rs"));

8
tests/floatuntidf.rs Normal file
View File

@ -0,0 +1,8 @@
#![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"), "/floatuntidf.rs"));

8
tests/floatuntisf.rs Normal file
View File

@ -0,0 +1,8 @@
#![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"), "/floatuntisf.rs"));