From 6a33a1cbcf2a68b94320b3ebd0c803440a74d6db Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 15 May 2024 10:08:49 -0500 Subject: [PATCH 1/2] Make conv more generic --- src/float/conv.rs | 119 ++++++++++++++++------------------------ src/int/mod.rs | 15 +++++ testcrate/tests/conv.rs | 4 ++ 3 files changed, 66 insertions(+), 72 deletions(-) diff --git a/src/float/conv.rs b/src/float/conv.rs index 790c0ab9f..f57d5a83a 100644 --- a/src/float/conv.rs +++ b/src/float/conv.rs @@ -1,3 +1,7 @@ +use crate::int::{CastFrom, CastInto, Int, MinInt}; + +use super::Float; + /// Conversions from integers to floats. /// /// These are hand-optimized bit twiddling code, @@ -142,102 +146,73 @@ intrinsics! { } } +fn float_to_unsigned_int(f: F) -> U +where + F: Float, + U: Int, + u32: CastInto, + u32: CastFrom, + F::Int: CastInto, + F::Int: CastFrom, +{ + let uint_max_exp: u32 = F::EXPONENT_BIAS + U::BITS; + 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 { + 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 + } +} + // 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) } } 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, From 4b304db80d41cfee481955b55e2b95834b6e3bac Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 16 May 2024 02:59:50 -0500 Subject: [PATCH 2/2] Make float to signed int generic --- src/float/conv.rs | 135 +++++++++++++++++++--------------------------- src/float/mod.rs | 10 ++-- 2 files changed, 61 insertions(+), 84 deletions(-) diff --git a/src/float/conv.rs b/src/float/conv.rs index f57d5a83a..0179a3175 100644 --- a/src/float/conv.rs +++ b/src/float/conv.rs @@ -1,3 +1,5 @@ +use core::ops::Neg; + use crate::int::{CastFrom, CastInto, Int, MinInt}; use super::Float; @@ -150,12 +152,11 @@ fn float_to_unsigned_int(f: F) -> U where F: Float, U: Int, - u32: CastInto, u32: CastFrom, F::Int: CastInto, F::Int: CastFrom, { - let uint_max_exp: u32 = F::EXPONENT_BIAS + U::BITS; + let uint_max_exp: u32 = F::EXPONENT_BIAS + U::MAX.ilog2() + 1; let fbits = f.repr(); if fbits < F::ONE.repr() { @@ -166,6 +167,7 @@ where 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) }; @@ -183,6 +185,51 @@ where } } +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] @@ -220,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