diff --git a/src/float/conv.rs b/src/float/conv.rs index 790c0ab9f..0179a3175 100644 --- a/src/float/conv.rs +++ b/src/float/conv.rs @@ -1,3 +1,9 @@ +use core::ops::Neg; + +use crate::int::{CastFrom, CastInto, Int, MinInt}; + +use super::Float; + /// Conversions from integers to floats. /// /// These are hand-optimized bit twiddling code, @@ -142,102 +148,118 @@ intrinsics! { } } +fn float_to_unsigned_int(f: F) -> U +where + F: Float, + U: Int, + u32: CastFrom, + F::Int: CastInto, + F::Int: CastFrom, +{ + let uint_max_exp: u32 = F::EXPONENT_BIAS + U::MAX.ilog2() + 1; + let fbits = f.repr(); + + if fbits < F::ONE.repr() { + // >= 0.0, < 1.0 (< 0.0 are > 1.0 in int repr) + U::ZERO + } else if fbits < F::Int::cast_from(uint_max_exp) << F::SIGNIFICAND_BITS { + // >= 1, < U::max + let mantissa = if U::BITS >= F::Int::BITS { + U::cast_from(fbits) << (U::BITS - F::SIGNIFICAND_BITS - 1) + } else { + // FIXME magic number for when we go smaller + U::cast_from(fbits >> 21) + }; + + // Set the implicit 1-bit. + let m: U = U::ONE << (U::BITS - 1) | mantissa; + // Shift based on the exponent and bias. + let s: u32 = (uint_max_exp - 1) - u32::cast_from(fbits >> F::SIGNIFICAND_BITS); + + m >> s + } else if fbits <= F::EXPONENT_MASK { + // >= max (incl. inf) + U::MAX + } else { + U::ZERO + } +} + +fn float_to_signed_int(f: F) -> I +where + F: Float, + I: Int + Neg, + I::UnsignedInt: Int, + u32: CastFrom, + F::Int: CastInto, + F::Int: CastFrom, +{ + let int_max_exp: u32 = F::EXPONENT_BIAS + I::MAX.ilog2() + 1; + let fbits = f.repr() & !F::SIGN_MASK; + + if fbits < F::ONE.repr() { + // >= 0.0, < 1.0 (< 0.0 are > 1.0 in int repr) + I::ZERO + } else if fbits < F::Int::cast_from(int_max_exp) << F::SIGNIFICAND_BITS { + // >= 1, < U::max + let mantissa = if I::BITS >= F::Int::BITS { + I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIGNIFICAND_BITS - 1) + } else { + I::UnsignedInt::cast_from(fbits >> 21) + }; + + // Set the implicit 1-bit. + let m: I::UnsignedInt = I::UnsignedInt::ONE << (I::BITS - 1) | mantissa; + // Shift based on the exponent and bias. + let s: u32 = int_max_exp - u32::cast_from(fbits >> F::SIGNIFICAND_BITS); + let u: I = I::from_unsigned(m >> s); + if f.is_sign_negative() { + -u + } else { + u + } + } else if fbits <= F::EXPONENT_MASK { + // >= max (incl. inf) + if f.is_sign_negative() { + I::MIN + } else { + I::MAX + } + } else { + I::ZERO + } +} + // Conversions from floats to unsigned integers. intrinsics! { #[arm_aeabi_alias = __aeabi_f2uiz] pub extern "C" fn __fixunssfsi(f: f32) -> u32 { - let fbits = f.to_bits(); - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 159 << 23 { // >= 1, < max - let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit. - let s = 158 - (fbits >> 23); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 255 << 23 { // >= max (incl. inf) - u32::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[arm_aeabi_alias = __aeabi_f2ulz] pub extern "C" fn __fixunssfdi(f: f32) -> u64 { - let fbits = f.to_bits(); - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 191 << 23 { // >= 1, < max - let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit. - let s = 190 - (fbits >> 23); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 255 << 23 { // >= max (incl. inf) - u64::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixunssfti(f: f32) -> u128 { - let fbits = f.to_bits(); - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 255 << 23 { // >= 1, < inf - let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit. - let s = 254 - (fbits >> 23); // Shift based on the exponent and bias. - m >> s - } else if fbits == 255 << 23 { // == inf - u128::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[arm_aeabi_alias = __aeabi_d2uiz] pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { - let fbits = f.to_bits(); - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1055 << 52 { // >= 1, < max - let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit. - let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - u32::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[arm_aeabi_alias = __aeabi_d2ulz] pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { - let fbits = f.to_bits(); - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1087 << 52 { // >= 1, < max - let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit. - let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - u64::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixunsdfti(f: f64) -> u128 { - let fbits = f.to_bits(); - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1151 << 52 { // >= 1, < max - let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit. - let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias. - m >> s - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - u128::MAX - } else { // Negative or NaN - 0 - } + float_to_unsigned_int(f) } } @@ -245,103 +267,31 @@ intrinsics! { intrinsics! { #[arm_aeabi_alias = __aeabi_f2iz] pub extern "C" fn __fixsfsi(f: f32) -> i32 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 158 << 23 { // >= 1, < max - let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit. - let s = 158 - (fbits >> 23); // Shift based on the exponent and bias. - let u = (m >> s) as i32; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 255 << 23 { // >= max (incl. inf) - if f.is_sign_negative() { i32::MIN } else { i32::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[arm_aeabi_alias = __aeabi_f2lz] pub extern "C" fn __fixsfdi(f: f32) -> i64 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 190 << 23 { // >= 1, < max - let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit. - let s = 190 - (fbits >> 23); // Shift based on the exponent and bias. - let u = (m >> s) as i64; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 255 << 23 { // >= max (incl. inf) - if f.is_sign_negative() { i64::MIN } else { i64::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixsfti(f: f32) -> i128 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 127 << 23 { // >= 0, < 1 - 0 - } else if fbits < 254 << 23 { // >= 1, < max - let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit. - let s = 254 - (fbits >> 23); // Shift based on the exponent and bias. - let u = (m >> s) as i128; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 255 << 23 { // >= max (incl. inf) - if f.is_sign_negative() { i128::MIN } else { i128::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[arm_aeabi_alias = __aeabi_d2iz] pub extern "C" fn __fixdfsi(f: f64) -> i32 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1054 << 52 { // >= 1, < max - let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit. - let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias. - let u = (m >> s) as i32; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - if f.is_sign_negative() { i32::MIN } else { i32::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[arm_aeabi_alias = __aeabi_d2lz] pub extern "C" fn __fixdfdi(f: f64) -> i64 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1086 << 52 { // >= 1, < max - let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit. - let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias. - let u = (m >> s) as i64; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - if f.is_sign_negative() { i64::MIN } else { i64::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } #[win64_128bit_abi_hack] pub extern "C" fn __fixdfti(f: f64) -> i128 { - let fbits = f.to_bits() & !0 >> 1; // Remove sign bit. - if fbits < 1023 << 52 { // >= 0, < 1 - 0 - } else if fbits < 1150 << 52 { // >= 1, < max - let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit. - let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias. - let u = (m >> s) as i128; // Unsigned result. - if f.is_sign_negative() { -u } else { u } - } else if fbits <= 2047 << 52 { // >= max (incl. inf) - if f.is_sign_negative() { i128::MIN } else { i128::MAX } - } else { // NaN - 0 - } + float_to_signed_int(f) } } diff --git a/src/float/mod.rs b/src/float/mod.rs index e62a3fe0f..de32c31ad 100644 --- a/src/float/mod.rs +++ b/src/float/mod.rs @@ -80,8 +80,8 @@ pub(crate) trait Float: /// compared. fn eq_repr(self, rhs: Self) -> bool; - /// Returns the sign bit - fn sign(self) -> bool; + /// Returns true if the sign is negative + fn is_sign_negative(self) -> bool; /// Returns the exponent with bias fn exp(self) -> Self::ExpInt; @@ -103,6 +103,8 @@ pub(crate) trait Float: /// Returns if `self` is subnormal fn is_subnormal(self) -> bool; + + } } @@ -150,8 +152,8 @@ macro_rules! float_impl { self.repr() == rhs.repr() } } - fn sign(self) -> bool { - self.signed_repr() < Self::SignedInt::ZERO + fn is_sign_negative(self) -> bool { + self.is_sign_negative() } fn exp(self) -> Self::ExpInt { ((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt diff --git a/src/int/mod.rs b/src/int/mod.rs index 2b6d4b812..45d383880 100644 --- a/src/int/mod.rs +++ b/src/int/mod.rs @@ -102,6 +102,7 @@ pub(crate) trait Int: MinInt fn rotate_left(self, other: u32) -> Self; fn overflowing_add(self, other: Self) -> (Self, bool); fn leading_zeros(self) -> u32; + fn ilog2(self) -> u32; } } @@ -200,6 +201,10 @@ macro_rules! int_impl_common { fn leading_zeros(self) -> u32 { ::leading_zeros(self) } + + fn ilog2(self) -> u32 { + ::ilog2(self) + } }; } @@ -380,6 +385,16 @@ public_test_dep! { pub(crate) trait CastInto: Copy { fn cast(self) -> T; } + +pub(crate) trait CastFrom:Copy { + fn cast_from(value: T) -> Self; +} +} + +impl + Copy> CastFrom for T { + fn cast_from(value: U) -> Self { + value.cast() + } } macro_rules! cast_into { diff --git a/testcrate/tests/conv.rs b/testcrate/tests/conv.rs index f0ef95255..d661bfbd7 100644 --- a/testcrate/tests/conv.rs +++ b/testcrate/tests/conv.rs @@ -118,6 +118,10 @@ fn float_to_int() { __fixdfdi, __fixdfsi, __fixdfti, __fixsfdi, __fixsfsi, __fixsfti, __fixunsdfdi, __fixunsdfsi, __fixunsdfti, __fixunssfdi, __fixunssfsi, __fixunssfti, }; + println!("bias {}", f32::EXPONENT_BIAS); + println!("bits {}", f32::SIGNIFICAND_BITS); + println!("bias {}", f64::EXPONENT_BIAS); + println!("bits {}", f64::SIGNIFICAND_BITS); fuzz_float(N, |x: f32| { f_to_i!(x,