about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTrevor Gross <tmgross@umich.edu>2025-06-30 16:53:21 -0500
committerTrevor Gross <tmgross@umich.edu>2025-07-02 01:18:54 -0500
commitbe35d37d8b6c206576ff3cdcad956d921b47cc6b (patch)
treecaf31c698ab2f77edda0fa4be0f290c6fb0ad7df
parent6c4221818e00828ecf54b395475477f49d0ea716 (diff)
downloadrust-be35d37d8b6c206576ff3cdcad956d921b47cc6b.tar.gz
rust-be35d37d8b6c206576ff3cdcad956d921b47cc6b.zip
Use the compiler to determine whether or not to enable `f16` and `f128`
Currently we whether or not to build and test `f16` and `f128` support
mostly based on the target triple. This isn't always accurate, however,
since support also varies by backend and the backend version.

Since recently, `rustc` is aware of this with the unstable config option
`target_has_reliable_{f16,f128}`, which better represents when the types
are actually expected to be available and usable. Switch our
compiler-builtins and libm configuration to use this by probing `rustc`
for the target's settings.

A few small `cfg` fixes are needed with this.
-rw-r--r--library/compiler-builtins/builtins-test-intrinsics/build.rs1
-rw-r--r--library/compiler-builtins/builtins-test/benches/float_cmp.rs2
-rw-r--r--library/compiler-builtins/builtins-test/build.rs1
-rw-r--r--library/compiler-builtins/builtins-test/tests/conv.rs4
-rw-r--r--library/compiler-builtins/builtins-test/tests/div_rem.rs4
-rw-r--r--library/compiler-builtins/compiler-builtins/build.rs3
-rw-r--r--library/compiler-builtins/compiler-builtins/configure.rs81
-rw-r--r--library/compiler-builtins/libm/configure.rs81
8 files changed, 66 insertions, 111 deletions
diff --git a/library/compiler-builtins/builtins-test-intrinsics/build.rs b/library/compiler-builtins/builtins-test-intrinsics/build.rs
index 89b126ff2b2..b82581262f7 100644
--- a/library/compiler-builtins/builtins-test-intrinsics/build.rs
+++ b/library/compiler-builtins/builtins-test-intrinsics/build.rs
@@ -6,6 +6,5 @@ fn main() {
     println!("cargo::rerun-if-changed=../configure.rs");
 
     let target = builtins_configure::Target::from_env();
-    builtins_configure::configure_f16_f128(&target);
     builtins_configure::configure_aliases(&target);
 }
diff --git a/library/compiler-builtins/builtins-test/benches/float_cmp.rs b/library/compiler-builtins/builtins-test/benches/float_cmp.rs
index 87a89efb5a4..da29b5d3132 100644
--- a/library/compiler-builtins/builtins-test/benches/float_cmp.rs
+++ b/library/compiler-builtins/builtins-test/benches/float_cmp.rs
@@ -177,6 +177,7 @@ float_bench! {
     ],
 }
 
