Skip to content

Commit dfa178a

Browse files
committed
Implement the internal feature cfg_target_has_reliable_f16_f128
Support for `f16` and `f128` is varied across targets, backends, and backend versions. Eventually we would like to reach a point where all backends support these approximately equally, but until then we have to work around some of these nuances of support being observable. Introduce the `cfg_target_has_reliable_f16_f128` internal feature, which provides the following new configuration gates: * `cfg(target_has_reliable_f16)` * `cfg(target_has_reliable_f16_math)` * `cfg(target_has_reliable_f128)` * `cfg(target_has_reliable_f128_math)` `reliable_f16` and `reliable_f128` indicate that basic arithmetic for the type works correctly. The `_math` versions indicate that anything relying on `libm` works correctly, since sometimes this hits a separate class of codegen bugs. These options match configuration set by the build script at [1]. The logic for LLVM support is duplicated as-is from the same script. There are a few possible updates that will come as a follow up. The config introduced here is not planned to ever become stable, it is only intended to replace the build scripts for `std` tests and `compiler-builtins` that don't have any way to configure based on the codegen backend. MCP: rust-lang/compiler-team#866 Closes: rust-lang/compiler-team#866 [1]: https://github.com/rust-lang/rust/blob/555e1d0386f024a8359645c3217f4b3eae9be042/library/std/build.rs#L84-L186
1 parent 555e1d0 commit dfa178a

28 files changed

+291
-34
lines changed

compiler/rustc_codegen_cranelift/src/lib.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ use std::sync::Arc;
4141

4242
use cranelift_codegen::isa::TargetIsa;
4343
use cranelift_codegen::settings::{self, Configurable};
44-
use rustc_codegen_ssa::CodegenResults;
4544
use rustc_codegen_ssa::traits::CodegenBackend;
45+
use rustc_codegen_ssa::{CodegenResults, TargetFeatureCfg};
4646
use rustc_metadata::EncodedMetadata;
4747
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
4848
use rustc_session::Session;
@@ -178,7 +178,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
178178
}
179179
}
180180

181-
fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
181+
fn target_features_cfg(&self, sess: &Session) -> TargetFeatureCfg {
182182
// FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
183183
let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" {
184184
// x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled
@@ -197,7 +197,16 @@ impl CodegenBackend for CraneliftCodegenBackend {
197197
};
198198
// FIXME do `unstable_target_features` properly
199199
let unstable_target_features = target_features.clone();
200-
(target_features, unstable_target_features)
200+
201+
TargetFeatureCfg {
202+
target_features,
203+
unstable_target_features,
204+
// Cranelift does not yet support f16 or f128
205+
has_reliable_f16: false,
206+
has_reliable_f16_math: false,
207+
has_reliable_f128: false,
208+
has_reliable_f128_math: false,
209+
}
201210
}
202211

203212
fn print_version(&self) {

compiler/rustc_codegen_gcc/src/lib.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ use rustc_codegen_ssa::back::write::{
102102
};
103103
use rustc_codegen_ssa::base::codegen_crate;
104104
use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};
105-
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
105+
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetFeatureCfg};
106106
use rustc_data_structures::fx::FxIndexMap;
107107
use rustc_data_structures::sync::IntoDynSyncSend;
108108
use rustc_errors::DiagCtxtHandle;
@@ -260,7 +260,7 @@ impl CodegenBackend for GccCodegenBackend {
260260
.join(sess)
261261
}
262262

263-
fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
263+
fn target_features_cfg(&self, sess: &Session) -> TargetFeatureCfg {
264264
target_features_cfg(sess, &self.target_info)
265265
}
266266
}
@@ -485,10 +485,7 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
485485
}
486486

