]>
Commit | Line | Data |
---|---|---|
041b39d2 XL |
1 | use float::Float; |
2 | use int::Int; | |
3 | ||
4 | macro_rules! int_to_float { | |
48663c56 | 5 | ($i:expr, $ity:ty, $fty:ty) => {{ |
041b39d2 XL |
6 | let i = $i; |
7 | if i == 0 { | |
48663c56 | 8 | return 0.0; |
041b39d2 XL |
9 | } |
10 | ||
ea8adc8c XL |
11 | let mant_dig = <$fty>::SIGNIFICAND_BITS + 1; |
12 | let exponent_bias = <$fty>::EXPONENT_BIAS; | |
041b39d2 | 13 | |
5869c6ff | 14 | let n = <$ity as Int>::BITS; |
041b39d2 XL |
15 | let (s, a) = i.extract_sign(); |
16 | let mut a = a; | |
17 | ||
18 | // number of significant digits | |
19 | let sd = n - a.leading_zeros(); | |
20 | ||
21 | // exponent | |
22 | let mut e = sd - 1; | |
23 | ||
5869c6ff | 24 | if <$ity as Int>::BITS < mant_dig { |
48663c56 XL |
25 | return <$fty>::from_parts( |
26 | s, | |
041b39d2 | 27 | (e + exponent_bias) as <$fty as Float>::Int, |
48663c56 XL |
28 | (a as <$fty as Float>::Int) << (mant_dig - e - 1), |
29 | ); | |
041b39d2 XL |
30 | } |
31 | ||
32 | a = if sd > mant_dig { | |
33 | /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx | |
48663c56 XL |
34 | * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR |
35 | * 12345678901234567890123456 | |
36 | * 1 = msb 1 bit | |
37 | * P = bit MANT_DIG-1 bits to the right of 1 | |
38 | * Q = bit MANT_DIG bits to the right of 1 | |
39 | * R = "or" of all bits to the right of Q | |
40 | */ | |
041b39d2 XL |
41 | let mant_dig_plus_one = mant_dig + 1; |
42 | let mant_dig_plus_two = mant_dig + 2; | |
43 | a = if sd == mant_dig_plus_one { | |
44 | a << 1 | |
45 | } else if sd == mant_dig_plus_two { | |
46 | a | |
47 | } else { | |
48663c56 XL |
48 | (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt |
49 | | ((a & <$ity as Int>::UnsignedInt::max_value()) | |
50 | .wrapping_shl((n + mant_dig_plus_two) - sd) | |
51 | != 0) as <$ity as Int>::UnsignedInt | |
041b39d2 XL |
52 | }; |
53 | ||
54 | /* finish: */ | |
55 | a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */ | |
56 | a += 1; /* round - this step may add a significant bit */ | |
57 | a >>= 2; /* dump Q and R */ | |
58 | ||
59 | /* a is now rounded to mant_dig or mant_dig+1 bits */ | |
60 | if (a & (1 << mant_dig)) != 0 { | |
48663c56 XL |
61 | a >>= 1; |
62 | e += 1; | |
041b39d2 XL |
63 | } |
64 | a | |
48663c56 | 65 | /* a is now rounded to mant_dig bits */ |
041b39d2 XL |
66 | } else { |
67 | a.wrapping_shl(mant_dig - sd) | |
68 | /* a is now rounded to mant_dig bits */ | |
69 | }; | |
70 | ||
48663c56 XL |
71 | <$fty>::from_parts( |
72 | s, | |
041b39d2 | 73 | (e + exponent_bias) as <$fty as Float>::Int, |
48663c56 XL |
74 | a as <$fty as Float>::Int, |
75 | ) | |
76 | }}; | |
041b39d2 XL |
77 | } |
78 | ||
79 | intrinsics! { | |
80 | #[arm_aeabi_alias = __aeabi_i2f] | |
81 | pub extern "C" fn __floatsisf(i: i32) -> f32 { | |
82 | int_to_float!(i, i32, f32) | |
83 | } | |
84 | ||
85 | #[arm_aeabi_alias = __aeabi_i2d] | |
86 | pub extern "C" fn __floatsidf(i: i32) -> f64 { | |
87 | int_to_float!(i, i32, f64) | |
88 | } | |
89 | ||
48663c56 | 90 | #[maybe_use_optimized_c_shim] |
94b46f34 XL |
91 | #[arm_aeabi_alias = __aeabi_l2f] |
92 | pub extern "C" fn __floatdisf(i: i64) -> f32 { | |
93 | // On x86_64 LLVM will use native instructions for this conversion, we | |
94 | // can just do it directly | |
95 | if cfg!(target_arch = "x86_64") { | |
96 | i as f32 | |
97 | } else { | |
98 | int_to_float!(i, i64, f32) | |
99 | } | |
100 | } | |
101 | ||
48663c56 | 102 | #[maybe_use_optimized_c_shim] |
041b39d2 XL |
103 | #[arm_aeabi_alias = __aeabi_l2d] |
104 | pub extern "C" fn __floatdidf(i: i64) -> f64 { | |
105 | // On x86_64 LLVM will use native instructions for this conversion, we | |
106 | // can just do it directly | |
107 | if cfg!(target_arch = "x86_64") { | |
108 | i as f64 | |
109 | } else { | |
110 | int_to_float!(i, i64, f64) | |
111 | } | |
112 | } | |
113 | ||
114 | #[unadjusted_on_win64] | |
115 | pub extern "C" fn __floattisf(i: i128) -> f32 { | |
116 | int_to_float!(i, i128, f32) | |
117 | } | |
118 | ||
119 | #[unadjusted_on_win64] | |
120 | pub extern "C" fn __floattidf(i: i128) -> f64 { | |
121 | int_to_float!(i, i128, f64) | |
122 | } | |
123 | ||
124 | #[arm_aeabi_alias = __aeabi_ui2f] | |
125 | pub extern "C" fn __floatunsisf(i: u32) -> f32 { | |
126 | int_to_float!(i, u32, f32) | |
127 | } | |
128 | ||
129 | #[arm_aeabi_alias = __aeabi_ui2d] | |
130 | pub extern "C" fn __floatunsidf(i: u32) -> f64 { | |
131 | int_to_float!(i, u32, f64) | |
132 | } | |
133 | ||
48663c56 | 134 | #[maybe_use_optimized_c_shim] |
94b46f34 XL |
135 | #[arm_aeabi_alias = __aeabi_ul2f] |
136 | pub extern "C" fn __floatundisf(i: u64) -> f32 { | |
137 | int_to_float!(i, u64, f32) | |
138 | } | |
139 | ||
48663c56 | 140 | #[maybe_use_optimized_c_shim] |
041b39d2 XL |
141 | #[arm_aeabi_alias = __aeabi_ul2d] |
142 | pub extern "C" fn __floatundidf(i: u64) -> f64 { | |
143 | int_to_float!(i, u64, f64) | |
144 | } | |
145 | ||
146 | #[unadjusted_on_win64] | |
147 | pub extern "C" fn __floatuntisf(i: u128) -> f32 { | |
148 | int_to_float!(i, u128, f32) | |
149 | } | |
150 | ||
151 | #[unadjusted_on_win64] | |
152 | pub extern "C" fn __floatuntidf(i: u128) -> f64 { | |
153 | int_to_float!(i, u128, f64) | |
154 | } | |
155 | } | |
156 | ||
157 | #[derive(PartialEq)] | |
158 | enum Sign { | |
159 | Positive, | |
48663c56 | 160 | Negative, |
041b39d2 XL |
161 | } |
162 | ||
163 | macro_rules! float_to_int { | |
48663c56 | 164 | ($f:expr, $fty:ty, $ity:ty) => {{ |
041b39d2 XL |
165 | let f = $f; |
166 | let fixint_min = <$ity>::min_value(); | |
167 | let fixint_max = <$ity>::max_value(); | |
5869c6ff | 168 | let fixint_bits = <$ity as Int>::BITS as usize; |
041b39d2 XL |
169 | let fixint_unsigned = fixint_min == 0; |
170 | ||
ea8adc8c XL |
171 | let sign_bit = <$fty>::SIGN_MASK; |
172 | let significand_bits = <$fty>::SIGNIFICAND_BITS as usize; | |
173 | let exponent_bias = <$fty>::EXPONENT_BIAS as usize; | |
041b39d2 XL |
174 | //let exponent_max = <$fty>::exponent_max() as usize; |
175 | ||
176 | // Break a into sign, exponent, significand | |
177 | let a_rep = <$fty>::repr(f); | |
178 | let a_abs = a_rep & !sign_bit; | |
179 | ||
180 | // this is used to work around -1 not being available for unsigned | |
48663c56 XL |
181 | let sign = if (a_rep & sign_bit) == 0 { |
182 | Sign::Positive | |
183 | } else { | |
184 | Sign::Negative | |
185 | }; | |
041b39d2 | 186 | let mut exponent = (a_abs >> significand_bits) as usize; |
ea8adc8c | 187 | let significand = (a_abs & <$fty>::SIGNIFICAND_MASK) | <$fty>::IMPLICIT_BIT; |
041b39d2 XL |
188 | |
189 | // if < 1 or unsigned & negative | |
48663c56 XL |
190 | if exponent < exponent_bias || fixint_unsigned && sign == Sign::Negative { |
191 | return 0; | |
041b39d2 XL |
192 | } |
193 | exponent -= exponent_bias; | |
194 | ||
195 | // If the value is infinity, saturate. | |
196 | // If the value is too large for the integer type, 0. | |
48663c56 XL |
197 | if exponent |
198 | >= (if fixint_unsigned { | |
199 | fixint_bits | |
200 | } else { | |
201 | fixint_bits - 1 | |
202 | }) | |
203 | { | |
204 | return if sign == Sign::Positive { | |
205 | fixint_max | |
206 | } else { | |
207 | fixint_min | |
208 | }; | |
041b39d2 XL |
209 | } |
210 | // If 0 <= exponent < significand_bits, right shift to get the result. | |
211 | // Otherwise, shift left. | |
212 | // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned | |
213 | let r = if exponent < significand_bits { | |
214 | (significand >> (significand_bits - exponent)) as $ity | |
215 | } else { | |
216 | (significand as $ity) << (exponent - significand_bits) | |
217 | }; | |
218 | ||
219 | if sign == Sign::Negative { | |
220 | (!r).wrapping_add(1) | |
221 | } else { | |
222 | r | |
223 | } | |
48663c56 | 224 | }}; |
041b39d2 XL |
225 | } |
226 | ||
227 | intrinsics! { | |
228 | #[arm_aeabi_alias = __aeabi_f2iz] | |
229 | pub extern "C" fn __fixsfsi(f: f32) -> i32 { | |
230 | float_to_int!(f, f32, i32) | |
231 | } | |
232 | ||
233 | #[arm_aeabi_alias = __aeabi_f2lz] | |
234 | pub extern "C" fn __fixsfdi(f: f32) -> i64 { | |
235 | float_to_int!(f, f32, i64) | |
236 | } | |
237 | ||
238 | #[unadjusted_on_win64] | |
239 | pub extern "C" fn __fixsfti(f: f32) -> i128 { | |
240 | float_to_int!(f, f32, i128) | |
241 | } | |
242 | ||
243 | #[arm_aeabi_alias = __aeabi_d2iz] | |
244 | pub extern "C" fn __fixdfsi(f: f64) -> i32 { | |
245 | float_to_int!(f, f64, i32) | |
246 | } | |
247 | ||
248 | #[arm_aeabi_alias = __aeabi_d2lz] | |
249 | pub extern "C" fn __fixdfdi(f: f64) -> i64 { | |
250 | float_to_int!(f, f64, i64) | |
251 | } | |
252 | ||
253 | #[unadjusted_on_win64] | |
254 | pub extern "C" fn __fixdfti(f: f64) -> i128 { | |
255 | float_to_int!(f, f64, i128) | |
256 | } | |
257 | ||
258 | #[arm_aeabi_alias = __aeabi_f2uiz] | |
259 | pub extern "C" fn __fixunssfsi(f: f32) -> u32 { | |
260 | float_to_int!(f, f32, u32) | |
261 | } | |
262 | ||
263 | #[arm_aeabi_alias = __aeabi_f2ulz] | |
264 | pub extern "C" fn __fixunssfdi(f: f32) -> u64 { | |
265 | float_to_int!(f, f32, u64) | |
266 | } | |
267 | ||
268 | #[unadjusted_on_win64] | |
269 | pub extern "C" fn __fixunssfti(f: f32) -> u128 { | |
270 | float_to_int!(f, f32, u128) | |
271 | } | |
272 | ||
273 | #[arm_aeabi_alias = __aeabi_d2uiz] | |
274 | pub extern "C" fn __fixunsdfsi(f: f64) -> u32 { | |
275 | float_to_int!(f, f64, u32) | |
276 | } | |
277 | ||
278 | #[arm_aeabi_alias = __aeabi_d2ulz] | |
279 | pub extern "C" fn __fixunsdfdi(f: f64) -> u64 { | |
280 | float_to_int!(f, f64, u64) | |
281 | } | |
282 | ||
283 | #[unadjusted_on_win64] | |
284 | pub extern "C" fn __fixunsdfti(f: f64) -> u128 { | |
285 | float_to_int!(f, f64, u128) | |
286 | } | |
287 | } |