diff --git a/library/compiler-builtins/libm/src/math/support/float_traits.rs b/library/compiler-builtins/libm/src/math/support/float_traits.rs index f90e99d5228b..a1d84faf2e25 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -1,4 +1,4 @@ -use core::ops; +use core::{fmt, ops}; use super::int_traits::{Int, MinInt}; @@ -6,7 +6,8 @@ use super::int_traits::{Int, MinInt}; #[allow(dead_code)] pub trait Float: Copy - + core::fmt::Debug + + fmt::Debug + + fmt::Display + PartialEq + PartialOrd + ops::AddAssign @@ -17,16 +18,17 @@ pub trait Float: + ops::Rem { /// A uint of the same width as the float - type Int: Int; + type Int: Int; /// A int of the same width as the float - type SignedInt: Int + MinInt; + type SignedInt: Int + MinInt; /// An int capable of containing the exponent bits plus a sign bit. This is signed. type ExpInt: Int; const ZERO: Self; const ONE: Self; + const NEG_ONE: Self; const INFINITY: Self; const NEG_INFINITY: Self; const NAN: Self; @@ -69,9 +71,18 @@ pub trait Float: /// compared. fn eq_repr(self, rhs: Self) -> bool; - /// Returns true if the sign is negative + /// Returns true if the value is NaN. + fn is_nan(self) -> bool; + + /// Returns true if the value is +inf or -inf. + fn is_infinite(self) -> bool; + + /// Returns true if the sign is negative. fn is_sign_negative(self) -> bool; + /// Returns if `self` is subnormal + fn is_subnormal(self) -> bool; + /// Returns the exponent, not adjusting for bias. fn exp(self) -> Self::ExpInt; @@ -95,8 +106,11 @@ pub trait Float: /// Returns (normalized exponent, normalized significand) fn normalize(significand: Self::Int) -> (i32, Self::Int); - /// Returns if `self` is subnormal - fn is_subnormal(self) -> bool; + /// Returns a number composed of the magnitude of self and the sign of sign. + fn copysign(self, other: Self) -> Self; + + /// Returns a number that represents the sign of self. + fn signum(self) -> Self; } macro_rules! float_impl { @@ -108,6 +122,7 @@ macro_rules! float_impl { const ZERO: Self = 0.0; const ONE: Self = 1.0; + const NEG_ONE: Self = -1.0; const INFINITY: Self = Self::INFINITY; const NEG_INFINITY: Self = Self::NEG_INFINITY; const NAN: Self = Self::NAN; @@ -136,9 +151,18 @@ macro_rules! float_impl { } if is_nan(self) && is_nan(rhs) { true } else { self.to_bits() == rhs.to_bits() } } + fn is_nan(self) -> bool { + self.is_nan() + } + fn is_infinite(self) -> bool { + self.is_infinite() + } fn is_sign_negative(self) -> bool { self.is_sign_negative() } + fn is_subnormal(self) -> bool { + (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + } fn exp(self) -> Self::ExpInt { ((self.to_bits() & Self::EXP_MASK) >> Self::SIG_BITS) as Self::ExpInt } @@ -162,8 +186,16 @@ macro_rules! float_impl { let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS); (1i32.wrapping_sub(shift as i32), significand << shift as Self::Int) } - fn is_subnormal(self) -> bool { - (self.to_bits() & Self::EXP_MASK) == Self::Int::ZERO + fn copysign(self, other: Self) -> Self { + let mut x = self.to_bits(); + let y = other.to_bits(); + x &= !Self::SIGN_MASK; + x |= y & Self::SIGN_MASK; + Self::from_bits(x) + } + + fn signum(self) -> Self { + if self.is_nan() { self } else { Self::ONE.copysign(self) } } } }; diff --git a/library/compiler-builtins/libm/src/math/support/int_traits.rs b/library/compiler-builtins/libm/src/math/support/int_traits.rs index bdf3afd48cef..c5feef8d7268 100644 --- a/library/compiler-builtins/libm/src/math/support/int_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/int_traits.rs @@ -12,7 +12,7 @@ pub trait MinInt: /// Type with the same width but other signedness type OtherSign: MinInt; /// Unsigned version of Self - type UnsignedInt: MinInt; + type Unsigned: MinInt; /// If `Self` is a signed integer const SIGNED: bool; @@ -30,6 +30,7 @@ pub trait MinInt: #[allow(dead_code)] pub trait Int: MinInt + + fmt::Display + PartialEq + PartialOrd + ops::AddAssign @@ -47,8 +48,10 @@ pub trait Int: + ops::BitXor + ops::BitAnd { - fn unsigned(self) -> Self::UnsignedInt; - fn from_unsigned(unsigned: Self::UnsignedInt) -> Self; + fn signed(self) -> ::OtherSign; + fn unsigned(self) -> Self::Unsigned; + fn from_unsigned(unsigned: Self::Unsigned) -> Self; + fn abs(self) -> Self; fn from_bool(b: bool) -> Self; @@ -56,10 +59,12 @@ pub trait Int: fn logical_shr(self, other: u32) -> Self; /// Absolute difference between two integers. - fn abs_diff(self, other: Self) -> Self::UnsignedInt; + fn abs_diff(self, other: Self) -> Self::Unsigned; // copied from primitive integers, but put in a trait fn is_zero(self) -> bool; + fn checked_add(self, other: Self) -> Option; + fn checked_sub(self, other: Self) -> Option; fn wrapping_neg(self) -> Self; fn wrapping_add(self, other: Self) -> Self; fn wrapping_mul(self, other: Self) -> Self; @@ -86,6 +91,14 @@ macro_rules! int_impl_common { self == Self::ZERO } + fn checked_add(self, other: Self) -> Option { + self.checked_add(other) + } + + fn checked_sub(self, other: Self) -> Option { + self.checked_sub(other) + } + fn wrapping_neg(self) -> Self { ::wrapping_neg(self) } @@ -132,7 +145,7 @@ macro_rules! int_impl { ($ity:ty, $uty:ty) => { impl MinInt for $uty { type OtherSign = $ity; - type UnsignedInt = $uty; + type Unsigned = $uty; const BITS: u32 = ::ZERO.count_zeros(); const SIGNED: bool = Self::MIN != Self::ZERO; @@ -144,10 +157,18 @@ macro_rules! int_impl { } impl Int for $uty { - fn unsigned(self) -> $uty { + fn signed(self) -> $ity { + self as $ity + } + + fn unsigned(self) -> Self { self } + fn abs(self) -> Self { + unimplemented!() + } + // It makes writing macros easier if this is implemented for both signed and unsigned #[allow(clippy::wrong_self_convention)] fn from_unsigned(me: $uty) -> Self { @@ -163,7 +184,7 @@ macro_rules! int_impl { impl MinInt for $ity { type OtherSign = $uty; - type UnsignedInt = $uty; + type Unsigned = $uty; const BITS: u32 = ::ZERO.count_zeros(); const SIGNED: bool = Self::MIN != Self::ZERO; @@ -175,10 +196,18 @@ macro_rules! int_impl { } impl Int for $ity { + fn signed(self) -> Self { + self + } + fn unsigned(self) -> $uty { self as $uty } + fn abs(self) -> Self { + self.abs() + } + fn from_unsigned(me: $uty) -> Self { me as $ity }