]> git.proxmox.com Git - rustc.git/blame - vendor/compiler_builtins/src/float/conv.rs
New upstream version 1.51.0+dfsg1
[rustc.git] / vendor / compiler_builtins / src / float / conv.rs
CommitLineData
041b39d2
XL
1use float::Float;
2use int::Int;
3
4macro_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
79intrinsics! {
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)]
158enum Sign {
159 Positive,
48663c56 160 Negative,
041b39d2
XL
161}
162
163macro_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
227intrinsics! {
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}