1use core::ops::Neg;
2
3use super::Float;
4use crate::int::{CastFrom, CastInto, Int, MinInt};
5
6mod int_to_float {
27 use super::*;
28
29 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 fn m_adj<F: Float>(m_base: F::Int, dropped_bits: F::Int) -> F::Int {
42 let adj = (dropped_bits - ((dropped_bits >> (F::BITS - 1)) & !m_base)) >> (F::BITS - 1);
45
46 m_base + adj
48 }
49
50 fn repr<F: Float>(e: F::Int, m: F::Int) -> F::Int {
55 (e << F::SIG_BITS) + m
57 }
58
59 fn shift_f_lt_i<I: Int, F: Float>() -> u32 {
61 (I::BITS - F::BITS) + F::EXP_BITS
62 }
63
64 fn shift_f_gt_i<I: Int, F: Float>(n: u32) -> u32 {
66 F::SIG_BITS - I::BITS + 1 + n
67 }
68
69 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 let m_base = (i << n) >> f32::EXP_BITS;
88 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 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 let m = (i as u64) << (shift_f_gt_i::<u32, f128>(n) - 64);
116 let e = exp::<u32, f128>(n) as u64 - 1;
117 let h = (e << (f128::SIG_BITS - 64)) + m;
119
120 (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 let m_base: u32 = (i_m >> shift_f_lt_i::<u64, f32>()) as u32;
129 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 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 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); let m_base: u32 = (i_m >> shift_f_lt_i::<u128, f32>()) as u32;
166
167 let d1: u32 = (i_m >> (u128::BITS - f32::BITS - f32::SIG_BITS - 1)).cast();
170
171 let d2: u32 = (i_m << f32::BITS >> f32::BITS != 0).into();
174 let adj = d1 | d2;
175
176 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 let m_base: u64 = (i_m >> shift_f_lt_i::<u128, f64>()) as u64;
187 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 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
210intrinsics! {
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
261intrinsics! {
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
312fn 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
325fn 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
342fn 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 I::ZERO
369 } else if fbits < F::Int::cast_from(int_max_exp) << F::SIG_BITS {
370 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 let m: I::UnsignedInt = (I::UnsignedInt::ONE << (I::BITS - 1)) | m_base;
379
380 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 out_of_bounds()
388 } else {
389 I::ZERO
390 }
391}
392
393intrinsics! {
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
442intrinsics! {
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}