Replace "intrinsic" config with "arch" config

WASM is the only architecture we use `intrinsics::` for. We probably
don't want to do this for any other architectures since it is better to
use assembly, or work toward getting the functions available in `core`.

To more accurately reflect the relationship between arch and intrinsics,
make wasm32 an `arch` module and call the intrinsics from there.
This commit is contained in:
Trevor Gross 2025-01-07 00:19:26 +00:00 committed by Trevor Gross
parent c574145577
commit f3ad123a09
14 changed files with 37 additions and 50 deletions

View file

@ -108,14 +108,14 @@
"sources": [
"src/libm_helper.rs",
"src/math/arch/i586.rs",
"src/math/arch/intrinsics.rs",
"src/math/arch/wasm32.rs",
"src/math/ceil.rs"
],
"type": "f64"
},
"ceilf": {
"sources": [
"src/math/arch/intrinsics.rs",
"src/math/arch/wasm32.rs",
"src/math/ceilf.rs"
],
"type": "f32"
@ -258,7 +258,7 @@
"fabs": {
"sources": [
"src/libm_helper.rs",
"src/math/arch/intrinsics.rs",
"src/math/arch/wasm32.rs",
"src/math/fabs.rs",
"src/math/generic/fabs.rs"
],
@ -266,7 +266,7 @@
},
"fabsf": {
"sources": [
"src/math/arch/intrinsics.rs",
"src/math/arch/wasm32.rs",
"src/math/fabsf.rs",
"src/math/generic/fabs.rs"
],
@ -303,14 +303,14 @@
"sources": [
"src/libm_helper.rs",
"src/math/arch/i586.rs",
"src/math/arch/intrinsics.rs",
"src/math/arch/wasm32.rs",
"src/math/floor.rs"
],
"type": "f64"
},
"floorf": {
"sources": [
"src/math/arch/intrinsics.rs",
"src/math/arch/wasm32.rs",
"src/math/floorf.rs"
],
"type": "f32"
@ -683,7 +683,7 @@
"sources": [
"src/libm_helper.rs",
"src/math/arch/i686.rs",
"src/math/arch/intrinsics.rs",
"src/math/arch/wasm32.rs",
"src/math/sqrt.rs"
],
"type": "f64"
@ -691,7 +691,7 @@
"sqrtf": {
"sources": [
"src/math/arch/i686.rs",
"src/math/arch/intrinsics.rs",
"src/math/arch/wasm32.rs",
"src/math/sqrtf.rs"
],
"type": "f32"
@ -738,14 +738,14 @@
"trunc": {
"sources": [
"src/libm_helper.rs",
"src/math/arch/intrinsics.rs",
"src/math/arch/wasm32.rs",
"src/math/trunc.rs"
],
"type": "f64"
},
"truncf": {
"sources": [
"src/math/arch/intrinsics.rs",
"src/math/arch/wasm32.rs",
"src/math/truncf.rs"
],
"type": "f32"

View file

@ -5,14 +5,14 @@
//! is used when calling the function directly. This helps anyone who uses `libm` directly, as
//! well as improving things when these routines are called as part of other implementations.
#[cfg(intrinsics_enabled)]
pub mod intrinsics;
// Most implementations should be defined here, to ensure they are not made available when
// soft floats are required.
#[cfg(arch_enabled)]
cfg_if! {
if #[cfg(target_feature = "sse2")] {
if #[cfg(all(target_arch = "wasm32", intrinsics_enabled))] {
mod wasm32;
pub use wasm32::{ceil, ceilf, fabs, fabsf, floor, floorf, sqrt, sqrtf, trunc, truncf};
} else if #[cfg(target_feature = "sse2")] {
mod i686;
pub use i686::{sqrt, sqrtf};
}

View file

@ -1,5 +1,7 @@
// Config is needed for times when this module is available but we don't call everything
#![allow(dead_code)]
//! Wasm asm is not stable; just use intrinsics for operations that have asm routine equivalents.
//!
//! Note that we need to be absolutely certain that everything here lowers to assembly operations,
//! otherwise libcalls will be recursive.
pub fn ceil(x: f64) -> f64 {
// SAFETY: safe intrinsic with no preconditions

View file

@ -10,8 +10,8 @@ const TOINT: f64 = 1. / f64::EPSILON;
pub fn ceil(x: f64) -> f64 {
select_implementation! {
name: ceil,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")),
use_intrinsic: target_arch = "wasm32",
args: x,
}

View file

@ -7,7 +7,7 @@ use core::f32;
pub fn ceilf(x: f32) -> f32 {
select_implementation! {
name: ceilf,
use_intrinsic: target_arch = "wasm32",
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}

View file

@ -6,7 +6,7 @@
pub fn fabs(x: f64) -> f64 {
select_implementation! {
name: fabs,
use_intrinsic: target_arch = "wasm32",
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}

View file

@ -6,7 +6,7 @@
pub fn fabsf(x: f32) -> f32 {
select_implementation! {
name: fabsf,
use_intrinsic: target_arch = "wasm32",
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}

View file

@ -10,8 +10,8 @@ const TOINT: f64 = 1. / f64::EPSILON;
pub fn floor(x: f64) -> f64 {
select_implementation! {
name: floor,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
use_arch_required: all(target_arch = "x86", not(target_feature = "sse2")),
use_intrinsic: target_arch = "wasm32",
args: x,
}

View file

@ -7,7 +7,7 @@ use core::f32;
pub fn floorf(x: f32) -> f32 {
select_implementation! {
name: floorf,
use_intrinsic: target_arch = "wasm32",
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}

View file

@ -83,8 +83,10 @@ use core::f64;
pub fn sqrt(x: f64) -> f64 {
select_implementation! {
name: sqrt,
use_arch: target_feature = "sse2",
use_intrinsic: target_arch = "wasm32",
use_arch: any(
all(target_arch = "wasm32", intrinsics_enabled),
target_feature = "sse2"
),
args: x,
}

View file

@ -18,8 +18,10 @@
pub fn sqrtf(x: f32) -> f32 {
select_implementation! {
name: sqrtf,
use_arch: target_feature = "sse2",
use_intrinsic: target_arch = "wasm32",
use_arch: any(
all(target_arch = "wasm32", intrinsics_enabled),
target_feature = "sse2"
),
args: x,
}

View file

@ -39,13 +39,8 @@ macro_rules! cfg_if {
(@__identity $($tokens:tt)*) => { $($tokens)* };
}
/// Choose among using an intrinsic, an arch-specific implementation, and the function body.
/// Returns directly if the intrinsic or arch is used, otherwise continue with the rest of the
/// function.
///
/// Specify a `use_intrinsic` meta field if the intrinsic is (1) available on the platforms (i.e.
/// LLVM lowers it without libcalls that may recurse), (2) it is likely to be more performant.
/// Intrinsics require wrappers in the `math::arch::intrinsics` module.
/// Choose between using an arch-specific implementation and the function body. Returns directly
/// if the arch implementation is used, otherwise continue with the rest of the function.
///
/// Specify a `use_arch` meta field if an architecture-specific implementation is provided.
/// These live in the `math::arch::some_target_arch` module.
@ -53,8 +48,7 @@ macro_rules! cfg_if {
/// Specify a `use_arch_required` meta field if something architecture-specific must be used
/// regardless of feature configuration (`force-soft-floats`).
///
/// The passed meta options do not need to account for relevant Cargo features
/// (`unstable-intrinsics`, `arch`, `force-soft-floats`), this macro handles that part.
/// The passed meta options do not need to account for the `arch` target feature.
macro_rules! select_implementation {
(
name: $fn_name:ident,
@ -64,15 +58,12 @@ macro_rules! select_implementation {
// Configuration meta for when to use the arch module regardless of whether softfloats
// have been requested.
$( use_arch_required: $use_arch_required:meta, )?
// 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.
// However, we do need a few things from `arch` that are used even with soft floats.
//
select_implementation! {
@cfg $($use_arch_required)?;
if true {
@ -89,16 +80,6 @@ macro_rules! select_implementation {
return super::arch::$fn_name( $($arg),+ );
}
}
// 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::$fn_name( $($arg),+ );
}
}
};
// Coalesce helper to construct an expression only if a config is provided

View file

@ -7,7 +7,7 @@ use core::f64;
pub fn trunc(x: f64) -> f64 {
select_implementation! {
name: trunc,
use_intrinsic: target_arch = "wasm32",
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}

View file

@ -7,7 +7,7 @@ use core::f32;
pub fn truncf(x: f32) -> f32 {
select_implementation! {
name: truncf,
use_intrinsic: target_arch = "wasm32",
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}