Introduce a select_implementation macro

Currently there is a macro called `llvm_intrinsically_optimized` that
uses an intrinsic rather than the function implementation if the
configuration is correct. Add a new macro `select_implementation` that
is somewhat cleaner to use.

In the future, we can update this macro with more fields to specify
other implementations that may be selected, such as something
architecture-specific or e.g. using a generic implementation for `f32`
routines, rather than those that convert to `f64`.

This introduces a `macros` module within `math/support`. We will be able
to move more things here later.
This commit is contained in:
Trevor Gross 2024-10-26 02:56:22 -05:00
parent 1b7346bf5f
commit d54896343c
3 changed files with 69 additions and 30 deletions

View file

@ -74,6 +74,7 @@ macro_rules! div {
};
}
// FIXME: phase this out, to be replaced by the more flexible `select_implementation`
macro_rules! llvm_intrinsically_optimized {
(#[cfg($($clause:tt)*)] $e:expr) => {
#[cfg(all(intrinsics_enabled, not(feature = "force-soft-floats"), $($clause)*))]
@ -85,6 +86,38 @@ macro_rules! llvm_intrinsically_optimized {
};
}
// Private modules
#[macro_use]
mod support;
mod arch;
mod expo2;
mod fenv;
mod k_cos;
mod k_cosf;
mod k_expo2;
mod k_expo2f;
mod k_sin;
mod k_sinf;
mod k_tan;
mod k_tanf;
mod rem_pio2;
mod rem_pio2_large;
mod rem_pio2f;
// Private re-imports
use self::expo2::expo2;
use self::k_cos::k_cos;
use self::k_cosf::k_cosf;
use self::k_expo2::k_expo2;
use self::k_expo2f::k_expo2f;
use self::k_sin::k_sin;
use self::k_sinf::k_sinf;
use self::k_tan::k_tan;
use self::k_tanf::k_tanf;
use self::rem_pio2::rem_pio2;
use self::rem_pio2_large::rem_pio2_large;
use self::rem_pio2f::rem_pio2f;
// Public modules
mod acos;
mod acosf;
@ -301,36 +334,6 @@ pub use self::tgammaf::tgammaf;
pub use self::trunc::trunc;
pub use self::truncf::truncf;
// Private modules
mod arch;
mod expo2;
mod fenv;
mod k_cos;
mod k_cosf;
mod k_expo2;
mod k_expo2f;
mod k_sin;
mod k_sinf;
mod k_tan;
mod k_tanf;
mod rem_pio2;
mod rem_pio2_large;
mod rem_pio2f;
// Private re-imports
use self::expo2::expo2;
use self::k_cos::k_cos;
use self::k_cosf::k_cosf;
use self::k_expo2::k_expo2;
use self::k_expo2f::k_expo2f;
use self::k_sin::k_sin;
use self::k_sinf::k_sinf;
use self::k_tan::k_tan;
use self::k_tanf::k_tanf;
use self::rem_pio2::rem_pio2;
use self::rem_pio2_large::rem_pio2_large;
use self::rem_pio2f::rem_pio2f;
#[inline]
fn get_high_word(x: f64) -> u32 {
(x.to_bits() >> 32) as u32

View file

@ -0,0 +1,34 @@
/// Choose among using an intrinsic (if available) and falling back to the default function body.
/// Returns directly if the intrinsic version is used, otherwise continues to the rest of the
/// function.
///
/// Use this if the intrinsic is likely to be more performant on the platform(s) specified
/// in `intrinsic_available`.
///
/// The `cfg` used here is controlled by `build.rs` so the passed meta does not need to account
/// for e.g. the `unstable-intrinsics` or `force-soft-float` features.
macro_rules! select_implementation {
(
name: $fname:ident,
// Configuration meta for when to call intrinsics and let LLVM figure it out
$( use_intrinsic: $use_intrinsic:meta, )?
args: $($arg:ident),+ ,
) => {
// FIXME: these use paths that are a pretty fragile (`super`). We should figure out
// something better w.r.t. how this is vendored into compiler-builtins.
// Never use intrinsics if we are forcing soft floats, and only enable with the
// `unstable-intrinsics` feature.
#[cfg(intrinsics_enabled)]
select_implementation! {
@cfg $( $use_intrinsic )?;
if true {
return super::arch::intrinsics::$fname( $($arg),+ );
}
}
};
// Coalesce helper to construct an expression only if a config is provided
(@cfg ; $ex:expr) => { };
(@cfg $provided:meta; $ex:expr) => { #[cfg($provided)] $ex };
}

View file

@ -0,0 +1,2 @@
#[macro_use]
pub mod macros;