diff --git a/Cargo.toml b/Cargo.toml index 181000f3..f811877b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,10 @@ unstable = [] # Used to prevent using any intrinsics or arch-specific code. force-soft-floats = [] +# Workaround for codegen backends which haven't yet implemented `f16` and +# `f128` support. Disabled any intrinsics which use those types. +no-f16-f128 = [] + [workspace] members = [ "crates/compiler-builtins-smoke-test", diff --git a/build.rs b/build.rs index 653ccf79..23ff3568 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,8 @@ use std::env; fn main() { + let cfg = Target::from_env(); + println!("cargo:rerun-if-changed=build.rs"); println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); println!("cargo::rustc-check-cfg=cfg(feature, values(\"unstable\"))"); @@ -14,4 +16,97 @@ fn main() { println!("cargo:rustc-cfg=assert_no_panic"); } } + + configure_f16_f128(&cfg); +} + +#[derive(Debug)] +#[allow(dead_code)] +pub struct Target { + pub triple: String, + pub os: String, + pub arch: String, + pub vendor: String, + pub env: String, + pub pointer_width: u8, + pub little_endian: bool, + pub features: Vec, +} + +impl Target { + pub fn from_env() -> Self { + let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() { + "little" => true, + "big" => false, + x => panic!("unknown endian {x}"), + }; + + Self { + triple: env::var("TARGET").unwrap(), + os: env::var("CARGO_CFG_TARGET_OS").unwrap(), + arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(), + vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(), + env: env::var("CARGO_CFG_TARGET_ENV").unwrap(), + pointer_width: env::var("CARGO_CFG_TARGET_POINTER_WIDTH") + .unwrap() + .parse() + .unwrap(), + little_endian, + features: env::var("CARGO_CFG_TARGET_FEATURE") + .unwrap_or_default() + .split(",") + .map(ToOwned::to_owned) + .collect(), + } + } + + #[allow(dead_code)] + pub fn has_feature(&self, feature: &str) -> bool { + self.features.iter().any(|f| f == feature) + } +} + +/// Configure whether or not `f16` and `f128` support should be enabled. +pub fn configure_f16_f128(target: &Target) { + // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means + // that the backend will not crash when using these types. This does not mean that the + // backend does the right thing, or that the platform doesn't have ABI bugs. + // + // We do this here rather than in `rust-lang/rust` because configuring via cargo features is + // not straightforward. + // + // Original source of this list: + // + let (f16_ok, f128_ok) = match target.arch.as_str() { + // `f16` and `f128` both crash + "arm64ec" => (false, false), + // `f16` crashes + "s390x" => (false, true), + // `f128` crashes + "mips64" | "mips64r6" => (true, false), + // `f128` crashes + "powerpc64" if &target.os == "aix" => (true, false), + // `f128` crashes + "sparc" | "sparcv9" => (true, false), + // `f16` miscompiles + "wasm32" | "wasm64" => (false, true), + // Most everything else works as of LLVM 19 + _ => (true, true), + }; + + // If the no-f16-f128 feature is set, disable these types. The `unstable` feature is also + // required. + let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some() + || env::var_os("CARGO_FEATURE_UNSTABLE").is_none(); + + println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); + + if f16_ok && !disable_both { + println!("cargo::rustc-cfg=f16_enabled"); + } + + if f128_ok && !disable_both { + println!("cargo::rustc-cfg=f128_enabled"); + } } diff --git a/crates/compiler-builtins-smoke-test/build.rs b/crates/compiler-builtins-smoke-test/build.rs index 27d4a0e8..e74c89e9 100644 --- a/crates/compiler-builtins-smoke-test/build.rs +++ b/crates/compiler-builtins-smoke-test/build.rs @@ -1,3 +1,5 @@ fn main() { println!("cargo::rustc-check-cfg=cfg(assert_no_panic)"); + println!("cargo::rustc-check-cfg=cfg(f16_enabled)"); + println!("cargo::rustc-check-cfg=cfg(f128_enabled)"); } diff --git a/crates/libm-test/Cargo.toml b/crates/libm-test/Cargo.toml index 6367bdca..6545b50c 100644 --- a/crates/libm-test/Cargo.toml +++ b/crates/libm-test/Cargo.toml @@ -6,6 +6,7 @@ publish = false [features] default = [] +no-f16-f128 = ["libm/no-f16-f128"] # Generate tests which are random inputs and the outputs are calculated with # musl libc. diff --git a/crates/libm-test/build.rs b/crates/libm-test/build.rs index 3a49e3c5..2f11ad26 100644 --- a/crates/libm-test/build.rs +++ b/crates/libm-test/build.rs @@ -63,6 +63,7 @@ mod musl_reference_tests { let files = fs::read_dir(math_src) .unwrap() .map(|f| f.unwrap().path()) + .filter(|f| f.is_dir()) .collect::>(); let mut math = Vec::new(); diff --git a/src/lib.rs b/src/lib.rs index 23885ecf..c71f27af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,8 @@ #![no_std] #![cfg_attr(feature = "unstable", allow(internal_features))] #![cfg_attr(feature = "unstable", feature(core_intrinsics))] +#![cfg_attr(f128_enabled, feature(f128))] +#![cfg_attr(f16_enabled, feature(f16))] #![allow(clippy::unreadable_literal)] #![allow(clippy::many_single_char_names)] #![allow(clippy::needless_return)] diff --git a/src/math/traits/mod.rs b/src/math/traits/mod.rs index a1abd017..547003d5 100644 --- a/src/math/traits/mod.rs +++ b/src/math/traits/mod.rs @@ -171,8 +171,12 @@ macro_rules! float_impl { }; } +#[cfg(f16_enabled)] +float_impl!(f16, u16, i16, i8, 16, 10); float_impl!(f32, u32, i32, i16, 32, 23); float_impl!(f64, u64, i64, i16, 64, 52); +#[cfg(f128_enabled)] +float_impl!(f128, u128, i128, i16, 128, 112); /// Minimal integer implementations needed on all integer types, including wide integers. #[allow(dead_code)]