Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit 6f6bd11

Browse files
committed
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.
1 parent 110c6f7 commit 6f6bd11

File tree

5 files changed

+43
-16
lines changed

5 files changed

+43
-16
lines changed

crates/libm-test/src/f8_impl.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ impl Float for f8 {
7070
Self(a)
7171
}
7272

73+
fn abs(self) -> Self {
74+
libm::generic::fabs(self)
75+
}
76+
77+
fn copysign(self, other: Self) -> Self {
78+
libm::generic::copysign(self, other)
79+
}
80+
7381
fn normalize(_significand: Self::Int) -> (i32, Self::Int) {
7482
unimplemented!()
7583
}

src/math/generic/copysign.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ pub fn copysign<F: Float>(x: F, y: F) -> F {
55
let mut ux = x.to_bits();
66
let uy = y.to_bits();
77
ux &= !F::SIGN_MASK;
8-
ux |= uy & (F::SIGN_MASK);
8+
ux |= uy & F::SIGN_MASK;
99
F::from_bits(ux)
1010
}

src/math/generic/fabs.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ use super::super::Float;
22

33
/// Absolute value.
44
pub fn fabs<F: Float>(x: F) -> F {
5-
x.abs()
5+
let abs_mask = !F::SIGN_MASK;
6+
F::from_bits(x.to_bits() & abs_mask)
67
}

src/math/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,18 @@ pub mod support;
8383
#[cfg(not(feature = "unstable-test-support"))]
8484
mod support;
8585

86+
cfg_if! {
87+
if #[cfg(feature = "unstable-test-support")] {
88+
pub mod generic;
89+
} else {
90+
mod generic;
91+
}
92+
}
93+
8694
// Private modules
8795
mod arch;
8896
mod expo2;
8997
mod fenv;
90-
mod generic;
9198
mod k_cos;
9299
mod k_cosf;
93100
mod k_expo2;

src/math/support/float_traits.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -123,23 +123,14 @@ pub trait Float:
123123
)
124124
}
125125

126-
fn abs(self) -> Self {
127-
let abs_mask = !Self::SIGN_MASK;
128-
Self::from_bits(self.to_bits() & abs_mask)
129-
}
126+
fn abs(self) -> Self;
127+
128+
/// Returns a number composed of the magnitude of self and the sign of sign.
129+
fn copysign(self, other: Self) -> Self;
130130

131131
/// Returns (normalized exponent, normalized significand)
132132
fn normalize(significand: Self::Int) -> (i32, Self::Int);
133133

134-
/// Returns a number composed of the magnitude of self and the sign of sign.
135-
fn copysign(self, other: Self) -> Self {
136-
let mut x = self.to_bits();
137-
let y = other.to_bits();
138-
x &= !Self::SIGN_MASK;
139-
x |= y & Self::SIGN_MASK;
140-
Self::from_bits(x)
141-
}
142-
143134
/// Returns a number that represents the sign of self.
144135
fn signum(self) -> Self {
145136
if self.is_nan() { self } else { Self::ONE.copysign(self) }
@@ -206,6 +197,26 @@ macro_rules! float_impl {
206197
fn from_bits(a: Self::Int) -> Self {
207198
Self::from_bits(a)
208199
}
200+
fn abs(self) -> Self {
201+
cfg_if! {
202+
// FIXME(msrv): `abs` is available in `core` starting with 1.85.
203+
if #[cfg(feature = "unstable-intrinsics")] {
204+
self.abs()
205+
} else {
206+
super::super::generic::fabs(self)
207+
}
208+
}
209+
}
210+
fn copysign(self, other: Self) -> Self {
211+
cfg_if! {
212+
// FIXME(msrv): `copysign` is available in `core` starting with 1.85.
213+
if #[cfg(feature = "unstable-intrinsics")] {
214+
self.copysign(other)
215+
} else {
216+
super::super::generic::copysign(self, other)
217+
}
218+
}
219+
}
209220
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
210221
let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS);
211222
(1i32.wrapping_sub(shift as i32), significand << shift as Self::Int)

0 commit comments

Comments
 (0)