compiler_builtins/float/
conv.rs

1use core::ops::Neg;
2
3use super::Float;
4use crate::int::{CastFrom, CastInto, Int, MinInt};
5
6/// Conversions from integers to floats.
7///
8/// The algorithm is explained here: <https://blog.m-ou.se/floats/>. It roughly does the following:
9/// - Calculate a base mantissa by shifting the integer into mantissa position. This gives us a
10///   mantissa _with the implicit bit set_!
11/// - Figure out if rounding needs to occur by classifying the bits that are to be truncated. Some
12///   patterns are used to simplify this. Adjust the mantissa with the result if needed.
13/// - Calculate the exponent based on the base-2 logarithm of `i` (leading zeros). Subtract one.
14/// - Shift the exponent and add the mantissa to create the final representation. Subtracting one
15///   from the exponent (above) accounts for the explicit bit being set in the mantissa.
16///
17/// # Terminology
18///
19/// - `i`: the original integer
20/// - `i_m`: the integer, shifted fully left (no leading zeros)
21/// - `n`: number of leading zeroes
22/// - `e`: the resulting exponent. Usually 1 is subtracted to offset the mantissa implicit bit.
23/// - `m_base`: the mantissa before adjusting for truncated bits. Implicit bit is usually set.
24/// - `adj`: the bits that will be truncated, possibly compressed in some way.
25/// - `m`: the resulting mantissa. Implicit bit is usually set.
26mod int_to_float {
27    use super::*;
28
29    /// Calculate the exponent from the number of leading zeros.
30    ///
31    /// Usually 1 is subtracted from this function's result, so that a mantissa with the implicit
32    /// bit set can be added back later.
33    fn exp<I: Int, F: Float<Int: CastFrom<u32>>>(n: u32) -> F::Int {
34        F::Int::cast_from(F::EXP_BIAS - 1 + I::BITS - n)
35    }
36
37    /// Adjust a mantissa with dropped bits to perform correct rounding.
38    ///
39    /// The dropped bits should be exactly the bits that get truncated (left-aligned), but they
40    /// can be combined or compressed in some way that simplifies operations.
41    fn m_adj<F: Float>(m_base: F::Int, dropped_bits: F::Int) -> F::Int {
42        // Branchlessly extract a `1` if rounding up should happen, 0 otherwise
43        // This accounts for rounding to even.
44        let adj = (dropped_bits - ((dropped_bits >> (F::BITS - 1)) & !m_base)) >> (F::BITS - 1);
45
46        // Add one when we need to round up. Break ties to even.
47        m_base + adj
48    }
49
50    /// Shift the exponent to its position and add the mantissa.
51    ///
52    /// If the mantissa has the implicit bit set, the exponent should be one less than its actual
53    /// value to cancel it out.
54    fn repr<F: Float>(e: F::Int, m: F::Int) -> F::Int {
55        // + rather than | so the mantissa can overflow into the exponent
56        (e << F::SIG_BITS) + m
57    }
58
59    /// Shift distance from a left-aligned integer to a smaller float.
60    fn shift_f_lt_i<I: Int, F: Float>() -> u32 {
61        (I::BITS - F::BITS) + F::EXP_BITS
62    }
63
64    /// Shift distance from an integer with `n` leading zeros to a smaller float.
65    fn shift_f_gt_i<I: Int, F: Float>(n: u32) -> u32 {
66        F::SIG_BITS - I::BITS + 1 + n
67    }
68
69    /// Perform a signed operation as unsigned, then add the sign back.
70    pub fn signed<I, F, Conv>(i: I, conv: Conv) -> F
71    where
72        F: Float,
73        I: Int,
74        F::Int: CastFrom<I>,
75        Conv: Fn(I::UnsignedInt) -> F::Int,
76    {
77        let sign_bit = F::Int::cast_from(i >> (I::BITS - 1)) << (F::BITS - 1);
78        F::from_bits(conv(i.unsigned_abs()) | sign_bit)
79    }
80
81    pub fn u32_to_f32_bits(i: u32) -> u32 {
82        if i == 0 {
83            return 0;
84        }
85        let n = i.leading_zeros();
86        // Mantissa with implicit bit set (significant bits)
87        let m_base = (i << n) >> f32::EXP_BITS;
88        // Bits that will be dropped (insignificant bits)
89        let adj = (i << n) << (f32::SIG_BITS + 1);
90        let m = m_adj::<f32>(m_base, adj);
91        let e = exp::<u32, f32>(n) - 1;
92        repr::<f32>(e, m)
93    }
94
95    pub fn u32_to_f64_bits(i: u32) -> u64 {
96        if i == 0 {
97            return 0;
98        }
99        let n = i.leading_zeros();
100        // Mantissa with implicit bit set
101        let m = (i as u64) << shift_f_gt_i::<u32, f64>(n);
102        let e = exp::<u32, f64>(n) - 1;
103        repr::<f64>(e, m)
104    }
105
106    #[cfg(f128_enabled)]
107    pub fn u32_to_f128_bits(i: u32) -> u128 {
108        if i == 0 {
109            return 0;
110        }
111        let n = i.leading_zeros();
112
113        // Shift into mantissa position that is correct for the type, but shifted into the lower
114        // 64 bits over so can can avoid 128-bit math.
115        let m = (i as u64) << (shift_f_gt_i::<u32, f128>(n) - 64);
116        let e = exp::<u32, f128>(n) as u64 - 1;
117        // High 64 bits of f128 representation.
118        let h = (e << (f128::SIG_BITS - 64)) + m;
119
120        // Shift back to the high bits, the rest of the mantissa will always be 0.
121        (h as u128) << 64
122    }
123
124    pub fn u64_to_f32_bits(i: u64) -> u32 {
125        let n = i.leading_zeros();
126        let i_m = i.wrapping_shl(n);
127        // Mantissa with implicit bit set
128        let m_base: u32 = (i_m >> shift_f_lt_i::<u64, f32>()) as u32;
129        // The entire lower half of `i` will be truncated (masked portion), plus the
130        // next `EXP_BITS` bits.
131        let adj = ((i_m >> f32::EXP_BITS) | i_m & 0xFFFF) as u32;
132        let m = m_adj::<f32>(m_base, adj);
133        let e = if i == 0 { 0 } else { exp::<u64, f32>(n) - 1 };
134        repr::<f32>(e, m)
135    }
136
137    pub fn u64_to_f64_bits(i: u64) -> u64 {
138        if i == 0 {
139            return 0;
140        }
141        let n = i.leading_zeros();
142        // Mantissa with implicit bit set
143        let m_base = (i << n) >> f64::EXP_BITS;
144        let adj = (i << n) << (f64::SIG_BITS + 1);
145        let m = m_adj::<f64>(m_base, adj);
146        let e = exp::<u64, f64>(n) - 1;
147        repr::<f64>(e, m)
148    }
149
150    #[cfg(f128_enabled)]
151    pub fn u64_to_f128_bits(i: u64) -> u128 {
152        if i == 0 {
153            return 0;
154        }
155        let n = i.leading_zeros();
156        // Mantissa with implicit bit set
157        let m = (i as u128) << shift_f_gt_i::<u64, f128>(n);
158        let e = exp::<u64, f128>(n) - 1;
159        repr::<f128>(e, m)
160    }
161
162    pub fn u128_to_f32_bits(i: u128) -> u32 {
163        let n = i.leading_zeros();
164        let i_m = i.wrapping_shl(n); // Mantissa, shifted so the first bit is nonzero
165        let m_base: u32 = (i_m >> shift_f_lt_i::<u128, f32>()) as u32;
166
167        // Within the upper `F::BITS`, everything except for the signifcand
168        // gets truncated
169        let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast();
170
171        // The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just
172        // check if it is nonzero.
173        let d2: u32 = (i_m << f32::BITS >> f32::BITS != 0).into();
174        let adj = d1 | d2;
175
176        // Mantissa with implicit bit set
177        let m = m_adj::<f32>(m_base, adj);
178        let e = if i == 0 { 0 } else { exp::<u128, f32>(n) - 1 };
179        repr::<f32>(e, m)
180    }
181
182    pub fn u128_to_f64_bits(i: u128) -> u64 {
183        let n = i.leading_zeros();
184        let i_m = i.wrapping_shl(n);
185        // Mantissa with implicit bit set
186        let m_base: u64 = (i_m >> shift_f_lt_i::<u128, f64>()) as u64;
187        // The entire lower half of `i` will be truncated (masked portion), plus the
188        // next `EXP_BITS` bits.
189        let adj = ((i_m >> f64::EXP_BITS) | i_m & 0xFFFF_FFFF) as u64;
190        let m = m_adj::<f64>(m_base, adj);
191        let e = if i == 0 { 0 } else { exp::<u128, f64>(n) - 1 };
192        repr::<f64>(e, m)
193    }
194
195    #[cfg(f128_enabled)]
196    pub fn u128_to_f128_bits(i: u128) -> u128 {
197        if i == 0 {
198            return 0;
199        }
200        let n = i.leading_zeros();
201        // Mantissa with implicit bit set
202        let m_base = (i << n) >> f128::EXP_BITS;
203        let adj = (i << n) << (f128::SIG_BITS + 1);
204        let m = m_adj::<f128>(m_base, adj);
205        let e = exp::<u128, f128>(n) - 1;
206        repr::<f128>(e, m)
207    }
208}
209
210// Conversions from unsigned integers to floats.
211intrinsics! {
212    #[arm_aeabi_alias = __aeabi_ui2f]
213    pub extern "C" fn __floatunsisf(i: u32) -> f32 {
214        f32::from_bits(int_to_float::u32_to_f32_bits(i))
215    }
216
217    #[arm_aeabi_alias = __aeabi_ui2d]
218    pub extern "C" fn __floatunsidf(i: u32) -> f64 {
219        f64::from_bits(int_to_float::u32_to_f64_bits(i))
220    }
221
222    #[arm_aeabi_alias = __aeabi_ul2f]
223    pub extern "C" fn __floatundisf(i: u64) -> f32 {
224        f32::from_bits(int_to_float::u64_to_f32_bits(i))
225    }
226
227    #[arm_aeabi_alias = __aeabi_ul2d]
228    pub extern "C" fn __floatundidf(i: u64) -> f64 {
229        f64::from_bits(int_to_float::u64_to_f64_bits(i))
230    }
231
232    #[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
233    pub extern "C" fn __floatuntisf(i: u128) -> f32 {
234        f32::from_bits(int_to_float::u128_to_f32_bits(i))
235    }
236
237    #[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
238    pub extern "C" fn __floatuntidf(i: u128) -> f64 {
239        f64::from_bits(int_to_float::u128_to_f64_bits(i))
240    }
241
242    #[ppc_alias = __floatunsikf]
243    #[cfg(f128_enabled)]
244    pub extern "C" fn __floatunsitf(i: u32) -> f128 {
245        f128::from_bits(int_to_float::u32_to_f128_bits(i))
246    }
247
248    #[ppc_alias = __floatundikf]
249    #[cfg(f128_enabled)]
250    pub extern "C" fn __floatunditf(i: u64) -> f128 {
251        f128::from_bits(int_to_float::u64_to_f128_bits(i))
252    }
253
254    #[ppc_alias = __floatuntikf]
255    #[cfg(f128_enabled)]
256    pub extern "C" fn __floatuntitf(i: u128) -> f128 {
257        f128::from_bits(int_to_float::u128_to_f128_bits(i))
258    }
259}
260
261// Conversions from signed integers to floats.
262intrinsics! {
263    #[arm_aeabi_alias = __aeabi_i2f]
264    pub extern "C" fn __floatsisf(i: i32) -> f32 {
265        int_to_float::signed(i, int_to_float::u32_to_f32_bits)
266    }
267
268    #[arm_aeabi_alias = __aeabi_i2d]
269    pub extern "C" fn __floatsidf(i: i32) -> f64 {
270        int_to_float::signed(i, int_to_float::u32_to_f64_bits)
271    }
272
273    #[arm_aeabi_alias = __aeabi_l2f]
274    pub extern "C" fn __floatdisf(i: i64) -> f32 {
275        int_to_float::signed(i, int_to_float::u64_to_f32_bits)
276    }
277
278    #[arm_aeabi_alias = __aeabi_l2d]
279    pub extern "C" fn __floatdidf(i: i64) -> f64 {
280        int_to_float::signed(i, int_to_float::u64_to_f64_bits)
281    }
282
283    #[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
284    pub extern "C" fn __floattisf(i: i128) -> f32 {
285        int_to_float::signed(i, int_to_float::u128_to_f32_bits)
286    }
287
288    #[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
289    pub extern "C" fn __floattidf(i: i128) -> f64 {
290        int_to_float::signed(i, int_to_float::u128_to_f64_bits)
291    }
292
293    #[ppc_alias = __floatsikf]
294    #[cfg(f128_enabled)]
295    pub extern "C" fn __floatsitf(i: i32) -> f128 {
296        int_to_float::signed(i, int_to_float::u32_to_f128_bits)
297    }
298
299    #[ppc_alias = __floatdikf]
300    #[cfg(f128_enabled)]
301    pub extern "C" fn __floatditf(i: i64) -> f128 {
302        int_to_float::signed(i, int_to_float::u64_to_f128_bits)
303    }
304
305    #[ppc_alias = __floattikf]
306    #[cfg(f128_enabled)]
307    pub extern "C" fn __floattitf(i: i128) -> f128 {
308        int_to_float::signed(i, int_to_float::u128_to_f128_bits)
309    }
310}
311
312/// Generic float to unsigned int conversions.
313fn float_to_unsigned_int<F, U>(f: F) -> U
314where
315    F: Float,
316    U: Int<UnsignedInt = U>,
317    F::Int: CastInto<U>,
318    F::Int: CastFrom<u32>,
319    F::Int: CastInto<U::UnsignedInt>,
320    u32: CastFrom<F::Int>,
321{
322    float_to_int_inner::<F, U, _, _>(f.to_bits(), |i: U| i, || U::MAX)
323}
324
325/// Generic float to signed int conversions.
326fn float_to_signed_int<F, I>(f: F) -> I
327where
328    F: Float,
329    I: Int + Neg<Output = I>,
330    I::UnsignedInt: Int,
331    F::Int: CastInto<I::UnsignedInt>,
332    F::Int: CastFrom<u32>,
333    u32: CastFrom<F::Int>,
334{
335    float_to_int_inner::<F, I, _, _>(
336        f.to_bits() & !F::SIGN_MASK,
337        |i: I| if f.is_sign_negative() { -i } else { i },
338        || if f.is_sign_negative() { I::MIN } else { I::MAX },
339    )
340}
341
342/// Float to int conversions, generic for both signed and unsigned.
343///
344/// Parameters:
345/// - `fbits`: `abg(f)` bitcasted to an integer.
346/// - `map_inbounds`: apply this transformation to integers that are within range (add the sign back).
347/// - `out_of_bounds`: return value when out of range for `I`.
348fn float_to_int_inner<F, I, FnFoo, FnOob>(
349    fbits: F::Int,
350    map_inbounds: FnFoo,
351    out_of_bounds: FnOob,
352) -> I
353where
354    F: Float,
355    I: Int,
356    FnFoo: FnOnce(I) -> I,
357    FnOob: FnOnce() -> I,
358    I::UnsignedInt: Int,
359    F::Int: CastInto<I::UnsignedInt>,
360    F::Int: CastFrom<u32>,
361    u32: CastFrom<F::Int>,
362{
363    let int_max_exp = F::EXP_BIAS + I::MAX.ilog2() + 1;
364    let foobar = F::EXP_BIAS + I::UnsignedInt::BITS - 1;
365
366    if fbits < F::ONE.to_bits() {
367        // < 0 gets rounded to 0
368        I::ZERO
369    } else if fbits < F::Int::cast_from(int_max_exp) << F::SIG_BITS {
370        // >= 1, < integer max
371        let m_base = if I::UnsignedInt::BITS >= F::Int::BITS {
372            I::UnsignedInt::cast_from(fbits) << (I::BITS - F::SIG_BITS - 1)
373        } else {
374            I::UnsignedInt::cast_from(fbits >> (F::SIG_BITS - I::BITS + 1))
375        };
376
377        // Set the implicit 1-bit.
378        let m: I::UnsignedInt = (I::UnsignedInt::ONE << (I::BITS - 1)) | m_base;
379
380        // Shift based on the exponent and bias.
381        let s: u32 = (foobar) - u32::cast_from(fbits >> F::SIG_BITS);
382
383        let unsigned = m >> s;
384        map_inbounds(I::from_unsigned(unsigned))
385    } else if fbits <= F::EXP_MASK {
386        // >= max (incl. inf)
387        out_of_bounds()
388    } else {
389        I::ZERO
390    }
391}
392
393// Conversions from floats to unsigned integers.
394intrinsics! {
395    #[arm_aeabi_alias = __aeabi_f2uiz]
396    pub extern "C" fn __fixunssfsi(f: f32) -> u32 {
397        float_to_unsigned_int(f)
398    }
399
400    #[arm_aeabi_alias = __aeabi_f2ulz]
401    pub extern "C" fn __fixunssfdi(f: f32) -> u64 {
402        float_to_unsigned_int(f)
403    }
404
405    pub extern "C" fn __fixunssfti(f: f32) -> u128 {
406        float_to_unsigned_int(f)
407    }
408
409    #[arm_aeabi_alias = __aeabi_d2uiz]
410    pub extern "C" fn __fixunsdfsi(f: f64) -> u32 {
411        float_to_unsigned_int(f)
412    }
413
414    #[arm_aeabi_alias = __aeabi_d2ulz]
415    pub extern "C" fn __fixunsdfdi(f: f64) -> u64 {
416        float_to_unsigned_int(f)
417    }
418
419    pub extern "C" fn __fixunsdfti(f: f64) -> u128 {
420        float_to_unsigned_int(f)
421    }
422
423    #[ppc_alias = __fixunskfsi]
424    #[cfg(f128_enabled)]
425    pub extern "C" fn __fixunstfsi(f: f128) -> u32 {
426        float_to_unsigned_int(f)
427    }
428
429    #[ppc_alias = __fixunskfdi]
430    #[cfg(f128_enabled)]
431    pub extern "C" fn __fixunstfdi(f: f128) -> u64 {
432        float_to_unsigned_int(f)
433    }
434
435    #[ppc_alias = __fixunskfti]
436    #[cfg(f128_enabled)]
437    pub extern "C" fn __fixunstfti(f: f128) -> u128 {
438        float_to_unsigned_int(f)
439    }
440}
441
442// Conversions from floats to signed integers.
443intrinsics! {
444    #[arm_aeabi_alias = __aeabi_f2iz]
445    pub extern "C" fn __fixsfsi(f: f32) -> i32 {
446        float_to_signed_int(f)
447    }
448
449    #[arm_aeabi_alias = __aeabi_f2lz]
450    pub extern "C" fn __fixsfdi(f: f32) -> i64 {
451        float_to_signed_int(f)
452    }
453
454    pub extern "C" fn __fixsfti(f: f32) -> i128 {
455        float_to_signed_int(f)
456    }
457
458    #[arm_aeabi_alias = __aeabi_d2iz]
459    pub extern "C" fn __fixdfsi(f: f64) -> i32 {
460        float_to_signed_int(f)
461    }
462
463    #[arm_aeabi_alias = __aeabi_d2lz]
464    pub extern "C" fn __fixdfdi(f: f64) -> i64 {
465        float_to_signed_int(f)
466    }
467
468    pub extern "C" fn __fixdfti(f: f64) -> i128 {
469        float_to_signed_int(f)
470    }
471
472    #[ppc_alias = __fixkfsi]
473    #[cfg(f128_enabled)]
474    pub extern "C" fn __fixtfsi(f: f128) -> i32 {
475        float_to_signed_int(f)
476    }
477
478    #[ppc_alias = __fixkfdi]
479    #[cfg(f128_enabled)]
480    pub extern "C" fn __fixtfdi(f: f128) -> i64 {
481        float_to_signed_int(f)
482    }
483
484    #[ppc_alias = __fixkfti]
485    #[cfg(f128_enabled)]
486    pub extern "C" fn __fixtfti(f: f128) -> i128 {
487        float_to_signed_int(f)
488    }
489}