compiler_builtins/float/
trunc.rs1use 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 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 abs_result = (a_abs >> sig_bits_delta).cast();
54 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 abs_result += dst_one;
63 } else if round_bits == halfway {
64 abs_result += abs_result & dst_one;
66 };
67 } else if a_abs > src_infinity {
68 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 let dst_inf_exp: R::Int = dst_inf_exp.cast();
80 abs_result = dst_inf_exp << R::SIG_BITS;
81 } else {
82 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 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 if round_bits > halfway {
104 abs_result += dst_one;
105 }
106 else if round_bits == halfway {
108 abs_result += abs_result & dst_one;
109 };
110 }
111 }
112
113 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}