From 79808af0c437dc637ac398ca832813442f95b9a2 Mon Sep 17 00:00:00 2001 From: Phaiax Date: Sat, 15 Oct 2016 04:26:56 +0200 Subject: [PATCH 1/3] Implement floatunsisf (WIP) --- compiler-rt/compiler-rt-cdylib/build.rs | 1 + compiler-rt/compiler-rt-cdylib/src/lib.rs | 2 + src/float/conv.rs | 74 +++++++++++++++++++ src/float/mod.rs | 86 ++++++++++++++++++++--- 4 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 src/float/conv.rs diff --git a/compiler-rt/compiler-rt-cdylib/build.rs b/compiler-rt/compiler-rt-cdylib/build.rs index 4eb763895..7fb9e8adf 100644 --- a/compiler-rt/compiler-rt-cdylib/build.rs +++ b/compiler-rt/compiler-rt-cdylib/build.rs @@ -60,6 +60,7 @@ fn main() { "addsf3.c", "powidf2.c", "powisf2.c", + "floatunsisf.c", ]); for src in sources.files.iter() { diff --git a/compiler-rt/compiler-rt-cdylib/src/lib.rs b/compiler-rt/compiler-rt-cdylib/src/lib.rs index 81affa242..bf210c703 100644 --- a/compiler-rt/compiler-rt-cdylib/src/lib.rs +++ b/compiler-rt/compiler-rt-cdylib/src/lib.rs @@ -24,6 +24,7 @@ extern { fn __adddf3(); fn __powisf2(); fn __powidf2(); + fn __floatunsisf(); } macro_rules! declare { @@ -57,6 +58,7 @@ declare!(___addsf3, __addsf3); declare!(___adddf3, __adddf3); declare!(___powisf2, __powisf2); declare!(___powidf2, __powidf2); +declare!(___floatunsisf, __floatunsisf); #[lang = "eh_personality"] fn eh_personality() {} diff --git a/src/float/conv.rs b/src/float/conv.rs new file mode 100644 index 000000000..54c60c73d --- /dev/null +++ b/src/float/conv.rs @@ -0,0 +1,74 @@ +use core::num::Wrapping; +use float::Float; +use int::Int; + + +macro_rules! floatunsisf { + ($intrinsic:ident: $ity:ty => $fty:ty) => { + /// Returns `a as f32` or `a as f64` + #[cfg_attr(not(test), no_mangle)] + pub extern "C" fn $intrinsic(a: $ity) -> $fty { + // CC This file implements unsigned integer to single-precision conversion for the + // CC compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even + // CC mode. + + // CC const int aWidth = sizeof a * CHAR_BIT; + let a_width : usize = <$ity>::bits() as usize; + // CC + // CC // Handle zero as a special case to protect clz + // CC if (a == 0) return fromRep(0); + if a == 0 { return (<$fty as Float>::from_repr)(<$fty>::zero().0); } + // CC + // CC // Exponent of (fp_t)a is the width of abs(a). + // CC const int exponent = (aWidth - 1) - __builtin_clz(a); + let exponent : usize = (a_width - 1usize) - a.leading_zeros() as usize; + // CC rep_t result; + // CC + let mut result = + // CC // Shift a into the significand field, rounding if it is a right-shift + // CC if (exponent <= significandBits) { + if exponent <= <$fty>::significand_bits() { + // CC const int shift = significandBits - exponent; + let shift = <$fty>::significand_bits() - exponent; + // CC result = (rep_t)a << shift ^ implicitBit; + (Wrapping(a as <$fty as Float>::Int) << shift) ^ <$fty>::implicit_bit() + // CC } else { + } else { + // CC const int shift = exponent - significandBits; + let shift = exponent - <$fty>::significand_bits(); + // CC result = (rep_t)a >> shift ^ implicitBit; + let mut result = (Wrapping(a as <$fty as Float>::Int) >> shift) ^ <$fty>::implicit_bit(); + // CC rep_t round = (rep_t)a << (typeWidth - shift); + let round = Wrapping(a as <$fty as Float>::Int) << (<$fty>::bits() - shift); + // CC if (round > signBit) result++; + if round > <$fty>::sign_bit() { result += <$fty>::one() } + // CC if (round == signBit) result += result & 1; + if round == <$fty>::sign_bit() { result += result & <$fty>::one() } + result + // CC } + }; + // CC + // CC // Insert the exponent + // CC result += (rep_t)(exponent + exponentBias) << significandBits; + result += Wrapping((exponent + <$fty>::exponent_bias()) as <$fty as Float>::Int) << <$fty>::significand_bits(); + // CC return fromRep(result); + <$fty as Float>::from_repr(result.0) + } + } +} + +// __floatunsisf implements unsigned integer to single-precision conversion +// (IEEE-754 default round-to-nearest, ties-to-even mode) +floatunsisf!(__floatunsisf: u32 => f32); + +#[cfg(test)] +mod tests { + use qc::{U32}; + + check! { + fn __floatunsisf(f: extern fn(u32) -> f32, a: U32) + -> Option { + Some(f(a.0)) + } + } +} diff --git a/src/float/mod.rs b/src/float/mod.rs index 7dc084d4f..7b7ddd5d5 100644 --- a/src/float/mod.rs +++ b/src/float/mod.rs @@ -1,20 +1,83 @@ use core::mem; +use core::num::Wrapping; +use core::ops; +use core::convert; #[cfg(test)] use core::fmt; pub mod add; pub mod pow; +pub mod conv; /// Trait for some basic operations on floats -pub trait Float: Sized + Copy { +pub trait Float: Sized + Copy + where Wrapping : ops::Shl> + + ops::Shr> + + ops::Sub, Output = Wrapping> + + ops::BitOr, Output = Wrapping> + + ops::BitXor, Output = Wrapping>, + Self::Int : convert::From +{ /// A uint of the same with as the float type Int; + fn one() -> Wrapping { + Wrapping(Self::Int::from(1u32)) + } + + fn zero() -> Wrapping { + Wrapping(Self::Int::from(0u32)) + } + /// Returns the bitwidth of the float type - fn bits() -> u32; + fn bits() -> usize; /// Returns the bitwidth of the significand - fn significand_bits() -> u32; + fn significand_bits() -> usize; + + fn exponent_bits() -> usize { + Self::bits() - Self::significand_bits() - 1 + } + + fn max_exponent() -> usize { + (1usize << Self::exponent_bits()).wrapping_sub(1) + } + + fn exponent_bias() -> usize { + Self::max_exponent() >> 1 + } + + fn implicit_bit() -> Wrapping { + Self::one() << Self::significand_bits() + } + + fn significand_mask() -> Wrapping { + Self::implicit_bit() - Self::one() + } + + fn sign_bit() -> Wrapping { + Self::one() << (Self::significand_bits() + Self::exponent_bits()) + } + + fn abs_mask() -> Wrapping { + Self::sign_bit() - Self::one() + } + + fn exponent_mask() -> Wrapping { + Self::abs_mask() ^ Self::significand_mask() + } + + fn inf_rep() -> Wrapping { + Self::exponent_mask() + } + + fn quiet_bit() -> Wrapping { + Self::implicit_bit() >> 1 + } + + fn qnan_rep() -> Wrapping { + Self::exponent_mask() | Self::quiet_bit() + } /// Returns `self` transmuted to `Self::Int` fn repr(self) -> Self::Int; @@ -34,10 +97,10 @@ pub trait Float: Sized + Copy { impl Float for f32 { type Int = u32; - fn bits() -> u32 { + fn bits() -> usize { 32 } - fn significand_bits() -> u32 { + fn significand_bits() -> usize { 23 } fn repr(self) -> Self::Int { @@ -60,12 +123,13 @@ impl Float for f32 { (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } } + impl Float for f64 { type Int = u64; - fn bits() -> u32 { + fn bits() -> usize { 64 } - fn significand_bits() -> u32 { + fn significand_bits() -> usize { 52 } fn repr(self) -> Self::Int { @@ -95,7 +159,13 @@ impl Float for f64 { pub struct FRepr(F); #[cfg(test)] -impl PartialEq for FRepr { +impl PartialEq for FRepr + where Wrapping : ops::Shl> + + ops::Shr> + + ops::Sub, Output = Wrapping> + + ops::BitOr, Output = Wrapping> + + ops::BitXor, Output = Wrapping> +{ fn eq(&self, other: &FRepr) -> bool { // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't // match the output of its gcc_s counterpart. Until we investigate further, we'll From be076ac41f7309e320a6d352f6f866c8772feb0d Mon Sep 17 00:00:00 2001 From: Phaiax Date: Sat, 15 Oct 2016 19:00:39 +0200 Subject: [PATCH 2/3] Implement floatunsisf (WIP 2) --- build.rs | 1 - src/arm.rs | 5 +++++ src/float/conv.rs | 28 ++++++++++++++++++++++++---- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/build.rs b/build.rs index c0fdb52ec..93fb9215a 100644 --- a/build.rs +++ b/build.rs @@ -145,7 +145,6 @@ fn main() { "floatundisf.c", "floatundixf.c", "floatunsidf.c", - "floatunsisf.c", "int_util.c", "muldc3.c", "muldf3.c", diff --git a/src/arm.rs b/src/arm.rs index b74458f11..61ca5e263 100644 --- a/src/arm.rs +++ b/src/arm.rs @@ -68,6 +68,11 @@ pub extern "C" fn __aeabi_fadd(a: f32, b: f32) -> f32 { ::float::add::__addsf3(a, b) } +#[cfg_attr(not(test), no_mangle)] +pub extern "C" fn __aeabi_ui2f(a: u32) -> f32 { + ::float::conv::__floatunsisf(a) +} + #[cfg(not(all(feature = "c", target_arch = "arm", not(target_os = "ios"), not(thumbv6m))))] #[cfg_attr(not(test), no_mangle)] pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 { diff --git a/src/float/conv.rs b/src/float/conv.rs index 54c60c73d..aafcc7dc2 100644 --- a/src/float/conv.rs +++ b/src/float/conv.rs @@ -14,16 +14,16 @@ macro_rules! floatunsisf { // CC const int aWidth = sizeof a * CHAR_BIT; let a_width : usize = <$ity>::bits() as usize; - // CC + // CC // CC // Handle zero as a special case to protect clz // CC if (a == 0) return fromRep(0); if a == 0 { return (<$fty as Float>::from_repr)(<$fty>::zero().0); } - // CC + // CC // CC // Exponent of (fp_t)a is the width of abs(a). // CC const int exponent = (aWidth - 1) - __builtin_clz(a); let exponent : usize = (a_width - 1usize) - a.leading_zeros() as usize; // CC rep_t result; - // CC + // CC let mut result = // CC // Shift a into the significand field, rounding if it is a right-shift // CC if (exponent <= significandBits) { @@ -47,7 +47,7 @@ macro_rules! floatunsisf { result // CC } }; - // CC + // CC // CC // Insert the exponent // CC result += (rep_t)(exponent + exponentBias) << significandBits; result += Wrapping((exponent + <$fty>::exponent_bias()) as <$fty as Float>::Int) << <$fty>::significand_bits(); @@ -64,6 +64,7 @@ floatunsisf!(__floatunsisf: u32 => f32); #[cfg(test)] mod tests { use qc::{U32}; + use float::{Float}; check! { fn __floatunsisf(f: extern fn(u32) -> f32, a: U32) @@ -71,4 +72,23 @@ mod tests { Some(f(a.0)) } } + + #[test] + fn test_floatunsisf_conv_zero() { + let r = super::__floatunsisf(0); + assert!(r.eq_repr(0.0f32)); + } + + use std::mem; + + #[test] + fn test_floatunsisf_libcompilerrt() { + let compiler_rt_fn = ::compiler_rt::get("__floatunsisf"); + let compiler_rt_fn : extern fn(u32) -> f32 = unsafe { mem::transmute(compiler_rt_fn) }; + //println!("1231515 {:?}", compiler_rt_fn); + let ans = compiler_rt_fn(0); + println!("{:?}", ans); + assert!(ans.eq_repr(0.0f32)); + + } } From a209a1ee1b754508c0c55f93066e56c672ff7d96 Mon Sep 17 00:00:00 2001 From: Phaiax Date: Sat, 15 Oct 2016 19:01:28 +0200 Subject: [PATCH 3/3] Fix build script syntax --- ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/run.sh b/ci/run.sh index 0159e2389..8716c48c2 100755 --- a/ci/run.sh +++ b/ci/run.sh @@ -62,7 +62,7 @@ case $TRAVIS_OS_NAME in esac # NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it -if [ $TRAVIS_OS_NAME = osx ]; then +if [ "$TRAVIS_OS_NAME" = "osx" ]; then path=target/${1}/debug/libcompiler_builtins.rlib else path=/target/${1}/debug/libcompiler_builtins.rlib