Use intrinsics for abs and copysign when available
Currently our implementations for `abs` and `copysign` are defined on the trait, and these are then called from `generic`. It would be better to call core's `.abs()` / `.copysign(y)`, but we can't do this in the generic because calling the standalone function could become recursive (`fabsf` becomes `intrinsics::fabsf32`, that may lower to a call to `fabsf`). Change this so the traits uses the call to `core` if available, falling back to a call to the standalone generic function. In practice the recursion isn't likely to be a problem since LLVM probably always lowers `abs`/`copysign` to assembly, but this pattern should be more correct for functions that we will add in the future (e.g. `fma`). This should eventually be followed by a change to call the trait methods rather than `fabs`/`copysign` directly.
This commit is contained in:
parent
a277ec6954
commit
14e6d05dfb
5 changed files with 43 additions and 16 deletions
|
|
@ -70,6 +70,14 @@ impl Float for f8 {
|
|||
Self(a)
|
||||
}
|
||||
|
||||
fn abs(self) -> Self {
|
||||
libm::generic::fabs(self)
|
||||
}
|
||||
|
||||
fn copysign(self, other: Self) -> Self {
|
||||
libm::generic::copysign(self, other)
|
||||
}
|
||||
|
||||
fn normalize(_significand: Self::Int) -> (i32, Self::Int) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@ pub fn copysign<F: Float>(x: F, y: F) -> F {
|
|||
let mut ux = x.to_bits();
|
||||
let uy = y.to_bits();
|
||||
ux &= !F::SIGN_MASK;
|
||||
ux |= uy & (F::SIGN_MASK);
|
||||
ux |= uy & F::SIGN_MASK;
|
||||
F::from_bits(ux)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,5 +2,6 @@ use super::super::Float;
|
|||
|
||||
/// Absolute value.
|
||||
pub fn fabs<F: Float>(x: F) -> F {
|
||||
x.abs()
|
||||
let abs_mask = !F::SIGN_MASK;
|
||||
F::from_bits(x.to_bits() & abs_mask)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,11 +83,18 @@ pub mod support;
|
|||
#[cfg(not(feature = "unstable-test-support"))]
|
||||
mod support;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "unstable-test-support")] {
|
||||
pub mod generic;
|
||||
} else {
|
||||
mod generic;
|
||||
}
|
||||
}
|
||||
|
||||
// Private modules
|
||||
mod arch;
|
||||
mod expo2;
|
||||
mod fenv;
|
||||
mod generic;
|
||||
mod k_cos;
|
||||
mod k_cosf;
|
||||
mod k_expo2;
|
||||
|
|
|
|||
|
|
@ -123,23 +123,14 @@ pub trait Float:
|
|||
)
|
||||
}
|
||||
|
||||
fn abs(self) -> Self {
|
||||
let abs_mask = !Self::SIGN_MASK;
|
||||
Self::from_bits(self.to_bits() & abs_mask)
|
||||
}
|
||||
fn abs(self) -> Self;
|
||||
|
||||
/// Returns a number composed of the magnitude of self and the sign of sign.
|
||||
fn copysign(self, other: Self) -> Self;
|
||||
|
||||
/// Returns (normalized exponent, normalized significand)
|
||||
fn normalize(significand: Self::Int) -> (i32, Self::Int);
|
||||
|
||||
/// Returns a number composed of the magnitude of self and the sign of sign.
|
||||
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)
|
||||
}
|
||||
|
||||
/// Returns a number that represents the sign of self.
|
||||
fn signum(self) -> Self {
|
||||
if self.is_nan() { self } else { Self::ONE.copysign(self) }
|
||||
|
|
@ -206,6 +197,26 @@ macro_rules! float_impl {
|
|||
fn from_bits(a: Self::Int) -> Self {
|
||||
Self::from_bits(a)
|
||||
}
|
||||
fn abs(self) -> Self {
|
||||
cfg_if! {
|
||||
// FIXME(msrv): `abs` is available in `core` starting with 1.85.
|
||||
if #[cfg(feature = "unstable-intrinsics")] {
|
||||
self.abs()
|
||||
} else {
|
||||
super::super::generic::fabs(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn copysign(self, other: Self) -> Self {
|
||||
cfg_if! {
|
||||
// FIXME(msrv): `copysign` is available in `core` starting with 1.85.
|
||||
if #[cfg(feature = "unstable-intrinsics")] {
|
||||
self.copysign(other)
|
||||
} else {
|
||||
super::super::generic::copysign(self, other)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
|
||||
let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS);
|
||||
(1i32.wrapping_sub(shift as i32), significand << shift as Self::Int)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue