compiler_builtins/float/
trunc.rs

1use crate::float::Float;
2use crate::int::{CastInto, Int, MinInt};
3
4fn trunc<F: Float, R: Float>(a: F) -> R
5where
6    F::Int: CastInto<u64>,
7    F::Int: CastInto<u32>,
8    u64: CastInto<F::Int>,
9    u32: CastInto<F::Int>,
10    R::Int: CastInto<u32>,
11    u32: CastInto<R::Int>,
12    F::Int: CastInto<R::Int>,
13{
14    let src_zero = F::Int::ZERO;
15    let src_one = F::Int::ONE;
16    let src_bits = F::BITS;
17    let src_exp_bias = F::EXP_BIAS;
18
19    let src_min_normal = F::IMPLICIT_BIT;
20    let src_sig_mask = F::SIG_MASK;
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 round_mask = (src_one << (F::SIG_BITS - R::SIG_BITS)) - src_one;
25    let halfway = src_one << (F::SIG_BITS - R::SIG_BITS - 1);
26    let src_qnan = src_one << (F::SIG_BITS - 1);
27    let src_nan_code = src_qnan - src_one;
28
29    let dst_zero = R::Int::ZERO;
30    let dst_one = R::Int::ONE;
31    let dst_bits = R::BITS;
32    let dst_inf_exp = R::EXP_SAT;
33    let dst_exp_bias = R::EXP_BIAS;
34
35    let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast();
36    let overflow_exponent: F::Int = (src_exp_bias + dst_inf_exp - dst_exp_bias).cast();
37    let underflow: F::Int = underflow_exponent << F::SIG_BITS;
38    let overflow: F::Int = overflow_exponent << F::SIG_BITS;
39
40    let dst_qnan = R::Int::ONE << (R::SIG_BITS - 1);
41    let dst_nan_code = dst_qnan - dst_one;
42
43    let sig_bits_delta = F::SIG_BITS - R::SIG_BITS;
44    // Break a into a sign and representation of the absolute value.
45    let a_abs = a.to_bits() & src_abs_mask;
46    let sign = a.to_bits() & src_sign_mask;
47    let mut abs_result: R::Int;
48
49    if a_abs.wrapping_sub(underflow) < a_abs.wrapping_sub(overflow) {
50        // The exponent of a is within the range of normal numbers in the
51        // destination format.  We can convert by simply right-shifting with
52        // rounding and adjusting the exponent.
53        abs_result = (a_abs >> sig_bits_delta).cast();
54        // Cast before shifting to prevent overflow.
55        let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast();
56        let tmp = bias_diff << R::SIG_BITS;
57        abs_result = abs_result.wrapping_sub(tmp);
58
59        let round_bits = a_abs & round_mask;
60        if round_bits > halfway {
61            // Round to nearest.
62            abs_result += dst_one;
63        } else if round_bits == halfway {
64            // Tie to even.
65            abs_result += abs_result & dst_one;
66        };
67    } else if a_abs > src_infinity {
68        // a is NaN.
69        // Conjure the result by beginning with infinity, setting the qNaN
70        // bit and inserting the (truncated) trailing NaN field.
71        // Cast before shifting to prevent overflow.
72        let dst_inf_exp: R::Int = dst_inf_exp.cast();
73        abs_result = dst_inf_exp << R::SIG_BITS;
74        abs_result |= dst_qnan;
75        abs_result |= dst_nan_code & ((a_abs & src_nan_code) >> (F::SIG_BITS - R::SIG_BITS)).cast();
76    } else if a_abs >= overflow {
77        // a overflows to infinity.
78        // Cast before shifting to prevent overflow.
79        let dst_inf_exp: R::Int = dst_inf_exp.cast();
80        abs_result = dst_inf_exp << R::SIG_BITS;
81    } else {
82        // a underflows on conversion to the destination type or is an exact
83        // zero.  The result may be a denormal or zero.  Extract the exponent
84        // to get the shift amount for the denormalization.
85        let a_exp: u32 = (a_abs >> F::SIG_BITS).cast();
86        let shift = src_exp_bias - dst_exp_bias - a_exp + 1;
87
88        let significand = (a.to_bits() & src_sig_mask) | src_min_normal;
89
90        // Right shift by the denormalization amount with sticky.
91        if shift > F::SIG_BITS {
92            abs_result = dst_zero;
93        } else {
94            let sticky = if (significand << (src_bits - shift)) != src_zero {
95                src_one
96            } else {
97                src_zero
98            };
99            let denormalized_significand: F::Int = (significand >> shift) | sticky;
100            abs_result = (denormalized_significand >> (F::SIG_BITS - R::SIG_BITS)).cast();
101            let round_bits = denormalized_significand & round_mask;
102            // Round to nearest
103            if round_bits > halfway {
104                abs_result += dst_one;
105            }
106            // Ties to even
107            else if round_bits == halfway {
108                abs_result += abs_result & dst_one;
109            };
110        }
111    }
112
113    // Apply the signbit to the absolute value.
114    R::from_bits(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast())
115}
116
117intrinsics! {
118    #[aapcs_on_arm]
119    #[arm_aeabi_alias = __aeabi_d2f]
120    pub extern "C" fn __truncdfsf2(a: f64) -> f32 {
121        trunc(a)
122    }
123}
124
125intrinsics! {
126    #[aapcs_on_arm]
127    #[apple_f16_ret_abi]
128    #[arm_aeabi_alias = __aeabi_f2h]
129    #[cfg(f16_enabled)]
130    pub extern "C" fn __truncsfhf2(a: f32) -> f16 {
131        trunc(a)
132    }
133
134    #[aapcs_on_arm]
135    #[apple_f16_ret_abi]
136    #[cfg(f16_enabled)]
137    pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 {
138        trunc(a)
139    }
140
141    #[aapcs_on_arm]
142    #[apple_f16_ret_abi]
143    #[arm_aeabi_alias = __aeabi_d2h]
144    #[cfg(f16_enabled)]
145    pub extern "C" fn __truncdfhf2(a: f64) -> f16 {
146        trunc(a)
147    }
148
149    #[aapcs_on_arm]
150    #[ppc_alias = __trunckfhf2]
151    #[cfg(all(f16_enabled, f128_enabled))]
152    pub extern "C" fn __trunctfhf2(a: f128) -> f16 {
153        trunc(a)
154    }
155
156    #[aapcs_on_arm]
157    #[ppc_alias = __trunckfsf2]
158    #[cfg(f128_enabled)]
159    pub extern "C" fn __trunctfsf2(a: f128) -> f32 {
160        trunc(a)
161    }
162
163    #[aapcs_on_arm]
164    #[ppc_alias = __trunckfdf2]
165    #[cfg(f128_enabled)]
166    pub extern "C" fn __trunctfdf2(a: f128) -> f64 {
167        trunc(a)
168    }
169}