compiler_builtins/float/
extend.rs

1use crate::float::Float;
2use crate::int::{CastInto, Int, MinInt};
3
4/// Generic conversion from a narrower to a wider IEEE-754 floating-point type
5fn extend<F: Float, R: Float>(a: F) -> R
6where
7    F::Int: CastInto<u64>,
8    u64: CastInto<F::Int>,
9    u32: CastInto<R::Int>,
10    R::Int: CastInto<u32>,
11    R::Int: CastInto<u64>,
12    u64: CastInto<R::Int>,
13    F::Int: CastInto<R::Int>,
14{
15    let src_zero = F::Int::ZERO;
16    let src_one = F::Int::ONE;
17    let src_bits = F::BITS;
18    let src_sig_bits = F::SIG_BITS;
19    let src_exp_bias = F::EXP_BIAS;
20    let src_min_normal = F::IMPLICIT_BIT;
21    let src_infinity = F::EXP_MASK;
22    let src_sign_mask = F::SIGN_MASK;
23    let src_abs_mask = src_sign_mask - src_one;
24    let src_qnan = F::SIG_MASK;
25    let src_nan_code = src_qnan - src_one;
26
27    let dst_bits = R::BITS;
28    let dst_sig_bits = R::SIG_BITS;
29    let dst_inf_exp = R::EXP_SAT;
30    let dst_exp_bias = R::EXP_BIAS;
31    let dst_min_normal = R::IMPLICIT_BIT;
32
33    let sig_bits_delta = dst_sig_bits - src_sig_bits;
34    let exp_bias_delta = dst_exp_bias - src_exp_bias;
35    let a_abs = a.to_bits() & src_abs_mask;
36    let mut abs_result = R::Int::ZERO;
37
38    if a_abs.wrapping_sub(src_min_normal) < src_infinity.wrapping_sub(src_min_normal) {
39        // a is a normal number.
40        // Extend to the destination type by shifting the significand and
41        // exponent into the proper position and rebiasing the exponent.
42        let abs_dst: R::Int = a_abs.cast();
43        let bias_dst: R::Int = exp_bias_delta.cast();
44        abs_result = abs_dst.wrapping_shl(sig_bits_delta);
45        abs_result += bias_dst.wrapping_shl(dst_sig_bits);
46    } else if a_abs >= src_infinity {
47        // a is NaN or infinity.
48        // Conjure the result by beginning with infinity, then setting the qNaN
49        // bit (if needed) and right-aligning the rest of the trailing NaN
50        // payload field.
51        let qnan_dst: R::Int = (a_abs & src_qnan).cast();
52        let nan_code_dst: R::Int = (a_abs & src_nan_code).cast();
53        let inf_exp_dst: R::Int = dst_inf_exp.cast();
54        abs_result = inf_exp_dst.wrapping_shl(dst_sig_bits);
55        abs_result |= qnan_dst.wrapping_shl(sig_bits_delta);
56        abs_result |= nan_code_dst.wrapping_shl(sig_bits_delta);
57    } else if a_abs != src_zero {
58        // a is denormal.
59        // Renormalize the significand and clear the leading bit, then insert
60        // the correct adjusted exponent in the destination type.
61        let scale = a_abs.leading_zeros() - src_min_normal.leading_zeros();
62        let abs_dst: R::Int = a_abs.cast();
63        let bias_dst: R::Int = (exp_bias_delta - scale + 1).cast();
64        abs_result = abs_dst.wrapping_shl(sig_bits_delta + scale);
65        abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sig_bits));
66    }
67
68    let sign_result: R::Int = (a.to_bits() & src_sign_mask).cast();
69    R::from_bits(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits)))
70}
71
72intrinsics! {
73    #[aapcs_on_arm]
74    #[arm_aeabi_alias = __aeabi_f2d]
75    pub extern "C" fn  __extendsfdf2(a: f32) -> f64 {
76        extend(a)
77    }
78}
79
80intrinsics! {
81    #[aapcs_on_arm]
82    #[apple_f16_arg_abi]
83    #[arm_aeabi_alias = __aeabi_h2f]
84    #[cfg(f16_enabled)]
85    pub extern "C" fn __extendhfsf2(a: f16) -> f32 {
86        extend(a)
87    }
88
89    #[aapcs_on_arm]
90    #[apple_f16_arg_abi]
91    #[cfg(f16_enabled)]
92    pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 {
93        extend(a)
94    }
95
96    #[aapcs_on_arm]
97    #[apple_f16_arg_abi]
98    #[cfg(f16_enabled)]
99    pub extern "C" fn __extendhfdf2(a: f16) -> f64 {
100        extend(a)
101    }
102
103    #[aapcs_on_arm]
104    #[ppc_alias = __extendhfkf2]
105    #[cfg(all(f16_enabled, f128_enabled))]
106    pub extern "C" fn __extendhftf2(a: f16) -> f128 {
107        extend(a)
108    }
109
110    #[aapcs_on_arm]
111    #[ppc_alias = __extendsfkf2]
112    #[cfg(f128_enabled)]
113    pub extern "C" fn __extendsftf2(a: f32) -> f128 {
114        extend(a)
115    }
116
117    #[aapcs_on_arm]
118    #[ppc_alias = __extenddfkf2]
119    #[cfg(f128_enabled)]
120    pub extern "C" fn __extenddftf2(a: f64) -> f128 {
121        extend(a)
122    }
123}