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: https://github.com/rust-lang/compiler-team/issues/866
Closes: https://github.com/rust-lang/compiler-team/issues/866
[1]: 555e1d0386/library/std/build.rs (L84-L186)
This commit is contained in:
@@ -29,7 +29,7 @@ use back::owned_target_machine::OwnedTargetMachine;
|
||||
use back::write::{create_informational_target_machine, create_target_machine};
|
||||
use context::SimpleCx;
|
||||
use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig};
|
||||
use llvm_util::target_features_cfg;
|
||||
use llvm_util::target_config;
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
|
||||
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
|
||||
@@ -37,7 +37,7 @@ use rustc_codegen_ssa::back::write::{
|
||||
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
|
||||
};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{DiagCtxtHandle, FatalError};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
@@ -338,8 +338,8 @@ impl CodegenBackend for LlvmCodegenBackend {
|
||||
llvm_util::print_version();
|
||||
}
|
||||
|
||||
fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||
target_features_cfg(sess)
|
||||
fn target_config(&self, sess: &Session) -> TargetConfig {
|
||||
target_config(sess)
|
||||
}
|
||||
|
||||
fn codegen_crate<'tcx>(
|
||||
|
||||
@@ -6,6 +6,7 @@ use std::sync::Once;
|
||||
use std::{ptr, slice, str};
|
||||
|
||||
use libc::c_int;
|
||||
use rustc_codegen_ssa::TargetConfig;
|
||||
use rustc_codegen_ssa::base::wants_wasm_eh;
|
||||
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
|
||||
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
|
||||
/// Must express features in the way Rust understands them.
|
||||
///
|
||||
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
|
||||
pub(crate) fn target_features_cfg(sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||
pub(crate) fn target_config(sess: &Session) -> TargetConfig {
|
||||
// Add base features for the target.
|
||||
// We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below.
|
||||
// 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>)
|
||||
|
||||
let target_features = f(false);
|
||||
let unstable_target_features = f(true);
|
||||
(target_features, unstable_target_features)
|
||||
let mut cfg = TargetConfig {
|
||||
target_features,
|
||||
unstable_target_features,
|
||||
has_reliable_f16: true,
|
||||
has_reliable_f16_math: true,
|
||||
has_reliable_f128: true,
|
||||
has_reliable_f128_math: true,
|
||||
};
|
||||
|
||||
update_target_reliable_float_cfg(sess, &mut cfg);
|
||||
cfg
|
||||
}
|
||||
|
||||
/// Determine whether or not experimental float types are reliable based on known bugs.
|
||||
fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
||||
let target_arch = sess.target.arch.as_ref();
|
||||
let target_os = sess.target.options.os.as_ref();
|
||||
let target_env = sess.target.options.env.as_ref();
|
||||
let target_abi = sess.target.options.abi.as_ref();
|
||||
let target_pointer_width = sess.target.pointer_width;
|
||||
|
||||
cfg.has_reliable_f16 = match (target_arch, target_os) {
|
||||
// Selection failure <https://github.com/llvm/llvm-project/issues/50374>
|
||||
("s390x", _) => false,
|
||||
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
|
||||
("arm64ec", _) => false,
|
||||
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
|
||||
("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
|
||||
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
|
||||
("csky", _) => false,
|
||||
("hexagon", _) => false,
|
||||
("powerpc" | "powerpc64", _) => false,
|
||||
("sparc" | "sparc64", _) => false,
|
||||
("wasm32" | "wasm64", _) => false,
|
||||
// `f16` support only requires that symbols converting to and from `f32` are available. We
|
||||
// provide these in `compiler-builtins`, so `f16` should be available on all platforms that
|
||||
// do not have other ABI issues or LLVM crashes.
|
||||
_ => true,
|
||||
};
|
||||
|
||||
cfg.has_reliable_f128 = match (target_arch, target_os) {
|
||||
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
|
||||
("arm64ec", _) => false,
|
||||
// Selection bug <https://github.com/llvm/llvm-project/issues/96432>
|
||||
("mips64" | "mips64r6", _) => false,
|
||||
// Selection bug <https://github.com/llvm/llvm-project/issues/95471>
|
||||
("nvptx64", _) => false,
|
||||
// ABI bugs <https://github.com/rust-lang/rust/issues/125109> et al. (full
|
||||
// list at <https://github.com/rust-lang/rust/issues/116909>)
|
||||
("powerpc" | "powerpc64", _) => false,
|
||||
// ABI unsupported <https://github.com/llvm/llvm-project/issues/41838>
|
||||
("sparc", _) => false,
|
||||
// Stack alignment bug <https://github.com/llvm/llvm-project/issues/77401>. NB: tests may
|
||||
// not fail if our compiler-builtins is linked.
|
||||
("x86", _) => false,
|
||||
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
|
||||
("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
|
||||
// There are no known problems on other platforms, so the only requirement is that symbols
|
||||
// are available. `compiler-builtins` provides all symbols required for core `f128`
|
||||
// support, so this should work for everything else.
|
||||
_ => true,
|
||||
};
|
||||
|
||||
cfg.has_reliable_f16_math = match (target_arch, target_os) {
|
||||
// x86 has a crash for `powi`: <https://github.com/llvm/llvm-project/issues/105747>
|
||||
("x86" | "x86_64", _) => false,
|
||||
// Assume that working `f16` means working `f16` math for most platforms, since
|
||||
// operations just go through `f32`.
|
||||
_ => true,
|
||||
} && cfg.has_reliable_f16;
|
||||
|
||||
cfg.has_reliable_f128_math = match (target_arch, target_os) {
|
||||
// LLVM lowers `fp128` math to `long double` symbols even on platforms where
|
||||
// `long double` is not IEEE binary128. See
|
||||
// <https://github.com/llvm/llvm-project/issues/44744>.
|
||||
//
|
||||
// This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits
|
||||
// (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86`
|
||||
// (ld is 80-bit extended precision).
|
||||
("x86_64", _) => false,
|
||||
(_, "linux") if target_pointer_width == 64 => true,
|
||||
_ => false,
|
||||
} && cfg.has_reliable_f128;
|
||||
}
|
||||
|
||||
pub(crate) fn print_version() {
|
||||
@@ -686,7 +769,7 @@ pub(crate) fn global_llvm_features(
|
||||
)
|
||||
} else if let Some(feature) = feature.strip_prefix('-') {
|
||||
// FIXME: Why do we not remove implied features on "-" here?
|
||||
// We do the equivalent above in `target_features_cfg`.
|
||||
// We do the equivalent above in `target_config`.
|
||||
// See <https://github.com/rust-lang/rust/issues/134792>.
|
||||
all_rust_features.push((false, feature));
|
||||
} else if !feature.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user