487487
/// Returns the features that should be set in `cfg(target_feature)`.
488-
fn target_features_cfg(
489-
sess: &Session,
490-
target_info: &LockedTargetInfo,
491-
) -> (Vec<Symbol>, Vec<Symbol>) {
488+
fn target_features_cfg(sess: &Session, target_info: &LockedTargetInfo) -> TargetFeatureCfg {
492489
// TODO(antoyo): use global_gcc_features.
493490
let f = |allow_unstable| {
494491
sess.target
@@ -523,5 +520,14 @@ fn target_features_cfg(
523520

524521
let target_features = f(false);
525522
let unstable_target_features = f(true);
526-
(target_features, unstable_target_features)
523+
524+
TargetFeatureCfg {
525+
target_features,
526+
unstable_target_features,
527+
// There are no known bugs with GCC support for f16 or f128
528+
has_reliable_f16: true,
529+
has_reliable_f16_math: true,
530+
has_reliable_f128: true,
531+
has_reliable_f128_math: true,
532+
}
527533
}

compiler/rustc_codegen_llvm/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use rustc_codegen_ssa::back::write::{
3737
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
3838
};
3939
use rustc_codegen_ssa::traits::*;
40-
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
40+
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetFeatureCfg};
4141
use rustc_data_structures::fx::FxIndexMap;
4242
use rustc_errors::{DiagCtxtHandle, FatalError};
4343
use rustc_metadata::EncodedMetadata;
@@ -338,7 +338,7 @@ impl CodegenBackend for LlvmCodegenBackend {
338338
llvm_util::print_version();
339339
}
340340

341-
fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
341+
fn target_features_cfg(&self, sess: &Session) -> TargetFeatureCfg {
342342
target_features_cfg(sess)
343343
}
344344

compiler/rustc_codegen_llvm/src/llvm_util.rs

+85-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::sync::Once;
66
use std::{ptr, slice, str};
77

88
use libc::c_int;
9+
use rustc_codegen_ssa::TargetFeatureCfg;
910
use rustc_codegen_ssa::base::wants_wasm_eh;
1011
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
1112
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -302,7 +303,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
302303
/// Must express features in the way Rust understands them.
303304
///
304305
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
305-
pub(crate) fn target_features_cfg(sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
306+
pub(crate) fn target_features_cfg(sess: &Session) -> TargetFeatureCfg {
306307
// Add base features for the target.
307308
// We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below.
308309
// The reason is that if LLVM considers a feature implied but we do not, we don't want that to
@@ -402,7 +403,89 @@ pub(crate) fn target_features_cfg(sess: &Session) -> (Vec<Symbol>, Vec<Symbol>)
402403

403404
let target_features = f(false);
404405
let unstable_target_features = f(true);
405-
(target_features, unstable_target_features)
406+
let mut cfg = TargetFeatureCfg {
407+
target_features,
408+
unstable_target_features,
409+
has_reliable_f16: true,
410+
has_reliable_f16_math: true,
411+
has_reliable_f128: true,
412+
has_reliable_f128_math: true,
413+
};
414+
415+
update_target_reliable_float_cfg(sess, &mut cfg);
416+
cfg
417+
}
418+
419+
/// Determine whether or not experimental float types are reliable based on known bugs.
420+
fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetFeatureCfg) {
421+
let target_arch = sess.target.arch.as_ref();
422+
let target_os = sess.target.options.os.as_ref();
423+
let target_env = sess.target.options.env.as_ref();
424+
let target_abi = sess.target.options.abi.as_ref();
425+
let target_pointer_width = sess.target.pointer_width;
426+
427+
cfg.has_reliable_f16 = match (target_arch, target_os) {
428+
// Selection failure <https://github.com/llvm/llvm-project/issues/50374>
429+
("s390x", _) => false,
430+
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
431+
("arm64ec", _) => false,
432+
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
433+
("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
434+
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
435+
("csky", _) => false,
436+
("hexagon", _) => false,
437+
("powerpc" | "powerpc64", _) => false,
438+
("sparc" | "sparc64", _) => false,
439+
("wasm32" | "wasm64", _) => false,
440+
// `f16` support only requires that symbols converting to and from `f32` are available. We
441+
// provide these in `compiler-builtins`, so `f16` should be available on all platforms that
442+
// do not have other ABI issues or LLVM crashes.
443+
_ => true,
444+
};
445+
446+
cfg.has_reliable_f128 = match (target_arch, target_os) {
447+
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
448+
("arm64ec", _) => false,
449+
// Selection bug <https://github.com/llvm/llvm-project/issues/96432>
450+
("mips64" | "mips64r6", _) => false,
451+
// Selection bug <https://github.com/llvm/llvm-project/issues/95471>
452+
("nvptx64", _) => false,
453+
// ABI bugs <https://github.com/rust-lang/rust/issues/125109> et al. (full
454+
// list at <https://github.com/rust-lang/rust/issues/116909>)
455+
("powerpc" | "powerpc64", _) => false,
456+
// ABI unsupported <https://github.com/llvm/llvm-project/issues/41838>
457+
("sparc", _) => false,
458+
// Stack alignment bug <https://github.com/llvm/llvm-project/issues/77401>. NB: tests may
459+
// not fail if our compiler-builtins is linked.
460+
("x86", _) => false,
461+
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
462+
("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
463+
// There are no known problems on other platforms, so the only requirement is that symbols
464+
// are available. `compiler-builtins` provides all symbols required for core `f128`
465+
// support, so this should work for everything else.
466+
_ => true,
467+
};
468+
469+
cfg.has_reliable_f16_math = match (target_arch, target_os) {
470+
// x86 has a crash for `powi`: <https://github.com/llvm/llvm-project/issues/105747>
471+
("x86" | "x86_64", _) => false,
472+
// Assume that working `f16` means working `f16` math for most platforms, since
473+
// operations just go through `f32`.
474+
_ => true,
475+
} && cfg.has_reliable_f16;
476+
477+
cfg.has_reliable_f128_math = match (target_arch, target_os) {
478+
// LLVM lowers `fp128` math to `long double` symbols even on platforms where
479+
// `long double` is not IEEE binary128. See
480+
// <https://github.com/llvm/llvm-project/issues/44744>.
481+
//
482+
// This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits
483+
// (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86`
484+
// (ld is 80-bit extended precision).
485+
("x86_64", _) => false,
486+
(_, "linux") if target_pointer_width == 64 => true,
487+
_ => false,
488+
} && cfg.has_reliable_f128;
406489
}
407490

408491
pub(crate) fn print_version() {

compiler/rustc_codegen_ssa/src/lib.rs

+18
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,24 @@ pub struct CrateInfo {
235235
pub lint_levels: CodegenLintLevels,
236236
}
237237

238+
/// Target-specific feature support.
239+
///
240+
/// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
241+
pub struct TargetFeatureCfg {
242+
/// Options to be set in `cfg(target_features)`.
243+
pub target_features: Vec<Symbol>,
244+
/// Options to be set in `cfg(target_features)`, but including unstable features.
245+
pub unstable_target_features: Vec<Symbol>,
246+
/// Option for `cfg(target_has_reliable_f16)`, true if `f16` basic arithmetic works.
247+
pub has_reliable_f16: bool,
248+
/// Option for `cfg(target_has_reliable_f16_math)`, true if `f16` math calls work.
249+
pub has_reliable_f16_math: bool,
250+
/// Option for `cfg(target_has_reliable_f128)`, true if `f128` basic arithmetic works.
251+
pub has_reliable_f128: bool,
252+
/// Option for `cfg(target_has_reliable_f128_math)`, true if `f128` math calls work.
253+
pub has_reliable_f128_math: bool,
254+
}
255+
238256
#[derive(Encodable, Decodable)]
239257
pub struct CodegenResults {
240258
pub modules: Vec<CompiledModule>,

compiler/rustc_codegen_ssa/src/traits/backend.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use super::write::WriteBackendMethods;
1818
use crate::back::archive::ArArchiveBuilderBuilder;
1919
use crate::back::link::link_binary;
2020
use crate::back::write::TargetMachineFactoryFn;
21-
use crate::{CodegenResults, ModuleCodegen};
21+
use crate::{CodegenResults, ModuleCodegen, TargetFeatureCfg};
2222

2323
pub trait BackendTypes {
2424
type Value: CodegenObject;
@@ -50,8 +50,15 @@ pub trait CodegenBackend {
5050
/// - The second is like the first, but also includes unstable features.
5151
///
5252
/// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
53-
fn target_features_cfg(&self, _sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
54-
(vec![], vec![])
53+
fn target_features_cfg(&self, _sess: &Session) -> TargetFeatureCfg {
54+
TargetFeatureCfg {
55+
target_features: vec![],
56+
unstable_target_features: vec![],
57+
has_reliable_f16: true,
58+
has_reliable_f16_math: true,
59+
has_reliable_f128: true,
60+
has_reliable_f128_math: true,
61+
}
5562
}
5663

5764
fn print_passes(&self) {}

compiler/rustc_feature/src/builtin_attrs.rs

+20
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,26 @@ const GATED_CFGS: &[GatedCfg] = &[
4040
// this is consistent with naming of the compiler flag it's for
4141
(sym::fmt_debug, sym::fmt_debug, Features::fmt_debug),
4242
(sym::emscripten_wasm_eh, sym::cfg_emscripten_wasm_eh, Features::cfg_emscripten_wasm_eh),
43+
(
44+
sym::target_has_reliable_f16,
45+
sym::cfg_target_has_reliable_f16_f128,
46+
Features::cfg_target_has_reliable_f16_f128,
47+
),
48+
(
49+
sym::target_has_reliable_f16_math,
50+
sym::cfg_target_has_reliable_f16_f128,
51+
Features::cfg_target_has_reliable_f16_f128,
52+
),
53+
(
54+
sym::target_has_reliable_f128,
55+
sym::cfg_target_has_reliable_f16_f128,
56+
Features::cfg_target_has_reliable_f16_f128,
57+
),
58+
(
59+
sym::target_has_reliable_f128_math,
60+
sym::cfg_target_has_reliable_f16_f128,
61+
Features::cfg_target_has_reliable_f16_f128,
62+
),
4363
];
4464

4565
/// Find a gated cfg determined by the `pred`icate which is given the cfg's name.

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ declare_features! (
205205
(unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None),
206206
/// Allows access to the emscripten_wasm_eh config, used by panic_unwind and unwind
207207
(internal, cfg_emscripten_wasm_eh, "1.86.0", None),
208+
/// Allows checking whether or not the backend correctly supports unstable float types.
209+
(internal, cfg_target_has_reliable_f16_f128, "CURRENT_RUSTC_VERSION", None),
208210
/// Allows identifying the `compiler_builtins` crate.
209211
(internal, compiler_builtins, "1.13.0", None),
210212
/// Allows writing custom MIR

compiler/rustc_interface/src/util.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,25 @@ pub(crate) fn add_configuration(
3838
codegen_backend: &dyn CodegenBackend,
3939
) {
4040
let tf = sym::target_feature;
41+
let tf_cfg = codegen_backend.target_features_cfg(sess);
4142

42-
let (target_features, unstable_target_features) = codegen_backend.target_features_cfg(sess);
43+
sess.unstable_target_features.extend(tf_cfg.unstable_target_features.iter().copied());
44+
sess.target_features.extend(tf_cfg.target_features.iter().copied());
4345

44-
sess.unstable_target_features.extend(unstable_target_features.iter().copied());
46+
cfg.extend(tf_cfg.target_features.into_iter().map(|feat| (tf, Some(feat))));
4547

46-
sess.target_features.extend(target_features.iter().copied());
47-
48-
cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat))));
48+
if tf_cfg.has_reliable_f16 {
49+
cfg.insert((sym::target_has_reliable_f16, None));
50+
}
51+
if tf_cfg.has_reliable_f16_math {
52+
cfg.insert((sym::target_has_reliable_f16_math, None));
53+
}
54+
if tf_cfg.has_reliable_f128 {
55+
cfg.insert((sym::target_has_reliable_f128, None));
56+
}
57+
if tf_cfg.has_reliable_f128_math {
58+
cfg.insert((sym::target_has_reliable_f128_math, None));
59+
}
4960

5061
if sess.crt_static(None) {
5162
cfg.insert((tf, Some(sym::crt_dash_static)));

compiler/rustc_session/src/config/cfg.rs

+9
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
142142
| (sym::target_has_atomic, Some(_))
143143
| (sym::target_has_atomic_equal_alignment, Some(_))
144144
| (sym::target_has_atomic_load_store, Some(_))
145+
| (sym::target_has_reliable_f16, Some(_))
146+
| (sym::target_has_reliable_f16_math, Some(_))
147+
| (sym::target_has_reliable_f128, Some(_))
148+
| (sym::target_has_reliable_f128_math, Some(_))
145149
| (sym::target_thread_local, None) => disallow(cfg, "--target"),
146150
(sym::fmt_debug, None | Some(_)) => disallow(cfg, "-Z fmt-debug"),
147151
(sym::emscripten_wasm_eh, None | Some(_)) => disallow(cfg, "-Z emscripten_wasm_eh"),
@@ -463,6 +467,11 @@ impl CheckCfg {
463467
ins!(sym, no_values).extend(atomic_values);
464468
}
465469

470+
ins!(sym::target_has_reliable_f16, no_values);
471+
ins!(sym::target_has_reliable_f16_math, no_values);
472+
ins!(sym::target_has_reliable_f128, no_values);
473+
ins!(sym::target_has_reliable_f128_math, no_values);
474+
466475
ins!(sym::target_thread_local, no_values);
467476

468477
ins!(sym::ub_checks, no_values);

compiler/rustc_span/src/symbol.rs

+5
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ symbols! {
623623
cfg_target_feature,
624624
cfg_target_has_atomic,
625625
cfg_target_has_atomic_equal_alignment,
626+
cfg_target_has_reliable_f16_f128,
626627
cfg_target_thread_local,
627628
cfg_target_vendor,
628629
cfg_trace: "<cfg>", // must not be a valid identifier
@@ -2073,6 +2074,10 @@ symbols! {
20732074
target_has_atomic,
20742075
target_has_atomic_equal_alignment,
20752076
target_has_atomic_load_store,
2077+
target_has_reliable_f128,
2078+
target_has_reliable_f128_math,
2079+
target_has_reliable_f16,
2080+
target_has_reliable_f16_math,
20762081
target_os,
20772082
target_pointer_width,
20782083
target_thread_local,

src/doc/rustc/src/check-cfg.md

+4
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ As of `2025-01-02T`, the list of known names is as follows:
126126
- `target_has_atomic`
127127
- `target_has_atomic_equal_alignment`
128128
- `target_has_atomic_load_store`
129+
- `target_has_reliable_f16`
130+
- `target_has_reliable_f16_math`
131+
- `target_has_reliable_f128`
132+
- `target_has_reliable_f128_math`
129133
- `target_os`
130134
- `target_pointer_width`
131135
- `target_thread_local`

tests/ui/check-cfg/cargo-build-script.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `has_foo`
44
LL | #[cfg(has_foo)]
55
| ^^^^^^^
66
|
7-
= help: expected names are: `has_bar` and 31 more
7+
= help: expected names are: `has_bar` and 35 more
88
= help: consider using a Cargo feature instead
99
= help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
1010
[lints.rust]

tests/ui/check-cfg/cargo-feature.none.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ warning: unexpected `cfg` condition name: `tokio_unstable`
2525
LL | #[cfg(tokio_unstable)]
2626
| ^^^^^^^^^^^^^^
2727
|
28-
= help: expected names are: `docsrs`, `feature`, and `test` and 31 more
28+
= help: expected names are: `docsrs`, `feature`, and `test` and 35 more
2929
= help: consider using a Cargo feature instead
3030
= help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
3131
[lints.rust]

0 commit comments

Comments
 (0)