Skip to content

Commit 8da74d7

Browse files
committed
Make float to integer conversions generic
Deduplicate code used for float to integer conversions in order to make adding `f128` conversion functions easier.
1 parent 1806898 commit 8da74d7

File tree

3 files changed

+109
-154
lines changed

3 files changed

+109
-154
lines changed

src/float/conv.rs

Lines changed: 100 additions & 150 deletions
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,150 @@ 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)
241263
}
242264
}
243265

244266
// Conversions from floats to signed integers.
245267
intrinsics! {
246268
#[arm_aeabi_alias = __aeabi_f2iz]
247269
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-
}
270+
float_to_signed_int(f)
261271
}
262272

263273
#[arm_aeabi_alias = __aeabi_f2lz]
264274
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-
}
275+
float_to_signed_int(f)
278276
}
279277

280278
#[win64_128bit_abi_hack]
281279
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-
}
280+
float_to_signed_int(f)
295281
}
296282

297283
#[arm_aeabi_alias = __aeabi_d2iz]
298284
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-
}
285+
float_to_signed_int(f)
312286
}
313287

314288
#[arm_aeabi_alias = __aeabi_d2lz]
315289
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-
}
290+
float_to_signed_int(f)
329291
}
330292

331293
#[win64_128bit_abi_hack]
332294
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-
}
295+
float_to_signed_int(f)
346296
}
347297
}

src/float/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ pub(crate) trait Float:
8080
/// compared.
8181
fn eq_repr(self, rhs: Self) -> bool;
8282

83-
/// Returns the sign bit
84-
fn sign(self) -> bool;
83+
/// Returns true if the sign is negative
84+
fn is_sign_negative(self) -> bool;
8585

8686
/// Returns the exponent with bias
8787
fn exp(self) -> Self::ExpInt;
@@ -150,8 +150,8 @@ macro_rules! float_impl {
150150
self.repr() == rhs.repr()
151151
}
152152
}
153-
fn sign(self) -> bool {
154-
self.signed_repr() < Self::SignedInt::ZERO
153+
fn is_sign_negative(self) -> bool {
154+
self.is_sign_negative()
155155
}
156156
fn exp(self) -> Self::ExpInt {
157157
((self.to_bits() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS) as Self::ExpInt

src/int/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ pub(crate) trait Int: MinInt
102102
fn rotate_left(self, other: u32) -> Self;
103103
fn overflowing_add(self, other: Self) -> (Self, bool);
104104
fn leading_zeros(self) -> u32;
105+
fn ilog2(self) -> u32;
105106
}
106107
}
107108

@@ -200,6 +201,10 @@ macro_rules! int_impl_common {
200201
fn leading_zeros(self) -> u32 {
201202
<Self>::leading_zeros(self)
202203
}
204+
205+
fn ilog2(self) -> u32 {
206+
<Self>::ilog2(self)
207+
}
203208
};
204209
}
205210

0 commit comments

Comments
 (0)