Skip to content

Commit 1f701b0

Browse files
authored
Merge pull request #613 from tgross35/f16-f128-convert
Add `f128` float to integer conversion functions
2 parents fa0f7e0 + 4edcd5a commit 1f701b0

File tree

9 files changed

+261
-187
lines changed

9 files changed

+261
-187
lines changed

README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,12 @@ These builtins are needed to support `f16` and `f128`, which are in the process
239239
- [x] extendhfsf2.c
240240
- [x] extendhftf2.c
241241
- [x] extendsftf2.c
242-
- [ ] fixtfdi.c
243-
- [ ] fixtfsi.c
244-
- [ ] fixtfti.c
245-
- [ ] fixunstfdi.c
246-
- [ ] fixunstfsi.c
247-
- [ ] fixunstfti.c
242+
- [x] fixtfdi.c
243+
- [x] fixtfsi.c
244+
- [x] fixtfti.c
245+
- [x] fixunstfdi.c
246+
- [x] fixunstfsi.c
247+
- [x] fixunstfti.c
248248
- [ ] floatditf.c
249249
- [ ] floatsitf.c
250250
- [ ] floatunditf.c

build.rs

-10
Original file line numberDiff line numberDiff line change
@@ -533,12 +533,6 @@ mod c {
533533
if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics {
534534
sources.extend(&[
535535
("__comparetf2", "comparetf2.c"),
536-
("__fixtfdi", "fixtfdi.c"),
537-
("__fixtfsi", "fixtfsi.c"),
538-
("__fixtfti", "fixtfti.c"),
539-
("__fixunstfdi", "fixunstfdi.c"),
540-
("__fixunstfsi", "fixunstfsi.c"),
541-
("__fixunstfti", "fixunstfti.c"),
542536
("__floatditf", "floatditf.c"),
543537
("__floatsitf", "floatsitf.c"),
544538
("__floatunditf", "floatunditf.c"),
@@ -561,9 +555,7 @@ mod c {
561555
if target_arch == "mips64" {
562556
sources.extend(&[
563557
("__netf2", "comparetf2.c"),
564-
("__fixtfsi", "fixtfsi.c"),
565558
("__floatsitf", "floatsitf.c"),
566-
("__fixunstfsi", "fixunstfsi.c"),
567559
("__floatunsitf", "floatunsitf.c"),
568560
("__fe_getround", "fp_mode.c"),
569561
]);
@@ -572,9 +564,7 @@ mod c {
572564
if target_arch == "loongarch64" {
573565
sources.extend(&[
574566
("__netf2", "comparetf2.c"),
575-
("__fixtfsi", "fixtfsi.c"),
576567
("__floatsitf", "floatsitf.c"),
577-
("__fixunstfsi", "fixunstfsi.c"),
578568
("__floatunsitf", "floatunsitf.c"),
579569
("__fe_getround", "fp_mode.c"),
580570
]);

src/float/conv.rs

+130-150
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
use core::ops::Neg;
2+
3+
use crate::int::{CastFrom, CastInto, Int, MinInt};
4+
5+
use super::Float;
6+
17
/// Conversions from integers to floats.
28
///
39
/// These are hand-optimized bit twiddling code,
@@ -142,206 +148,180 @@ intrinsics! {
142148
}
143149
}
144150

151+
/// Generic float to unsigned int conversions.
152+
fn float_to_unsigned_int<F, U>(f: F) -> U
153+
where
154+
F: Float,
155+
U: Int<UnsignedInt = U>,
156+
F::Int: CastInto<U>,
157+
F::Int: CastFrom<u32>,
158+
F::Int: CastInto<U::UnsignedInt>,
159+
u32: CastFrom<F::Int>,
160+
{
161+
float_to_int_inner::<F, U, _, _>(f.repr(), |i: U| i, || U::MAX)
162+
}
163+
164+
/// Generic float to signed int conversions.
165+
fn float_to_signed_int<F, I>(f: F) -> I
166+
where
167+
F: Float,
168+
I: Int + Neg<Output = I>,
169+
I::UnsignedInt: Int,
170+
F::Int: CastInto<I::UnsignedInt>,
171+
F::Int: CastFrom<u32>,
172+
u32: CastFrom<F::Int>,
173+
{
174+
float_to_int_inner::<F, I, _, _>(
175+
f.repr() & !F::SIGN_MASK,
176+
|i: I| if f.is_sign_negative() { -i } else { i },
177+
|| if f.is_sign_negative() { I::MIN } else { I::MAX },
178+
)
179+
}
180+
181+
/// Float to int conversions, generic for both signed and unsigned.
182+
///
183+
/// Parameters:
184+
/// - `fbits`: `abg(f)` bitcasted to an integer.
185+
/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign
186+
/// back).
187+
/// - `out_of_bounds`: return value when out of range for `I`.
188+
fn float_to_int_inner<F, I, FnFoo, FnOob>(
189+
fbits: F::Int,
190+
map_inbounds: FnFoo,
191+
out_of_bounds: FnOob,
192+
) -> I
193+
where
194+
F: Float,
195+
I: Int,
196+
FnFoo: FnOnce(I) -> I,
197+
FnOob: FnOnce() -> I,
198+
I::UnsignedInt: Int,
199+
F::Int: CastInto<I::UnsignedInt>,
200+
F::Int: CastFrom<u32>,
201+
u32: CastFrom<F::Int>,
202+
{
203+
let int_max_exp = F::EXPONENT_BIAS + I::MAX.ilog2() + 1;
204+
let foobar = F::EXPONENT_BIAS + I::UnsignedInt::BITS - 1;
205+
206+
if fbits < F::ONE.repr() {
207+
// < 0 gets rounded to 0
208+
I::ZERO
209+
} else if fbits < F::Int::cast_from(int_max_exp) << F::SIGNIFICAND_BITS {
210+
// >= 1, < integer max
211+
let m_base = if I::UnsignedInt::BITS >= F::Int::BITS {
212+
I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIGNIFICAND_BITS - 1)
213+
} else {
214+
I::UnsignedInt::cast_from(fbits >> (F::SIGNIFICAND_BITS - I::BITS + 1))
215+
};
216+
217+
// Set the implicit 1-bit.
218+
let m: I::UnsignedInt = I::UnsignedInt::ONE << (I::BITS - 1) | m_base;
219+
220+
// Shift based on the exponent and bias.
221+
let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIGNIFICAND_BITS);
222+
223+
let unsigned = m >> s;
224+
map_inbounds(I::from_unsigned(unsigned))
225+
} else if fbits <= F::EXPONENT_MASK {
226+
// >= max (incl. inf)
227+
out_of_bounds()
228+
} else {
229+
I::ZERO
230+
}
231+
}
232+
145233
// Conversions from floats to unsigned integers.
146234
intrinsics! {
147235
#[arm_aeabi_alias = __aeabi_f2uiz]
148236
pub extern "C" fn __fixunssfsi(f: f32) -> u32 {
149-
let fbits = f.to_bits();
150-
if fbits < 127 << 23 { // >= 0, < 1
151-
0
152-
} else if fbits < 159 << 23 { // >= 1, < max
153-
let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit.
154-
let s = 158 - (fbits >> 23); // Shift based on the exponent and bias.
155-
m >> s
156-
} else if fbits <= 255 << 23 { // >= max (incl. inf)
157-
u32::MAX
158-
} else { // Negative or NaN
159-
0
160-
}
237+
float_to_unsigned_int(f)
161238
}
162239

163240
#[arm_aeabi_alias = __aeabi_f2ulz]
164241
pub extern "C" fn __fixunssfdi(f: f32) -> u64 {
165-
let fbits = f.to_bits();
166-
if fbits < 127 << 23 { // >= 0, < 1
167-
0
168-
} else if fbits < 191 << 23 { // >= 1, < max
169-
let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit.
170-
let s = 190 - (fbits >> 23); // Shift based on the exponent and bias.
171-
m >> s
172-
} else if fbits <= 255 << 23 { // >= max (incl. inf)
173-
u64::MAX
174-
} else { // Negative or NaN
175-
0
176-
}
242+
float_to_unsigned_int(f)
177243
}
178244

179245
#[win64_128bit_abi_hack]
180246
pub extern "C" fn __fixunssfti(f: f32) -> u128 {
181-
let fbits = f.to_bits();
182-
if fbits < 127 << 23 { // >= 0, < 1
183-
0
184-
} else if fbits < 255 << 23 { // >= 1, < inf
185-
let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit.
186-
let s = 254 - (fbits >> 23); // Shift based on the exponent and bias.
187-
m >> s
188-
} else if fbits == 255 << 23 { // == inf
189-
u128::MAX
190-
} else { // Negative or NaN
191-
0
192-
}
247+
float_to_unsigned_int(f)
193248
}
194249

195250
#[arm_aeabi_alias = __aeabi_d2uiz]
196251
pub extern "C" fn __fixunsdfsi(f: f64) -> u32 {
197-
let fbits = f.to_bits();
198-
if fbits < 1023 << 52 { // >= 0, < 1
199-
0
200-
} else if fbits < 1055 << 52 { // >= 1, < max
201-
let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit.
202-
let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias.
203-
m >> s
204-
} else if fbits <= 2047 << 52 { // >= max (incl. inf)
205-
u32::MAX
206-
} else { // Negative or NaN
207-
0
208-
}
252+
float_to_unsigned_int(f)
209253
}
210254

211255
#[arm_aeabi_alias = __aeabi_d2ulz]
212256
pub extern "C" fn __fixunsdfdi(f: f64) -> u64 {
213-
let fbits = f.to_bits();
214-
if fbits < 1023 << 52 { // >= 0, < 1
215-
0
216-
} else if fbits < 1087 << 52 { // >= 1, < max
217-
let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit.
218-
let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias.
219-
m >> s
220-
} else if fbits <= 2047 << 52 { // >= max (incl. inf)
221-
u64::MAX
222-
} else { // Negative or NaN
223-
0
224-
}
257+
float_to_unsigned_int(f)
225258
}
226259

227260
#[win64_128bit_abi_hack]
228261
pub extern "C" fn __fixunsdfti(f: f64) -> u128 {
229-
let fbits = f.to_bits();
230-
if fbits < 1023 << 52 { // >= 0, < 1
231-
0
232-
} else if fbits < 1151 << 52 { // >= 1, < max
233-
let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit.
234-
let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias.
235-
m >> s
236-
} else if fbits <= 2047 << 52 { // >= max (incl. inf)
237-
u128::MAX
238-
} else { // Negative or NaN
239-
0
240-
}
262+
float_to_unsigned_int(f)
263+
}
264+
265+
#[cfg(not(feature = "no-f16-f128"))]
266+
pub extern "C" fn __fixunstfsi(f: f128) -> u32 {
267+
float_to_unsigned_int(f)
268+
}
269+
270+
#[cfg(not(feature = "no-f16-f128"))]
271+
pub extern "C" fn __fixunstfdi(f: f128) -> u64 {
272+
float_to_unsigned_int(f)
273+
}
274+
275+
#[cfg(not(feature = "no-f16-f128"))]
276+
pub extern "C" fn __fixunstfti(f: f128) -> u128 {
277+
float_to_unsigned_int(f)
241278
}
242279
}
243280

244281
// Conversions from floats to signed integers.
245282
intrinsics! {
246283
#[arm_aeabi_alias = __aeabi_f2iz]
247284
pub extern "C" fn __fixsfsi(f: f32) -> i32 {
248-
let fbits = f.to_bits() & !0 >> 1; // Remove sign bit.
249-
if fbits < 127 << 23 { // >= 0, < 1
250-
0
251-
} else if fbits < 158 << 23 { // >= 1, < max
252-
let m = 1 << 31 | fbits << 8; // Mantissa and the implicit 1-bit.
253-
let s = 158 - (fbits >> 23); // Shift based on the exponent and bias.
254-
let u = (m >> s) as i32; // Unsigned result.
255-
if f.is_sign_negative() { -u } else { u }
256-
} else if fbits <= 255 << 23 { // >= max (incl. inf)
257-
if f.is_sign_negative() { i32::MIN } else { i32::MAX }
258-
} else { // NaN
259-
0
260-
}
285+
float_to_signed_int(f)
261286
}
262287

263288
#[arm_aeabi_alias = __aeabi_f2lz]
264289
pub extern "C" fn __fixsfdi(f: f32) -> i64 {
265-
let fbits = f.to_bits() & !0 >> 1; // Remove sign bit.
266-
if fbits < 127 << 23 { // >= 0, < 1
267-
0
268-
} else if fbits < 190 << 23 { // >= 1, < max
269-
let m = 1 << 63 | (fbits as u64) << 40; // Mantissa and the implicit 1-bit.
270-
let s = 190 - (fbits >> 23); // Shift based on the exponent and bias.
271-
let u = (m >> s) as i64; // Unsigned result.
272-
if f.is_sign_negative() { -u } else { u }
273-
} else if fbits <= 255 << 23 { // >= max (incl. inf)
274-
if f.is_sign_negative() { i64::MIN } else { i64::MAX }
275-
} else { // NaN
276-
0
277-
}
290+
float_to_signed_int(f)
278291
}
279292

280293
#[win64_128bit_abi_hack]
281294
pub extern "C" fn __fixsfti(f: f32) -> i128 {
282-
let fbits = f.to_bits() & !0 >> 1; // Remove sign bit.
283-
if fbits < 127 << 23 { // >= 0, < 1
284-
0
285-
} else if fbits < 254 << 23 { // >= 1, < max
286-
let m = 1 << 127 | (fbits as u128) << 104; // Mantissa and the implicit 1-bit.
287-
let s = 254 - (fbits >> 23); // Shift based on the exponent and bias.
288-
let u = (m >> s) as i128; // Unsigned result.
289-
if f.is_sign_negative() { -u } else { u }
290-
} else if fbits <= 255 << 23 { // >= max (incl. inf)
291-
if f.is_sign_negative() { i128::MIN } else { i128::MAX }
292-
} else { // NaN
293-
0
294-
}
295+
float_to_signed_int(f)
295296
}
296297

297298
#[arm_aeabi_alias = __aeabi_d2iz]
298299
pub extern "C" fn __fixdfsi(f: f64) -> i32 {
299-
let fbits = f.to_bits() & !0 >> 1; // Remove sign bit.
300-
if fbits < 1023 << 52 { // >= 0, < 1
301-
0
302-
} else if fbits < 1054 << 52 { // >= 1, < max
303-
let m = 1 << 31 | (fbits >> 21) as u32; // Mantissa and the implicit 1-bit.
304-
let s = 1054 - (fbits >> 52); // Shift based on the exponent and bias.
305-
let u = (m >> s) as i32; // Unsigned result.
306-
if f.is_sign_negative() { -u } else { u }
307-
} else if fbits <= 2047 << 52 { // >= max (incl. inf)
308-
if f.is_sign_negative() { i32::MIN } else { i32::MAX }
309-
} else { // NaN
310-
0
311-
}
300+
float_to_signed_int(f)
312301
}
313302

314303
#[arm_aeabi_alias = __aeabi_d2lz]
315304
pub extern "C" fn __fixdfdi(f: f64) -> i64 {
316-
let fbits = f.to_bits() & !0 >> 1; // Remove sign bit.
317-
if fbits < 1023 << 52 { // >= 0, < 1
318-
0
319-
} else if fbits < 1086 << 52 { // >= 1, < max
320-
let m = 1 << 63 | fbits << 11; // Mantissa and the implicit 1-bit.
321-
let s = 1086 - (fbits >> 52); // Shift based on the exponent and bias.
322-
let u = (m >> s) as i64; // Unsigned result.
323-
if f.is_sign_negative() { -u } else { u }
324-
} else if fbits <= 2047 << 52 { // >= max (incl. inf)
325-
if f.is_sign_negative() { i64::MIN } else { i64::MAX }
326-
} else { // NaN
327-
0
328-
}
305+
float_to_signed_int(f)
329306
}
330307

331308
#[win64_128bit_abi_hack]
332309
pub extern "C" fn __fixdfti(f: f64) -> i128 {
333-
let fbits = f.to_bits() & !0 >> 1; // Remove sign bit.
334-
if fbits < 1023 << 52 { // >= 0, < 1
335-
0
336-
} else if fbits < 1150 << 52 { // >= 1, < max
337-
let m = 1 << 127 | (fbits as u128) << 75; // Mantissa and the implicit 1-bit.
338-
let s = 1150 - (fbits >> 52); // Shift based on the exponent and bias.
339-
let u = (m >> s) as i128; // Unsigned result.
340-
if f.is_sign_negative() { -u } else { u }
341-
} else if fbits <= 2047 << 52 { // >= max (incl. inf)
342-
if f.is_sign_negative() { i128::MIN } else { i128::MAX }
343-
} else { // NaN
344-
0
345-
}
310+
float_to_signed_int(f)
311+
}
312+
313+
#[cfg(not(feature = "no-f16-f128"))]
314+
pub extern "C" fn __fixtfsi(f: f128) -> i32 {
315+
float_to_signed_int(f)
316+
}
317+
318+
#[cfg(not(feature = "no-f16-f128"))]
319+
pub extern "C" fn __fixtfdi(f: f128) -> i64 {
320+
float_to_signed_int(f)
321+
}
322+
323+
#[cfg(not(feature = "no-f16-f128"))]
324+
pub extern "C" fn __fixtfti(f: f128) -> i128 {
325+
float_to_signed_int(f)
346326
}
347327
}

0 commit comments

Comments
 (0)