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

Add f128 float to integer conversion functions #613

Merged
merged 5 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,12 +239,12 @@ These builtins are needed to support `f16` and `f128`, which are in the process
- [x] extendhfsf2.c
- [x] extendhftf2.c
- [x] extendsftf2.c
- [ ] fixtfdi.c
- [ ] fixtfsi.c
- [ ] fixtfti.c
- [ ] fixunstfdi.c
- [ ] fixunstfsi.c
- [ ] fixunstfti.c
- [x] fixtfdi.c
- [x] fixtfsi.c
- [x] fixtfti.c
- [x] fixunstfdi.c
- [x] fixunstfsi.c
- [x] fixunstfti.c
- [ ] floatditf.c
- [ ] floatsitf.c
- [ ] floatunditf.c
Expand Down
10 changes: 0 additions & 10 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,12 +533,6 @@ mod c {
if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics {
sources.extend(&[
("__comparetf2", "comparetf2.c"),
("__fixtfdi", "fixtfdi.c"),
("__fixtfsi", "fixtfsi.c"),
("__fixtfti", "fixtfti.c"),
("__fixunstfdi", "fixunstfdi.c"),
("__fixunstfsi", "fixunstfsi.c"),
("__fixunstfti", "fixunstfti.c"),
("__floatditf", "floatditf.c"),
("__floatsitf", "floatsitf.c"),
("__floatunditf", "floatunditf.c"),
Expand All @@ -561,9 +555,7 @@ mod c {
if target_arch == "mips64" {
sources.extend(&[
("__netf2", "comparetf2.c"),
("__fixtfsi", "fixtfsi.c"),
("__floatsitf", "floatsitf.c"),
("__fixunstfsi", "fixunstfsi.c"),
("__floatunsitf", "floatunsitf.c"),
("__fe_getround", "fp_mode.c"),
]);
Expand All @@ -572,9 +564,7 @@ mod c {
if target_arch == "loongarch64" {
sources.extend(&[
("__netf2", "comparetf2.c"),
("__fixtfsi", "fixtfsi.c"),
("__floatsitf", "floatsitf.c"),
("__fixunstfsi", "fixunstfsi.c"),
("__floatunsitf", "floatunsitf.c"),
("__fe_getround", "fp_mode.c"),
]);
Expand Down
280 changes: 130 additions & 150 deletions src/float/conv.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -142,206 +148,180 @@ intrinsics! {
}
}

/// Generic float to unsigned int conversions.
fn float_to_unsigned_int<F, U>(f: F) -> U
where
F: Float,
U: Int<UnsignedInt = U>,
F::Int: CastInto<U>,
F::Int: CastFrom<u32>,
F::Int: CastInto<U::UnsignedInt>,
u32: CastFrom<F::Int>,
{
float_to_int_inner::<F, U, _, _>(f.repr(), |i: U| i, || U::MAX)
}

/// Generic float to signed int conversions.
fn float_to_signed_int<F, I>(f: F) -> I
where
F: Float,
I: Int + Neg<Output = I>,
I::UnsignedInt: Int,
F::Int: CastInto<I::UnsignedInt>,
F::Int: CastFrom<u32>,
u32: CastFrom<F::Int>,
{
float_to_int_inner::<F, I, _, _>(
f.repr() & !F::SIGN_MASK,
|i: I| if f.is_sign_negative() { -i } else { i },
|| if f.is_sign_negative() { I::MIN } else { I::MAX },
)
}

/// Float to int conversions, generic for both signed and unsigned.
///
/// Parameters:
/// - `fbits`: `abg(f)` bitcasted to an integer.
/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign
/// back).
/// - `out_of_bounds`: return value when out of range for `I`.
fn float_to_int_inner<F, I, FnFoo, FnOob>(
fbits: F::Int,
map_inbounds: FnFoo,
out_of_bounds: FnOob,
) -> I
where
F: Float,
I: Int,
FnFoo: FnOnce(I) -> I,
FnOob: FnOnce() -> I,
I::UnsignedInt: Int,
F::Int: CastInto<I::UnsignedInt>,
F::Int: CastFrom<u32>,
u32: CastFrom<F::Int>,
{
let int_max_exp = F::EXPONENT_BIAS + I::MAX.ilog2() + 1;
let foobar = F::EXPONENT_BIAS + I::UnsignedInt::BITS - 1;

if fbits < F::ONE.repr() {
// < 0 gets rounded to 0
I::ZERO
} else if fbits < F::Int::cast_from(int_max_exp) << F::SIGNIFICAND_BITS {
// >= 1, < integer max
let m_base = if I::UnsignedInt::BITS >= F::Int::BITS {
I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIGNIFICAND_BITS - 1)
} else {
I::UnsignedInt::cast_from(fbits >> (F::SIGNIFICAND_BITS - I::BITS + 1))
};

// Set the implicit 1-bit.
let m: I::UnsignedInt = I::UnsignedInt::ONE << (I::BITS - 1) | m_base;

// Shift based on the exponent and bias.
let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIGNIFICAND_BITS);

let unsigned = m >> s;
map_inbounds(I::from_unsigned(unsigned))
} else if fbits <= F::EXPONENT_MASK {
// >= max (incl. inf)
out_of_bounds()
} 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)
}

#[cfg(not(feature = "no-f16-f128"))]
pub extern "C" fn __fixunstfsi(f: f128) -> u32 {
float_to_unsigned_int(f)
}

#[cfg(not(feature = "no-f16-f128"))]
pub extern "C" fn __fixunstfdi(f: f128) -> u64 {
float_to_unsigned_int(f)
}

#[cfg(not(feature = "no-f16-f128"))]
pub extern "C" fn __fixunstfti(f: f128) -> u128 {
float_to_unsigned_int(f)
}
}

// Conversions from floats to signed integers.
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)
}

#[cfg(not(feature = "no-f16-f128"))]
pub extern "C" fn __fixtfsi(f: f128) -> i32 {
float_to_signed_int(f)
}

#[cfg(not(feature = "no-f16-f128"))]
pub extern "C" fn __fixtfdi(f: f128) -> i64 {
float_to_signed_int(f)
}

#[cfg(not(feature = "no-f16-f128"))]
pub extern "C" fn __fixtfti(f: f128) -> i128 {
float_to_signed_int(f)
}
}
Loading