summaryrefslogtreecommitdiffstats
path: root/vendor/compiler_builtins/src/float/extend.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vendor/compiler_builtins/src/float/extend.rs83
1 files changed, 83 insertions, 0 deletions
diff --git a/vendor/compiler_builtins/src/float/extend.rs b/vendor/compiler_builtins/src/float/extend.rs
new file mode 100644
index 000000000..39633773b
--- /dev/null
+++ b/vendor/compiler_builtins/src/float/extend.rs
@@ -0,0 +1,83 @@
+use float::Float;
+use int::{CastInto, Int};
+
+/// Generic conversion from a narrower to a wider IEEE-754 floating-point type
+fn extend<F: Float, R: Float>(a: F) -> R
+where
+ F::Int: CastInto<u64>,
+ u64: CastInto<F::Int>,
+ u32: CastInto<R::Int>,
+ R::Int: CastInto<u32>,
+ R::Int: CastInto<u64>,
+ u64: CastInto<R::Int>,
+ F::Int: CastInto<R::Int>,
+{
+ let src_zero = F::Int::ZERO;
+ let src_one = F::Int::ONE;
+ let src_bits = F::BITS;
+ let src_sign_bits = F::SIGNIFICAND_BITS;
+ let src_exp_bias = F::EXPONENT_BIAS;
+ let src_min_normal = F::IMPLICIT_BIT;
+ let src_infinity = F::EXPONENT_MASK;
+ let src_sign_mask = F::SIGN_MASK as F::Int;
+ let src_abs_mask = src_sign_mask - src_one;
+ let src_qnan = F::SIGNIFICAND_MASK;
+ let src_nan_code = src_qnan - src_one;
+
+ let dst_bits = R::BITS;
+ let dst_sign_bits = R::SIGNIFICAND_BITS;
+ let dst_inf_exp = R::EXPONENT_MAX;
+ let dst_exp_bias = R::EXPONENT_BIAS;
+ let dst_min_normal = R::IMPLICIT_BIT;
+
+ let sign_bits_delta = dst_sign_bits - src_sign_bits;
+ let exp_bias_delta = dst_exp_bias - src_exp_bias;
+ let a_abs = a.repr() & src_abs_mask;
+ let mut abs_result = R::Int::ZERO;
+
+ if a_abs.wrapping_sub(src_min_normal) < src_infinity.wrapping_sub(src_min_normal) {
+ // a is a normal number.
+ // Extend to the destination type by shifting the significand and
+ // exponent into the proper position and rebiasing the exponent.
+ let abs_dst: R::Int = a_abs.cast();
+ let bias_dst: R::Int = exp_bias_delta.cast();
+ abs_result = abs_dst.wrapping_shl(sign_bits_delta);
+ abs_result += bias_dst.wrapping_shl(dst_sign_bits);
+ } else if a_abs >= src_infinity {
+ // a is NaN or infinity.
+ // Conjure the result by beginning with infinity, then setting the qNaN
+ // bit (if needed) and right-aligning the rest of the trailing NaN
+ // payload field.
+ let qnan_dst: R::Int = (a_abs & src_qnan).cast();
+ let nan_code_dst: R::Int = (a_abs & src_nan_code).cast();
+ let inf_exp_dst: R::Int = dst_inf_exp.cast();
+ abs_result = inf_exp_dst.wrapping_shl(dst_sign_bits);
+ abs_result |= qnan_dst.wrapping_shl(sign_bits_delta);
+ abs_result |= nan_code_dst.wrapping_shl(sign_bits_delta);
+ } else if a_abs != src_zero {
+ // a is denormal.
+ // Renormalize the significand and clear the leading bit, then insert
+ // the correct adjusted exponent in the destination type.
+ let scale = a_abs.leading_zeros() - src_min_normal.leading_zeros();
+ let abs_dst: R::Int = a_abs.cast();
+ let bias_dst: R::Int = (exp_bias_delta - scale + 1).cast();
+ abs_result = abs_dst.wrapping_shl(sign_bits_delta + scale);
+ abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sign_bits));
+ }
+
+ let sign_result: R::Int = (a.repr() & src_sign_mask).cast();
+ R::from_repr(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits)))
+}
+
+intrinsics! {
+ #[aapcs_on_arm]
+ #[arm_aeabi_alias = __aeabi_f2d]
+ pub extern "C" fn __extendsfdf2(a: f32) -> f64 {
+ extend(a)
+ }
+
+ #[cfg(target_arch = "arm")]
+ pub extern "C" fn __extendsfdf2vfp(a: f32) -> f64 {
+ a as f64 // LLVM generate 'fcvtds'
+ }
+}