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

Add f16 and f128 configuration from compiler-builtins #374

Merged
merged 1 commit into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ arch = []

# This tells the compiler to assume that a Nightly toolchain is being used and
# that it should activate any useful Nightly things accordingly.
unstable = ["unstable-intrinsics"]
unstable = ["unstable-intrinsics", "unstable-float"]

# Enable calls to functions in `core::intrinsics`
unstable-intrinsics = []

# Make some internal things public for testing.
unstable-test-support = []

# Enable the nightly-only `f16` and `f128`.
unstable-float = []

# Used to prevent using any intrinsics or arch-specific code.
#
# HACK: this is a negative feature which is generally a bad idea in Cargo, but
Expand Down
30 changes: 5 additions & 25 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use std::env;

mod configure;

fn main() {
let cfg = configure::Config::from_env();

println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rustc-check-cfg=cfg(assert_no_panic)");

Expand All @@ -14,29 +18,5 @@ fn main() {
}
}

configure_intrinsics();
configure_arch();
}

/// Simplify the feature logic for enabling intrinsics so code only needs to use
/// `cfg(intrinsics_enabled)`.
fn configure_intrinsics() {
println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)");

// Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides
// to disable.
if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") {
println!("cargo:rustc-cfg=intrinsics_enabled");
}
}

/// Simplify the feature logic for enabling arch-specific features so code only needs to use
/// `cfg(arch_enabled)`.
fn configure_arch() {
println!("cargo:rustc-check-cfg=cfg(arch_enabled)");

// Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable.
if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") {
println!("cargo:rustc-cfg=arch_enabled");
}
configure::emit_libm_config(&cfg);
}
168 changes: 168 additions & 0 deletions configure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// Configuration shared with both libm and libm-test

use std::env;
use std::path::PathBuf;

#[allow(dead_code)]
pub struct Config {
pub manifest_dir: PathBuf,
pub out_dir: PathBuf,
pub opt_level: u8,
pub target_arch: String,
pub target_env: String,
pub target_family: Option<String>,
pub target_os: String,
pub target_string: String,
pub target_vendor: String,
pub target_features: Vec<String>,
}

impl Config {
pub fn from_env() -> Self {
let target_features = env::var("CARGO_CFG_TARGET_FEATURE")
.map(|feats| feats.split(',').map(ToOwned::to_owned).collect())
.unwrap_or_default();

Self {
manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()),
out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()),
opt_level: env::var("OPT_LEVEL").unwrap().parse().unwrap(),
target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(),
target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(),
target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(),
target_string: env::var("TARGET").unwrap(),
target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(),
target_features,
}
}
}

/// Libm gets most config options made available.
#[allow(dead_code)]
pub fn emit_libm_config(cfg: &Config) {
emit_intrinsics_cfg();
emit_arch_cfg();
emit_optimization_cfg(cfg);
emit_cfg_shorthands(cfg);
emit_f16_f128_cfg(cfg);
}

/// Tests don't need most feature-related config.
#[allow(dead_code)]
pub fn emit_test_config(cfg: &Config) {
emit_optimization_cfg(cfg);
emit_cfg_shorthands(cfg);
emit_f16_f128_cfg(cfg);
}

/// Simplify the feature logic for enabling intrinsics so code only needs to use
/// `cfg(intrinsics_enabled)`.
fn emit_intrinsics_cfg() {
println!("cargo:rustc-check-cfg=cfg(intrinsics_enabled)");

// Disabled by default; `unstable-intrinsics` enables again; `force-soft-floats` overrides
// to disable.
if cfg!(feature = "unstable-intrinsics") && !cfg!(feature = "force-soft-floats") {
println!("cargo:rustc-cfg=intrinsics_enabled");
}
}

/// Simplify the feature logic for enabling arch-specific features so code only needs to use
/// `cfg(arch_enabled)`.
fn emit_arch_cfg() {
println!("cargo:rustc-check-cfg=cfg(arch_enabled)");

// Enabled by default via the "arch" feature, `force-soft-floats` overrides to disable.
if cfg!(feature = "arch") && !cfg!(feature = "force-soft-floats") {
println!("cargo:rustc-cfg=arch_enabled");
}
}

/// Some tests are extremely slow. Emit a config option based on optimization level.
fn emit_optimization_cfg(cfg: &Config) {
println!("cargo:rustc-check-cfg=cfg(optimizations_enabled)");

if cfg.opt_level >= 2 {
println!("cargo:rustc-cfg=optimizations_enabled");
}
}

/// Provide an alias for common longer config combinations.
fn emit_cfg_shorthands(cfg: &Config) {
println!("cargo:rustc-check-cfg=cfg(x86_no_sse)");
if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") {
// Shorthand to detect i586 targets
println!("cargo:rustc-cfg=x86_no_sse");
}
}

