mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
refactor(lexer): order variants of DynCpu per architecture (#28774)
Define `DynCpu` separately for each architecture, so its variants can be in a different order on each. `Generic` is always first, then the SIMD feature set which the platform has, then the variants which can't exist on the platform: - x86_64: `Generic`, `Avx2`, `Neon`. - aarch64: `Generic`, `Neon`, `Avx2`. - Other platforms: `Generic`, `Avx2`, `Neon`. `Generic` is always 0, and the platform's SIMD feature set is 1. Uninhabited variants don't exist at runtime, so `DynCpu` is like a `bool`. On aarch64 with Neon enabled at compile time, and on other platforms, only one variant can exist, so `DynCpu` is zero-sized. Each variant which can't exist on the platform is `#[expect(dead_code)]`, with no `cfg_attr` needed. This alters codegen slightly in a few places, but those changes are entirely incidental - same instructions but in a different order, and only in code which only runs once per lex.
This commit is contained in:
1 parent
84a5cd9906
commit
f8fa6b2a03
1 file changed
+64
-14
@@ -119,6 +119,18 @@ trait CpuPrivate {
|
||||
const DYN_CPU: Option<DynCpu>;
|
||||
}
|
||||
|
||||
// `DynCpu` is defined differently for each architecture.
|
||||
//
|
||||
// All variants exist on all architectures, but variants impossible on each architecture
|
||||
// are uninhabited. This allows code for all architectures to be compiled and linted
|
||||
// on any machine, and Rust Analyzer sees all the code for all archs "as one".
|
||||
// But the uninhabited variants allow compiler to apply dead code removal to code paths
|
||||
// which aren't for the architecture crate is being compiled for.
|
||||
//
|
||||
// Variants are ordered so that `Generic` is always 0, and the SIMD feature set
|
||||
// available on the platform is 1. Uninhabited variants don't exist at runtime,
|
||||
// so this type behaves like a `bool`.
|
||||
|
||||
/// Enum representing a CPU feature set.
|
||||
///
|
||||
/// Used for runtime feature detection.
|
||||
@@ -127,26 +139,64 @@ trait CpuPrivate {
|
||||
/// via target feature detection.
|
||||
///
|
||||
/// [`detect`]: Self::detect
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum DynCpu {
|
||||
/// AVX2 feature set.
|
||||
/// Exists on all platforms, but can only be created on x86_64. See [`Avx2`].
|
||||
#[cfg_attr(not(target_arch = "x86_64"), expect(dead_code))]
|
||||
Avx2(Avx2),
|
||||
/// Generic feature set.
|
||||
/// Exists on all platforms, but can never be created on aarch64
|
||||
/// when Neon is enabled at compile time. See [`Generic`].
|
||||
#[cfg_attr(all(target_arch = "aarch64", target_feature = "neon"), expect(dead_code))]
|
||||
Generic(Generic),
|
||||
// `Neon` is last. rustc numbers variants in the order they're declared, uninhabited ones too.
|
||||
// So on x86_64, where `Neon` is uninhabited, the 2 variants which can exist are 0 and 1,
|
||||
// like a `bool`.
|
||||
/// Neon feature set.
|
||||
/// Exists on all platforms, but can only be created on aarch64. See [`Neon`].
|
||||
#[cfg_attr(not(target_arch = "aarch64"), expect(dead_code))]
|
||||
Avx2(Avx2),
|
||||
#[expect(dead_code)]
|
||||
Neon(Neon),
|
||||
}
|
||||
|
||||
/// Enum representing a CPU feature set.
|
||||
///
|
||||
/// Used for runtime feature detection.
|
||||
///
|
||||
/// Implements [`Cpu`] and also provides a [`detect`] method which initializes [`DynCpu`]
|
||||
/// via target feature detection.
|
||||
///
|
||||
/// [`detect`]: Self::detect
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum DynCpu {
|
||||
// Can never be created on aarch64 when Neon is enabled at compile time. See `Generic`.
|
||||
#[cfg_attr(target_feature = "neon", expect(dead_code))]
|
||||
Generic(Generic),
|
||||
Neon(Neon),
|
||||
#[expect(dead_code)]
|
||||
Avx2(Avx2),
|
||||
}
|
||||
|
||||
/// Enum representing a CPU feature set.
|
||||
///
|
||||
/// Used for runtime feature detection.
|
||||
///
|
||||
/// Implements [`Cpu`] and also provides a [`detect`] method which initializes [`DynCpu`]
|
||||
/// via target feature detection.
|
||||
///
|
||||
/// [`detect`]: Self::detect
|
||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum DynCpu {
|
||||
Generic(Generic),
|
||||
#[expect(dead_code)]
|
||||
Avx2(Avx2),
|
||||
#[expect(dead_code)]
|
||||
Neon(Neon),
|
||||
}
|
||||
|
||||
/// On aarch64 with neon enabled, [`DynCpu`] has only 1 inhabited variant, so is a ZST.
|
||||
/// Ditto when arch is not x86_64 or aarch64.
|
||||
/// On all other platforms it's 1 byte.
|
||||
const _: () = {
|
||||
let expected_size = cfg_select! {
|
||||
all(target_arch = "aarch64", target_feature = "neon") => 0,
|
||||
not(any(target_arch = "x86_64", target_arch = "aarch64")) => 0,
|
||||
_ => 1,
|
||||
};
|
||||
assert!(size_of::<DynCpu>() == expected_size);
|
||||
};
|
||||
|
||||
impl Cpu for DynCpu {}
|
||||
|
||||
impl CpuPrivate for DynCpu {
|
||||
|
||||
Reference in new issue
Block a user