+#[cfg(f128_enabled)]
 float_bench! {
     name: cmp_f128_gt,
     sig: (a: f128, b: f128) -> CmpResult,
@@ -189,6 +190,7 @@ float_bench! {
     asm: []
 }
 
+#[cfg(f128_enabled)]
 float_bench! {
     name: cmp_f128_unord,
     sig: (a: f128, b: f128) -> CmpResult,
diff --git a/library/compiler-builtins/builtins-test/build.rs b/library/compiler-builtins/builtins-test/build.rs
index e8f4eb4dd22..5b2dcd12ef8 100644
--- a/library/compiler-builtins/builtins-test/build.rs
+++ b/library/compiler-builtins/builtins-test/build.rs
@@ -116,5 +116,4 @@ fn main() {
     }
 
     builtins_configure::configure_aliases(&target);
-    builtins_configure::configure_f16_f128(&target);
 }
diff --git a/library/compiler-builtins/builtins-test/tests/conv.rs b/library/compiler-builtins/builtins-test/tests/conv.rs
index 491915d9bb1..7d729364fae 100644
--- a/library/compiler-builtins/builtins-test/tests/conv.rs
+++ b/library/compiler-builtins/builtins-test/tests/conv.rs
@@ -118,7 +118,7 @@ mod i_to_f {
         i128, __floattidf;
     }
 
-    #[cfg(not(feature = "no-f16-f128"))]
+    #[cfg(f128_enabled)]
     #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
     i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"),
         u32, __floatunsitf;
@@ -129,7 +129,7 @@ mod i_to_f {
         i128, __floattitf;
     }
 
-    #[cfg(not(feature = "no-f16-f128"))]
+    #[cfg(f128_enabled)]
     #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
     i_to_f! { f128, Quad, not(feature = "no-sys-f128-int-convert"),
         u32, __floatunsikf;
diff --git a/library/compiler-builtins/builtins-test/tests/div_rem.rs b/library/compiler-builtins/builtins-test/tests/div_rem.rs
index 5ae653cc90c..e8327f9b4b8 100644
--- a/library/compiler-builtins/builtins-test/tests/div_rem.rs
+++ b/library/compiler-builtins/builtins-test/tests/div_rem.rs
@@ -147,7 +147,7 @@ mod float_div {
         f64, __divdf3, Double, all();
     }
 
-    #[cfg(not(feature = "no-f16-f128"))]
+    #[cfg(f128_enabled)]
     #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
     float! {
         f128, __divtf3, Quad,
@@ -156,7 +156,7 @@ mod float_div {
         not(any(feature = "no-sys-f128", all(target_arch = "aarch64", target_os = "linux")));
     }
 
-    #[cfg(not(feature = "no-f16-f128"))]
+    #[cfg(f128_enabled)]
     #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
     float! {
         f128, __divkf3, Quad, not(feature = "no-sys-f128");
diff --git a/library/compiler-builtins/compiler-builtins/build.rs b/library/compiler-builtins/compiler-builtins/build.rs
index 018899faf1d..8f51c12b535 100644
--- a/library/compiler-builtins/compiler-builtins/build.rs
+++ b/library/compiler-builtins/compiler-builtins/build.rs
@@ -2,7 +2,7 @@ mod configure;
 
 use std::env;
 
-use configure::{Target, configure_aliases, configure_f16_f128};
+use configure::{Target, configure_aliases};
 
 fn main() {
     println!("cargo::rerun-if-changed=build.rs");
@@ -12,7 +12,6 @@ fn main() {
     let cwd = env::current_dir().unwrap();
 
     configure_check_cfg();
-    configure_f16_f128(&target);
     configure_aliases(&target);
 
     configure_libm(&target);
diff --git a/library/compiler-builtins/compiler-builtins/configure.rs b/library/compiler-builtins/compiler-builtins/configure.rs
index d825f35a9aa..a1e45080e71 100644
--- a/library/compiler-builtins/compiler-builtins/configure.rs
+++ b/library/compiler-builtins/compiler-builtins/configure.rs
@@ -1,6 +1,7 @@
 // Configuration that is shared between `compiler_builtins` and `builtins_test`.
 
-use std::env;
+use std::process::{Command, Stdio};
+use std::{env, str};
 
 #[derive(Debug)]
 #[allow(dead_code)]
@@ -16,6 +17,8 @@ pub struct Target {
     pub pointer_width: u8,
     pub little_endian: bool,
     pub features: Vec<String>,
+    pub reliable_f128: bool,
+    pub reliable_f16: bool,
 }
 
 impl Target {
@@ -32,6 +35,19 @@ impl Target {
             .map(|s| s.to_lowercase().replace("_", "-"))
             .collect();
 
+        // Query rustc for options that Cargo does not provide env for. The bootstrap hack is used
+        // to get consistent output regardless of channel (`f16`/`f128` config options are hidden
+        // on stable otherwise).
+        let mut cmd = Command::new(env::var("RUSTC").unwrap());
+        cmd.args(["--print=cfg", "--target", &triple])
+            .env("RUSTC_BOOTSTRAP", "1")
+            .stderr(Stdio::inherit());
+        let out = cmd
+            .output()
+            .unwrap_or_else(|e| panic!("failed to run `{cmd:?}`: {e}"));
+        assert!(out.status.success(), "failed to run `{cmd:?}`");
+        let rustc_cfg = str::from_utf8(&out.stdout).unwrap();
+
         Self {
             triple,
             triple_split,
@@ -51,6 +67,8 @@ impl Target {
                 .split(",")
                 .map(ToOwned::to_owned)
                 .collect(),
+            reliable_f128: rustc_cfg.lines().any(|l| l == "target_has_reliable_f128"),
+            reliable_f16: rustc_cfg.lines().any(|l| l == "target_has_reliable_f16"),
         }
     }
 
@@ -74,63 +92,24 @@ pub fn configure_aliases(target: &Target) {
     if target.triple_split[0] == "thumbv6m" || target.triple_split[0] == "thumbv8m.base" {
         println!("cargo:rustc-cfg=thumb_1")
     }
-}
-
-/// 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 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 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>
-        "csky" => false,
-        "hexagon" => false,
-        "powerpc" | "powerpc64" => false,
-        "sparc" | "sparc64" => false,
-        "wasm32" | "wasm64" => false,
-        // Most everything else works as of LLVM 19
-        _ => true,
-    };
 
-    let f128_enabled = match 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,
-        // FIXME(llvm20): fixed by <https://github.com/llvm/llvm-project/pull/117525>
-        "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 &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,
-    };
+    /* Not all backends support `f16` and `f128` to the same level on all architectures, so we
+     * need to disable things if the compiler may crash. See configuration at:
+     * * https://github.com/rust-lang/rust/blob/c65dccabacdfd6c8a7f7439eba13422fdd89b91e/compiler/rustc_codegen_llvm/src/llvm_util.rs#L367-L432
+     * * https://github.com/rust-lang/rustc_codegen_gcc/blob/4b5c44b14166083eef8d71f15f5ea1f53fc976a0/src/lib.rs#L496-L507
+     * * https://github.com/rust-lang/rustc_codegen_cranelift/blob/c713ffab3c6e28ab4b4dd4e392330f786ea657ad/src/lib.rs#L196-L226
+     */
 
-    // If the feature is set, disable these types.
-    let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some();
+    // If the feature is set, disable both of these types.
+    let no_f16_f128 = target.cargo_features.iter().any(|s| s == "no-f16-f128");
 
     println!("cargo::rustc-check-cfg=cfg(f16_enabled)");
-    println!("cargo::rustc-check-cfg=cfg(f128_enabled)");
-
-    if f16_enabled && !disable_both {
+    if target.reliable_f16 && !no_f16_f128 {
         println!("cargo::rustc-cfg=f16_enabled");
     }
 
-    if f128_enabled && !disable_both {
+    println!("cargo::rustc-check-cfg=cfg(f128_enabled)");
+    if target.reliable_f128 && !no_f16_f128 {
         println!("cargo::rustc-cfg=f128_enabled");
     }
 }
diff --git a/library/compiler-builtins/libm/configure.rs b/library/compiler-builtins/libm/configure.rs
index 2a497c7b117..6562ecbe5db 100644
--- a/library/compiler-builtins/libm/configure.rs
+++ b/library/compiler-builtins/libm/configure.rs
@@ -1,7 +1,8 @@
 // Configuration shared with both libm and libm-test
 
-use std::env;
 use std::path::PathBuf;
+use std::process::{Command, Stdio};
+use std::{env, str};
 
 #[allow(dead_code)]
 pub struct Config {
@@ -9,6 +10,7 @@ pub struct Config {
     pub out_dir: PathBuf,
     pub opt_level: String,
     pub cargo_features: Vec<String>,
+    pub target_triple: String,
     pub target_arch: String,
     pub target_env: String,
     pub target_family: Option<String>,
@@ -16,10 +18,13 @@ pub struct Config {
     pub target_string: String,
     pub target_vendor: String,
     pub target_features: Vec<String>,
+    pub reliable_f128: bool,
+    pub reliable_f16: bool,
 }
 
 impl Config {
     pub fn from_env() -> Self {
+        let target_triple = env::var("TARGET").unwrap();
         let target_features = env::var("CARGO_CFG_TARGET_FEATURE")
             .map(|feats| feats.split(',').map(ToOwned::to_owned).collect())
             .unwrap_or_default();
@@ -28,7 +33,21 @@ impl Config {
             .map(|s| s.to_lowercase().replace("_", "-"))
             .collect();
 
+        // Query rustc for options that Cargo does not provide env for. The bootstrap hack is used
+        // to get consistent output regardless of channel (`f16`/`f128` config options are hidden
+        // on stable otherwise).
+        let mut cmd = Command::new(env::var("RUSTC").unwrap());
+        cmd.args(["--print=cfg", "--target", &target_triple])
+            .env("RUSTC_BOOTSTRAP", "1")
+            .stderr(Stdio::inherit());
+        let out = cmd
+            .output()
+            .unwrap_or_else(|e| panic!("failed to run `{cmd:?}`: {e}"));
+        assert!(out.status.success(), "failed to run `{cmd:?}`");
+        let rustc_cfg = str::from_utf8(&out.stdout).unwrap();
+
         Self {
+            target_triple,
             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(),
@@ -40,6 +59,8 @@ impl Config {
             target_string: env::var("TARGET").unwrap(),
             target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(),
             target_features,
+            reliable_f128: rustc_cfg.lines().any(|l| l == "target_has_reliable_f128"),
+            reliable_f16: rustc_cfg.lines().any(|l| l == "target_has_reliable_f16"),
         }
     }
 }
@@ -128,62 +149,18 @@ fn emit_f16_f128_cfg(cfg: &Config) {
         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();
+    /* See the compiler-builtins configure file for info about the meaning of these options */
 
-    println!("cargo:rustc-check-cfg=cfg(f16_enabled)");
-    println!("cargo:rustc-check-cfg=cfg(f128_enabled)");
+    // If the feature is set, disable both of these types.
+    let no_f16_f128 = cfg.cargo_features.iter().any(|s| s == "no-f16-f128");
 
-    if f16_enabled && !disable_both {
+    println!("cargo:rustc-check-cfg=cfg(f16_enabled)");
+    if cfg.reliable_f16 && !no_f16_f128 {
         println!("cargo:rustc-cfg=f16_enabled");
     }
 
-    if f128_enabled && !disable_both {
+    println!("cargo:rustc-check-cfg=cfg(f128_enabled)");
+    if cfg.reliable_f128 && !no_f16_f128 {
         println!("cargo:rustc-cfg=f128_enabled");
     }
 }