/// Configure whether or not `f16` and `f128` support should be enabled.
fn emit_f16_f128_cfg(cfg: &Config) {
println!("cargo:rustc-check-cfg=cfg(f16_enabled)");
println!("cargo:rustc-check-cfg=cfg(f128_enabled)");

// `unstable-float` enables these features.
if !cfg!(feature = "unstable-float") {
return;
}

// 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 and generates code that can be called
// without crashing (no infinite recursion). This does not mean that the platform doesn't have
// ABI or other bugs.
//
// We do this here rather than in `rust-lang/rust` because configuring via cargo features is
// not straightforward.
//
// Original source of this list:
// <https://github.com/rust-lang/compiler-builtins/pull/652#issuecomment-2266151350>
let f16_enabled = match cfg.target_arch.as_str() {
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
"arm64ec" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/50374>
"s390x" => false,
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
// FIXME(llvm): loongarch fixed by <https://github.com/llvm/llvm-project/pull/107791>
"csky" => false,
"hexagon" => false,
"loongarch64" => false,
"mips" | "mips64" | "mips32r6" | "mips64r6" => false,
"powerpc" | "powerpc64" => false,
"sparc" | "sparc64" => false,
"wasm32" | "wasm64" => false,
// Most everything else works as of LLVM 19
_ => true,
};

let f128_enabled = match cfg.target_arch.as_str() {
// Unsupported (libcall is not supported) <https://github.com/llvm/llvm-project/issues/121122>
"amdgpu" => false,
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
"arm64ec" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/96432>
"mips64" | "mips64r6" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/95471>
"nvptx64" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/101545>
"powerpc64" if &cfg.target_os == "aix" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/41838>
"sparc" => false,
// Most everything else works as of LLVM 19
_ => true,
};

// If the feature is set, disable these types.
let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some();

println!("cargo:rustc-check-cfg=cfg(f16_enabled)");
println!("cargo:rustc-check-cfg=cfg(f128_enabled)");

if f16_enabled && !disable_both {
println!("cargo:rustc-cfg=f16_enabled");
}

if f128_enabled && !disable_both {
println!("cargo:rustc-cfg=f128_enabled");
}
}
2 changes: 2 additions & 0 deletions crates/compiler-builtins-smoke-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ force-soft-floats = []
unexpected_cfgs = { level = "warn", check-cfg = [
"cfg(arch_enabled)",
"cfg(assert_no_panic)",
"cfg(f128_enabled)",
"cfg(f16_enabled)",
"cfg(intrinsics_enabled)",
] }
7 changes: 7 additions & 0 deletions crates/libm-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@ heck = "0.5.0"
proc-macro2 = "1.0.88"
quote = "1.0.37"
syn = { version = "2.0.79", features = ["full", "extra-traits", "visit-mut"] }

[lints.rust]
# Values used during testing
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(f16_enabled)',
'cfg(f128_enabled)',
] }
11 changes: 10 additions & 1 deletion crates/libm-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ edition = "2021"
publish = false

[features]
default = []
default = ["unstable-float"]

# Propagated from libm because this affects which functions we test.
unstable-float = ["libm/unstable-float"]

# Generate tests which are random inputs and the outputs are calculated with
# musl libc.
Expand Down Expand Up @@ -44,3 +47,9 @@ criterion = { version = "0.5.1", default-features = false, features = ["cargo_be
[[bench]]
name = "random"
harness = false

[lints.rust]
# Values from the chared config.rs used by `libm` but not the test crate
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(feature, values("arch", "force-soft-floats", "unstable-intrinsics"))',
] }
62 changes: 6 additions & 56 deletions crates/libm-test/build.rs
Original file line number Diff line number Diff line change
@@ -1,66 +1,16 @@
use std::fmt::Write;
use std::path::PathBuf;
use std::{env, fs};
use std::fs;

#[path = "../../configure.rs"]
mod configure;
use configure::Config;

fn main() {
let cfg = Config::from_env();

emit_optimization_cfg(&cfg);
emit_cfg_shorthands(&cfg);
list_all_tests(&cfg);
}

#[allow(dead_code)]
struct Config {
manifest_dir: PathBuf,
out_dir: PathBuf,
opt_level: u8,
target_arch: String,
target_env: String,
target_family: Option<String>,
target_os: String,
target_string: String,
target_vendor: String,
target_features: Vec<String>,
}

impl Config {
fn from_env() -> Self {
let target_features = env::var("CARGO_CFG_TARGET_FEATURE")
.map(|feats| feats.split(',').map(ToOwned::to_owned).collect())
.unwrap_or_default();

Self {
manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()),
out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()),
opt_level: env::var("OPT_LEVEL").unwrap().parse().unwrap(),
target_arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(),
target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(),
target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(),
target_string: env::var("TARGET").unwrap(),
target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(),
target_features,
}
}
}

/// Some tests are extremely slow. Emit a config option based on optimization level.
fn emit_optimization_cfg(cfg: &Config) {
println!("cargo::rustc-check-cfg=cfg(optimizations_enabled)");

if cfg.opt_level >= 2 {
println!("cargo::rustc-cfg=optimizations_enabled");
}
}

/// Provide an alias for common longer config combinations.
fn emit_cfg_shorthands(cfg: &Config) {
println!("cargo::rustc-check-cfg=cfg(x86_no_sse)");
if cfg.target_arch == "x86" && !cfg.target_features.iter().any(|f| f == "sse") {
// Shorthand to detect i586 targets
println!("cargo::rustc-cfg=x86_no_sse");
}
configure::emit_test_config(&cfg);
}

/// Create a list of all source files in an array. This can be used for making sure that
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#![no_std]
#![cfg_attr(intrinsics_enabled, allow(internal_features))]
#![cfg_attr(intrinsics_enabled, feature(core_intrinsics))]
#![cfg_attr(f128_enabled, feature(f128))]
#![cfg_attr(f16_enabled, feature(f16))]
#![allow(clippy::assign_op_pattern)]
#![allow(clippy::deprecated_cfg_attr)]
#![allow(clippy::eq_op)]
Expand Down
4 changes: 4 additions & 0 deletions src/math/support/float_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,5 +219,9 @@ 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);