From 14e6d05dfba4ec4cf69d347f4510640ff97419bc Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 3 Jan 2025 12:04:45 +0000 Subject: [PATCH] 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. --- .../libm/crates/libm-test/src/f8_impl.rs | 8 ++++ .../libm/src/math/generic/copysign.rs | 2 +- .../libm/src/math/generic/fabs.rs | 3 +- .../compiler-builtins/libm/src/math/mod.rs | 9 ++++- .../libm/src/math/support/float_traits.rs | 37 ++++++++++++------- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs index babcc6357a40..d378863f2fd9 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/f8_impl.rs @@ -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!() } diff --git a/library/compiler-builtins/libm/src/math/generic/copysign.rs b/library/compiler-builtins/libm/src/math/generic/copysign.rs index d6b814891935..04864a359056 100644 --- a/library/compiler-builtins/libm/src/math/generic/copysign.rs +++ b/library/compiler-builtins/libm/src/math/generic/copysign.rs @@ -5,6 +5,6 @@ pub fn copysign(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) } diff --git a/library/compiler-builtins/libm/src/math/generic/fabs.rs b/library/compiler-builtins/libm/src/math/generic/fabs.rs index f2c7f0f465bc..75b473107c67 100644 --- a/library/compiler-builtins/libm/src/math/generic/fabs.rs +++ b/library/compiler-builtins/libm/src/math/generic/fabs.rs @@ -2,5 +2,6 @@ use super::super::Float; /// Absolute value. pub fn fabs(x: F) -> F { - x.abs() + let abs_mask = !F::SIGN_MASK; + F::from_bits(x.to_bits() & abs_mask) } diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index ba1995228162..e7b21de67621 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -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; 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 e64640a0d154..3b5be4fa3d3d 100644 --- a/library/compiler-builtins/libm/src/math/support/float_traits.rs +++ b/library/compiler-builtins/libm/src/math/support/float_traits.rs @@ -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)