mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #140920 - RalfJung:target-feature-unification, r=nnethercote,WaffleLapkin
Extract some shared code from codegen backend target feature handling There's a bunch of code duplication between the GCC and LLVM backends in target feature handling. This moves that into new shared helper functions in `rustc_codegen_ssa`. The first two commits should be purely refactoring. I am fairly sure the LLVM-side behavior stays the same; if the GCC side deliberately diverges from this then I may have missed that. I did account for one divergence, which I do not know is deliberate or not: GCC does not seem to use the `-Ctarget-feature` flag to populate `cfg(target_feature)`. That seems odd, since the `-Ctarget-feature` flag is used to populate the return value of `global_gcc_features` which controls the target features actually used by GCC. ``@GuillaumeGomez`` ``@antoyo`` is there a reason `target_config` ignores `-Ctarget-feature` but `global_gcc_features` does not? The second commit also cleans up a bunch of unneeded complexity added in https://github.com/rust-lang/rust/pull/135927. The third commit extracts some shared logic out of the functions that populate `cfg(target_feature)` and the backend target feature set, respectively. This one actually has some slight functional changes: - Before, with `-Ctarget-feature=-feat`, if there is some other feature `x` that implies `feat` we would *not* add `-x` to the backend target feature set. Now, we do. This fixes rust-lang/rust#134792. - The logic that removes `x` from `cfg(target_feature)` in this case also changed a bit, avoiding a large number of calls to the (uncached) `sess.target.implied_target_features` (if there were a large number of positive features listed before a negative feature) but instead constructing a full inverse implication map when encountering the first negative feature. Ideally this would be done with queries but the backend target feature logic runs before `tcx` so we can't use that... - Previously, if feature "a" implied "b" and "b" was unstable, then using `-Ctarget-feature=+a` would also emit a warning about `b`. I had to remove this since when accounting for negative implications, this emits a ton of warnings in a bunch of existing tests... I assume this was unintentional anyway. The fourth commit increases consistency of the GCC backend with the LLVM backend. The last commit does some further cleanup: - Get rid of RUSTC_SPECIAL_FEATURES. It was only needed for s390x "backchain", but since LLVM 19 that is always a regular target feature so we don't need this hack any more. The hack also has various unintended side-effects so we don't want to keep it. Fixes https://github.com/rust-lang/rust/issues/142412. - Move RUSTC_SPECIFIC_FEATURES handling into the shared parse_rust_feature_flag helper so all consumers of `-Ctarget-feature` that only care about actual target features (and not "crt-static") have it. Previously, we actually set `cfg(target_feature = "crt-static")` twice: once in the backend target feature logic, and once specifically for that one feature. IIUC, some targets are meant to ignore `-Ctarget-feature=+crt-static`, it seems like before this PR that flag still incorrectly enabled `cfg(target_feature = "crt-static")` (but I didn't test this). - Move fixed_x18 handling together with retpoline handling. - Forbid setting fixed_x18 as a regular target feature, even unstably. It must be set via the `-Z` flag. ``@bjorn3`` I did not touch the cranelift backend here, since AFAIK it doesn't really support target features. But if you ever do, please use the new helpers. :) Cc ``@workingjubilee``
This commit is contained in:
@@ -1,7 +1,3 @@
|
||||
codegen_gcc_unknown_ctarget_feature_prefix =
|
||||
unknown feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = features must begin with a `+` to enable or `-` to disable it
|
||||
|
||||
codegen_gcc_unwinding_inline_asm =
|
||||
GCC backend does not support unwinding from inline asm
|
||||
|
||||
@@ -16,15 +12,3 @@ codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and st
|
||||
codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
|
||||
|
||||
codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err})
|
||||
|
||||
codegen_gcc_unknown_ctarget_feature =
|
||||
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
|
||||
.possible_feature = you might have meant: `{$rust_feature}`
|
||||
.consider_filing_feature_request = consider filing a feature request
|
||||
|
||||
codegen_gcc_missing_features =
|
||||
add the missing features in a `target_feature` attribute
|
||||
|
||||
codegen_gcc_target_feature_disable_or_enable =
|
||||
the target features {$features} must all be either enabled or disabled together
|
||||
|
||||
@@ -1,30 +1,6 @@
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_unknown_ctarget_feature_prefix)]
|
||||
#[note]
|
||||
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_unknown_ctarget_feature)]
|
||||
#[note]
|
||||
pub(crate) struct UnknownCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub rust_feature: PossibleFeature<'a>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum PossibleFeature<'a> {
|
||||
#[help(codegen_gcc_possible_feature)]
|
||||
Some { rust_feature: &'a str },
|
||||
#[help(codegen_gcc_consider_filing_feature_request)]
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_unwinding_inline_asm)]
|
||||
pub(crate) struct UnwindingInlineAsm {
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::Context;
|
||||
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
|
||||
use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_codegen_ssa::target_features;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
|
||||
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
|
||||
|
||||
fn gcc_features_by_flags(sess: &Session) -> Vec<&str> {
|
||||
let mut features: Vec<&str> = Vec::new();
|
||||
retpoline_features_by_flags(sess, &mut features);
|
||||
features
|
||||
fn gcc_features_by_flags(sess: &Session, features: &mut Vec<String>) {
|
||||
target_features::retpoline_features_by_flags(sess, features);
|
||||
// FIXME: LLVM also sets +reserve-x18 here under some conditions.
|
||||
}
|
||||
|
||||
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
||||
@@ -44,98 +36,29 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
||||
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
|
||||
|
||||
// -Ctarget-features
|
||||
let known_features = sess.target.rust_target_features();
|
||||
let mut featsmap = FxHashMap::default();
|
||||
|
||||
// Compute implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) {
|
||||
if let Some(feature) = feature.strip_prefix('+') {
|
||||
all_rust_features.extend(
|
||||
UnordSet::from(sess.target.implied_target_features(feature))
|
||||
.to_sorted_stable_ord()
|
||||
.iter()
|
||||
.map(|&&s| (true, s)),
|
||||
)
|
||||
} 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_config`.
|
||||
// See <https://github.com/rust-lang/rust/issues/134792>.
|
||||
all_rust_features.push((false, feature));
|
||||
} else if !feature.is_empty() && diagnostics {
|
||||
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
|
||||
}
|
||||
}
|
||||
// Remove features that are meant for rustc, not codegen.
|
||||
all_rust_features.retain(|&(_, feature)| {
|
||||
// Retain if it is not a rustc feature
|
||||
!RUSTC_SPECIFIC_FEATURES.contains(&feature)
|
||||
});
|
||||
|
||||
// Check feature validity.
|
||||
if diagnostics {
|
||||
for &(enable, feature) in &all_rust_features {
|
||||
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
|
||||
match feature_state {
|
||||
None => {
|
||||
let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let gcc_features = to_gcc_features(sess, rust_feature);
|
||||
if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature)
|
||||
{
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
} else {
|
||||
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some(&(_, stability, _)) => {
|
||||
stability.verify_feature_enabled_by_flag(sess, enable, feature);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable);
|
||||
}
|
||||
}
|
||||
|
||||
// Translate this into GCC features.
|
||||
let feats =
|
||||
all_rust_features.iter().flat_map(|&(enable, feature)| {
|
||||
let enable_disable = if enable { '+' } else { '-' };
|
||||
target_features::flag_to_backend_features(
|
||||
sess,
|
||||
diagnostics,
|
||||
|feature| to_gcc_features(sess, feature),
|
||||
|feature, enable| {
|
||||
// We run through `to_gcc_features` when
|
||||
// passing requests down to GCC. This means that all in-language
|
||||
// features also work on the command line instead of having two
|
||||
// different names when the GCC name and the Rust name differ.
|
||||
to_gcc_features(sess, feature)
|
||||
.iter()
|
||||
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
|
||||
.map(|feature| {
|
||||
if enable_disable == '-' {
|
||||
format!("-{}", feature)
|
||||
} else {
|
||||
feature.to_string()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
features.extend(feats);
|
||||
features.extend(
|
||||
to_gcc_features(sess, feature)
|
||||
.iter()
|
||||
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
|
||||
.map(
|
||||
|feature| {
|
||||
if !enable { format!("-{}", feature) } else { feature.to_string() }
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
|
||||
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
|
||||
features: f,
|
||||
span: None,
|
||||
missing_features: None,
|
||||
});
|
||||
}
|
||||
gcc_features_by_flags(sess, &mut features);
|
||||
|
||||
features
|
||||
}
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn,
|
||||
};
|
||||
use rustc_codegen_ssa::base::codegen_crate;
|
||||
use rustc_codegen_ssa::target_features::cfg_target_feature;
|
||||
use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
@@ -476,42 +477,21 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
|
||||
|
||||
/// Returns the features that should be set in `cfg(target_feature)`.
|
||||
fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig {
|
||||
// TODO(antoyo): use global_gcc_features.
|
||||
let f = |allow_unstable| {
|
||||
sess.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter_map(|&(feature, gate, _)| {
|
||||
if allow_unstable
|
||||
|| (gate.in_cfg()
|
||||
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
|
||||
{
|
||||
Some(feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|feature| {
|
||||
// TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
|
||||
if *feature == "neon" {
|
||||
return false;
|
||||
}
|
||||
target_info.cpu_supports(feature)
|
||||
// cSpell:disable
|
||||
/*
|
||||
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
|
||||
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
|
||||
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
|
||||
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
|
||||
*/
|
||||
// cSpell:enable
|
||||
})
|
||||
.map(Symbol::intern)
|
||||
.collect()
|
||||
};
|
||||
|
||||
let target_features = f(false);
|
||||
let unstable_target_features = f(true);
|
||||
let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| {
|
||||
// TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
|
||||
if feature == "neon" {
|
||||
return false;
|
||||
}
|
||||
target_info.cpu_supports(feature)
|
||||
// cSpell:disable
|
||||
/*
|
||||
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
|
||||
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
|
||||
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
|
||||
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
|
||||
*/
|
||||
// cSpell:enable
|
||||
});
|
||||
|
||||
let has_reliable_f16 = target_info.supports_target_dependent_type(CType::Float16);
|
||||
let has_reliable_f128 = target_info.supports_target_dependent_type(CType::Float128);
|
||||
|
||||
@@ -59,16 +59,6 @@ codegen_llvm_symbol_already_defined =
|
||||
codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
|
||||
codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
|
||||
|
||||
codegen_llvm_unknown_ctarget_feature =
|
||||
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
|
||||
.possible_feature = you might have meant: `{$rust_feature}`
|
||||
.consider_filing_feature_request = consider filing a feature request
|
||||
|
||||
codegen_llvm_unknown_ctarget_feature_prefix =
|
||||
unknown feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = features must begin with a `+` to enable or `-` to disable it
|
||||
|
||||
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
|
||||
|
||||
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
|
||||
|
||||
@@ -3,35 +3,11 @@
|
||||
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_unknown_ctarget_feature_prefix)]
|
||||
#[note]
|
||||
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_unknown_ctarget_feature)]
|
||||
#[note]
|
||||
pub(crate) struct UnknownCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub rust_feature: PossibleFeature<'a>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum PossibleFeature<'a> {
|
||||
#[help(codegen_llvm_possible_feature)]
|
||||
Some { rust_feature: &'a str },
|
||||
#[help(codegen_llvm_consider_filing_feature_request)]
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_symbol_already_defined)]
|
||||
pub(crate) struct SymbolAlreadyDefined<'a> {
|
||||
|
||||
@@ -6,27 +6,20 @@
|
||||
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};
|
||||
use rustc_codegen_ssa::target_features::cfg_target_feature;
|
||||
use rustc_codegen_ssa::{TargetConfig, target_features};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_fs_util::path_to_c_string;
|
||||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{PrintKind, PrintRequest};
|
||||
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
|
||||
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::errors::{
|
||||
FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
|
||||
};
|
||||
use crate::llvm;
|
||||
use crate::{errors, llvm};
|
||||
|
||||
static INIT: Once = Once::new();
|
||||
|
||||
@@ -195,15 +188,6 @@ fn with_dependencies(
|
||||
) -> Self {
|
||||
Self { llvm_feature_name, dependencies }
|
||||
}
|
||||
|
||||
fn contains(&'a self, feat: &str) -> bool {
|
||||
self.iter().any(|dep| dep == feat)
|
||||
}
|
||||
|
||||
fn iter(&'a self) -> impl Iterator<Item = &'a str> {
|
||||
let dependencies = self.dependencies.iter().map(|feat| feat.as_str());
|
||||
std::iter::once(self.llvm_feature_name).chain(dependencies)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for LLVMFeature<'a> {
|
||||
@@ -216,18 +200,22 @@ fn into_iter(self) -> Self::IntoIter {
|
||||
}
|
||||
}
|
||||
|
||||
// WARNING: the features after applying `to_llvm_features` must be known
|
||||
// to LLVM or the feature detection code will walk past the end of the feature
|
||||
// array, leading to crashes.
|
||||
//
|
||||
// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td
|
||||
// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`.
|
||||
//
|
||||
// Check the current rustc fork of LLVM in the repo at https://github.com/rust-lang/llvm-project/.
|
||||
// The commit in use can be found via the `llvm-project` submodule in
|
||||
// https://github.com/rust-lang/rust/tree/master/src Though note that Rust can also be build with
|
||||
// an external precompiled version of LLVM which might lead to failures if the oldest tested /
|
||||
// supported LLVM version doesn't yet support the relevant intrinsics.
|
||||
/// Convert a Rust feature name to an LLVM feature name. Returning `None` means the
|
||||
/// feature should be skipped, usually because it is not supported by the current
|
||||
/// LLVM version.
|
||||
///
|
||||
/// WARNING: the features after applying `to_llvm_features` must be known
|
||||
/// to LLVM or the feature detection code will walk past the end of the feature
|
||||
/// array, leading to crashes.
|
||||
///
|
||||
/// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td
|
||||
/// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`.
|
||||
///
|
||||
/// Check the current rustc fork of LLVM in the repo at
|
||||
/// <https://github.com/rust-lang/llvm-project/>. The commit in use can be found via the
|
||||
/// `llvm-project` submodule in <https://github.com/rust-lang/rust/tree/master/src> Though note that
|
||||
/// Rust can also be build with an external precompiled version of LLVM which might lead to failures
|
||||
/// if the oldest tested / supported LLVM version doesn't yet support the relevant intrinsics.
|
||||
pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFeature<'a>> {
|
||||
let arch = if sess.target.arch == "x86_64" {
|
||||
"x86"
|
||||
@@ -343,98 +331,25 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig {
|
||||
// the target CPU, that is still expanded to target features (with all their implied features)
|
||||
// by LLVM.
|
||||
let target_machine = create_informational_target_machine(sess, true);
|
||||
// Compute which of the known target features are enabled in the 'base' target machine. We only
|
||||
// consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
|
||||
let mut features: FxHashSet<Symbol> = sess
|
||||
.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|(feature, _, _)| {
|
||||
// skip checking special features, as LLVM may not understand them
|
||||
if RUSTC_SPECIAL_FEATURES.contains(feature) {
|
||||
return true;
|
||||
}
|
||||
if let Some(feat) = to_llvm_features(sess, feature) {
|
||||
for llvm_feature in feat {
|
||||
let cstr = SmallCStr::new(llvm_feature);
|
||||
// `LLVMRustHasFeature` is moderately expensive. On targets with many
|
||||
// features (e.g. x86) these calls take a non-trivial fraction of runtime
|
||||
// when compiling very small programs.
|
||||
if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } {
|
||||
return false;
|
||||
}
|
||||
|
||||
let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| {
|
||||
if let Some(feat) = to_llvm_features(sess, feature) {
|
||||
// All the LLVM features this expands to must be enabled.
|
||||
for llvm_feature in feat {
|
||||
let cstr = SmallCStr::new(llvm_feature);
|
||||
// `LLVMRustHasFeature` is moderately expensive. On targets with many
|
||||
// features (e.g. x86) these calls take a non-trivial fraction of runtime
|
||||
// when compiling very small programs.
|
||||
if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|(feature, _, _)| Symbol::intern(feature))
|
||||
.collect();
|
||||
|
||||
// Add enabled and remove disabled features.
|
||||
for (enabled, feature) in
|
||||
sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() {
|
||||
Some('+') => Some((true, Symbol::intern(&s[1..]))),
|
||||
Some('-') => Some((false, Symbol::intern(&s[1..]))),
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
if enabled {
|
||||
// Also add all transitively implied features.
|
||||
|
||||
// We don't care about the order in `features` since the only thing we use it for is the
|
||||
// `features.contains` below.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
features.extend(
|
||||
sess.target
|
||||
.implied_target_features(feature.as_str())
|
||||
.iter()
|
||||
.map(|s| Symbol::intern(s)),
|
||||
);
|
||||
true
|
||||
} else {
|
||||
// Remove transitively reverse-implied features.
|
||||
|
||||
// We don't care about the order in `features` since the only thing we use it for is the
|
||||
// `features.contains` below.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
features.retain(|f| {
|
||||
if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) {
|
||||
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
|
||||
// remove `f`. (This is the standard logical contraposition principle.)
|
||||
false
|
||||
} else {
|
||||
// We can keep `f`.
|
||||
true
|
||||
}
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Filter enabled features based on feature gates.
|
||||
let f = |allow_unstable| {
|
||||
sess.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter_map(|(feature, gate, _)| {
|
||||
// The `allow_unstable` set is used by rustc internally to determined which target
|
||||
// features are truly available, so we want to return even perma-unstable
|
||||
// "forbidden" features.
|
||||
if allow_unstable
|
||||
|| (gate.in_cfg()
|
||||
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
|
||||
{
|
||||
Some(Symbol::intern(feature))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|feature| features.contains(&feature))
|
||||
.collect()
|
||||
};
|
||||
|
||||
let target_features = f(false);
|
||||
let unstable_target_features = f(true);
|
||||
let mut cfg = TargetConfig {
|
||||
target_features,
|
||||
unstable_target_features,
|
||||
@@ -707,10 +622,18 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
|
||||
handle_native(cpu_name)
|
||||
}
|
||||
|
||||
fn llvm_features_by_flags(sess: &Session) -> Vec<&str> {
|
||||
let mut features: Vec<&str> = Vec::new();
|
||||
retpoline_features_by_flags(sess, &mut features);
|
||||
features
|
||||
/// The target features for compiler flags other than `-Ctarget-features`.
|
||||
fn llvm_features_by_flags(sess: &Session, features: &mut Vec<String>) {
|
||||
target_features::retpoline_features_by_flags(sess, features);
|
||||
|
||||
// -Zfixed-x18
|
||||
if sess.opts.unstable_opts.fixed_x18 {
|
||||
if sess.target.arch != "aarch64" {
|
||||
sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: &sess.target.arch });
|
||||
} else {
|
||||
features.push("+reserve-x18".into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
||||
@@ -777,6 +700,8 @@ pub(crate) fn global_llvm_features(
|
||||
.split(',')
|
||||
.filter(|v| !v.is_empty())
|
||||
// Drop +v8plus feature introduced in LLVM 20.
|
||||
// (Hard-coded target features do not go through `to_llvm_feature` since they already
|
||||
// are LLVM feature names, hence we need a special case here.)
|
||||
.filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
|
||||
.map(String::from),
|
||||
);
|
||||
@@ -787,86 +712,23 @@ pub(crate) fn global_llvm_features(
|
||||
|
||||
// -Ctarget-features
|
||||
if !only_base_features {
|
||||
let known_features = sess.target.rust_target_features();
|
||||
// Will only be filled when `diagnostics` is set!
|
||||
let mut featsmap = FxHashMap::default();
|
||||
|
||||
// Compute implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) {
|
||||
if let Some(feature) = feature.strip_prefix('+') {
|
||||
all_rust_features.extend(
|
||||
UnordSet::from(sess.target.implied_target_features(feature))
|
||||
.to_sorted_stable_ord()
|
||||
.iter()
|
||||
.map(|&&s| (true, s)),
|
||||
)
|
||||
} 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_config`.
|
||||
// See <https://github.com/rust-lang/rust/issues/134792>.
|
||||
all_rust_features.push((false, feature));
|
||||
} else if !feature.is_empty() {
|
||||
if diagnostics {
|
||||
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove features that are meant for rustc, not LLVM.
|
||||
all_rust_features.retain(|(_, feature)| {
|
||||
// Retain if it is not a rustc feature
|
||||
!RUSTC_SPECIFIC_FEATURES.contains(feature)
|
||||
});
|
||||
|
||||
// Check feature validity.
|
||||
if diagnostics {
|
||||
for &(enable, feature) in &all_rust_features {
|
||||
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
|
||||
match feature_state {
|
||||
None => {
|
||||
let rust_feature =
|
||||
known_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let llvm_features = to_llvm_features(sess, rust_feature)?;
|
||||
if llvm_features.contains(feature)
|
||||
&& !llvm_features.contains(rust_feature)
|
||||
{
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
} else {
|
||||
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, stability, _)) => {
|
||||
stability.verify_feature_enabled_by_flag(sess, enable, feature);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable);
|
||||
}
|
||||
}
|
||||
|
||||
// Translate this into LLVM features.
|
||||
let feats = all_rust_features
|
||||
.iter()
|
||||
.filter_map(|&(enable, feature)| {
|
||||
target_features::flag_to_backend_features(
|
||||
sess,
|
||||
diagnostics,
|
||||
|feature| {
|
||||
to_llvm_features(sess, feature)
|
||||
.map(|f| SmallVec::<[&str; 2]>::from_iter(f.into_iter()))
|
||||
.unwrap_or_default()
|
||||
},
|
||||
|feature, enable| {
|
||||
let enable_disable = if enable { '+' } else { '-' };
|
||||
// We run through `to_llvm_features` when
|
||||
// passing requests down to LLVM. This means that all in-language
|
||||
// features also work on the command line instead of having two
|
||||
// different names when the LLVM name and the Rust name differ.
|
||||
let llvm_feature = to_llvm_features(sess, feature)?;
|
||||
let Some(llvm_feature) = to_llvm_features(sess, feature) else { return };
|
||||
|
||||
Some(
|
||||
features.extend(
|
||||
std::iter::once(format!(
|
||||
"{}{}",
|
||||
enable_disable, llvm_feature.llvm_feature_name
|
||||
@@ -881,27 +743,12 @@ pub(crate) fn global_llvm_features(
|
||||
},
|
||||
)),
|
||||
)
|
||||
})
|
||||
.flatten();
|
||||
features.extend(feats);
|
||||
|
||||
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
|
||||
sess.dcx().emit_err(rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable {
|
||||
features: f,
|
||||
span: None,
|
||||
missing_features: None,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// -Zfixed-x18
|
||||
if sess.opts.unstable_opts.fixed_x18 {
|
||||
if sess.target.arch != "aarch64" {
|
||||
sess.dcx().emit_fatal(FixedX18InvalidArch { arch: &sess.target.arch });
|
||||
} else {
|
||||
features.push("+reserve-x18".into());
|
||||
}
|
||||
}
|
||||
// We add this in the "base target" so that these show up in `sess.unstable_target_features`.
|
||||
llvm_features_by_flags(sess, &mut features);
|
||||
|
||||
features
|
||||
}
|
||||
|
||||
@@ -66,6 +66,11 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error}
|
||||
|
||||
codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
|
||||
|
||||
codegen_ssa_forbidden_ctarget_feature =
|
||||
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
|
||||
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
codegen_ssa_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
codegen_ssa_forbidden_target_feature_attr =
|
||||
target feature `{$feature}` cannot be enabled with `#[target_feature]`: {$reason}
|
||||
|
||||
@@ -363,8 +368,22 @@ codegen_ssa_unexpected_parameter_name = unexpected parameter name
|
||||
codegen_ssa_unknown_archive_kind =
|
||||
Don't know how to build archive of type: {$kind}
|
||||
|
||||
codegen_ssa_unknown_ctarget_feature =
|
||||
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
|
||||
.possible_feature = you might have meant: `{$rust_feature}`
|
||||
.consider_filing_feature_request = consider filing a feature request
|
||||
|
||||
codegen_ssa_unknown_ctarget_feature_prefix =
|
||||
unknown feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = features must begin with a `+` to enable or `-` to disable it
|
||||
|
||||
codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
|
||||
|
||||
codegen_ssa_unstable_ctarget_feature =
|
||||
unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = this feature is not stably supported; its behavior can change in the future
|
||||
|
||||
codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]`
|
||||
|
||||
codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
use rustc_attr_data_structures::{
|
||||
AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
|
||||
@@ -18,13 +17,15 @@
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self as ty, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::{Session, lint};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use rustc_target::spec::SanitizerSet;
|
||||
|
||||
use crate::errors;
|
||||
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr};
|
||||
use crate::target_features::{
|
||||
check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr,
|
||||
};
|
||||
|
||||
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
|
||||
use rustc_middle::mir::mono::Linkage::*;
|
||||
@@ -590,25 +591,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
codegen_fn_attrs
|
||||
}
|
||||
|
||||
/// Given a map from target_features to whether they are enabled or disabled, ensure only valid
|
||||
/// combinations are allowed.
|
||||
pub fn check_tied_features(
|
||||
sess: &Session,
|
||||
features: &FxHashMap<&str, bool>,
|
||||
) -> Option<&'static [&'static str]> {
|
||||
if !features.is_empty() {
|
||||
for tied in sess.target.tied_target_features() {
|
||||
// Tied features must be set to the same value, or not set at all
|
||||
let mut tied_iter = tied.iter();
|
||||
let enabled = features.get(tied_iter.next().unwrap());
|
||||
if tied_iter.any(|f| enabled != features.get(f)) {
|
||||
return Some(tied);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
|
||||
/// applied to the method prototype.
|
||||
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
|
||||
@@ -1203,30 +1203,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> {
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
pub struct TargetFeatureDisableOrEnable<'a> {
|
||||
pub features: &'a [&'a str],
|
||||
pub span: Option<Span>,
|
||||
pub missing_features: Option<MissingFeatures>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(codegen_ssa_missing_features)]
|
||||
pub struct MissingFeatures;
|
||||
|
||||
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
|
||||
let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable);
|
||||
if let Some(span) = self.span {
|
||||
diag.span(span);
|
||||
};
|
||||
if let Some(missing_features) = self.missing_features {
|
||||
diag.subdiagnostic(missing_features);
|
||||
}
|
||||
diag.arg("features", self.features.join(", "));
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_aix_strip_not_used)]
|
||||
pub(crate) struct AixStripNotUsed;
|
||||
@@ -1269,3 +1245,68 @@ pub(crate) struct XcrunSdkPathWarning {
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(codegen_ssa_aarch64_softfloat_neon)]
|
||||
pub(crate) struct Aarch64SoftfloatNeon;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_unknown_ctarget_feature_prefix)]
|
||||
#[note]
|
||||
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum PossibleFeature<'a> {
|
||||
#[help(codegen_ssa_possible_feature)]
|
||||
Some { rust_feature: &'a str },
|
||||
#[help(codegen_ssa_consider_filing_feature_request)]
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_unknown_ctarget_feature)]
|
||||
#[note]
|
||||
pub(crate) struct UnknownCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub rust_feature: PossibleFeature<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_unstable_ctarget_feature)]
|
||||
#[note]
|
||||
pub(crate) struct UnstableCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_forbidden_ctarget_feature)]
|
||||
#[note]
|
||||
#[note(codegen_ssa_forbidden_ctarget_feature_issue)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub enabled: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
pub struct TargetFeatureDisableOrEnable<'a> {
|
||||
pub features: &'a [&'a str],
|
||||
pub span: Option<Span>,
|
||||
pub missing_features: Option<MissingFeatures>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(codegen_ssa_missing_features)]
|
||||
pub struct MissingFeatures;
|
||||
|
||||
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
|
||||
let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_target_feature_disable_or_enable);
|
||||
if let Some(span) = self.span {
|
||||
diag.span(span);
|
||||
};
|
||||
if let Some(missing_features) = self.missing_features {
|
||||
diag.subdiagnostic(missing_features);
|
||||
}
|
||||
diag.arg("features", self.features.join(", "));
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use rustc_attr_data_structures::InstructionSetAttr;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@@ -8,11 +8,12 @@
|
||||
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::features::StabilityExt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_target::target_features::{self, Stability};
|
||||
use rustc_target::target_features::{self, RUSTC_SPECIFIC_FEATURES, Stability};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
@@ -67,7 +68,7 @@ pub(crate) fn from_target_feature_attr(
|
||||
|
||||
// Only allow target features whose feature gates have been enabled
|
||||
// and which are permitted to be toggled.
|
||||
if let Err(reason) = stability.is_toggle_permitted(tcx.sess) {
|
||||
if let Err(reason) = stability.toggle_allowed() {
|
||||
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||
span: item.span(),
|
||||
feature,
|
||||
@@ -88,7 +89,7 @@ pub(crate) fn from_target_feature_attr(
|
||||
let feature_sym = Symbol::intern(feature);
|
||||
for &name in tcx.implied_target_features(feature_sym) {
|
||||
// But ensure the ABI does not forbid enabling this.
|
||||
// Here we do assume that LLVM doesn't add even more implied features
|
||||
// Here we do assume that the backend doesn't add even more implied features
|
||||
// we don't know about, at least no features that would have ABI effects!
|
||||
// We skip this logic in rustdoc, where we want to allow all target features of
|
||||
// all targets, so we can't check their ABI compatibility and anyway we are not
|
||||
@@ -156,6 +157,276 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId,
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the value of `-Ctarget-feature`, also expanding implied features,
|
||||
/// and call the closure for each (expanded) Rust feature. If the list contains
|
||||
/// a syntactically invalid item (not starting with `+`/`-`), the error callback is invoked.
|
||||
fn parse_rust_feature_flag<'a>(
|
||||
sess: &'a Session,
|
||||
err_callback: impl Fn(&'a str),
|
||||
mut callback: impl FnMut(
|
||||
/* base_feature */ &'a str,
|
||||
/* with_implied */ FxHashSet<&'a str>,
|
||||
/* enable */ bool,
|
||||
),
|
||||
) {
|
||||
// A cache for the backwards implication map.
|
||||
let mut inverse_implied_features: Option<FxHashMap<&str, FxHashSet<&str>>> = None;
|
||||
|
||||
for feature in sess.opts.cg.target_feature.split(',') {
|
||||
if let Some(base_feature) = feature.strip_prefix('+') {
|
||||
// Skip features that are not target features, but rustc features.
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(base_feature, sess.target.implied_target_features(base_feature), true)
|
||||
} else if let Some(base_feature) = feature.strip_prefix('-') {
|
||||
// Skip features that are not target features, but rustc features.
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If `f1` implies `f2`, then `!f2` implies `!f1` -- this is standard logical
|
||||
// contraposition. So we have to find all the reverse implications of `base_feature` and
|
||||
// disable them, too.
|
||||
|
||||
let inverse_implied_features = inverse_implied_features.get_or_insert_with(|| {
|
||||
let mut set: FxHashMap<&str, FxHashSet<&str>> = FxHashMap::default();
|
||||
for (f, _, is) in sess.target.rust_target_features() {
|
||||
for i in is.iter() {
|
||||
set.entry(i).or_default().insert(f);
|
||||
}
|
||||
}
|
||||
set
|
||||
});
|
||||
|
||||
// Inverse implied target features have their own inverse implied target features, so we
|
||||
// traverse the map until there are no more features to add.
|
||||
let mut features = FxHashSet::default();
|
||||
let mut new_features = vec![base_feature];
|
||||
while let Some(new_feature) = new_features.pop() {
|
||||
if features.insert(new_feature) {
|
||||
if let Some(implied_features) = inverse_implied_features.get(&new_feature) {
|
||||
new_features.extend(implied_features)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callback(base_feature, features, false)
|
||||
} else if !feature.is_empty() {
|
||||
err_callback(feature)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Utility function for a codegen backend to compute `cfg(target_feature)`, or more specifically,
|
||||
/// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and
|
||||
/// 2nd component of the return value, respectively).
|
||||
///
|
||||
/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is
|
||||
/// enabled in the "base" target machine, i.e., without applying `-Ctarget-feature`.
|
||||
///
|
||||
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere.
|
||||
pub fn cfg_target_feature(
|
||||
sess: &Session,
|
||||
mut target_base_has_feature: impl FnMut(&str) -> bool,
|
||||
) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||
// Compute which of the known target features are enabled in the 'base' target machine. We only
|
||||
// consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
|
||||
let mut features: UnordSet<Symbol> = sess
|
||||
.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|(feature, _, _)| target_base_has_feature(feature))
|
||||
.map(|(feature, _, _)| Symbol::intern(feature))
|
||||
.collect();
|
||||
|
||||
// Add enabled and remove disabled features.
|
||||
parse_rust_feature_flag(
|
||||
sess,
|
||||
/* err_callback */
|
||||
|_| {
|
||||
// Errors are already emitted in `flag_to_backend_features`; avoid duplicates.
|
||||
},
|
||||
|_base_feature, new_features, enabled| {
|
||||
// Iteration order is irrelevant since this only influences an `UnordSet`.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
if enabled {
|
||||
features.extend(new_features.into_iter().map(|f| Symbol::intern(f)));
|
||||
} else {
|
||||
// Remove `new_features` from `features`.
|
||||
for new in new_features {
|
||||
features.remove(&Symbol::intern(new));
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Filter enabled features based on feature gates.
|
||||
let f = |allow_unstable| {
|
||||
sess.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter_map(|(feature, gate, _)| {
|
||||
// The `allow_unstable` set is used by rustc internally to determine which target
|
||||
// features are truly available, so we want to return even perma-unstable
|
||||
// "forbidden" features.
|
||||
if allow_unstable
|
||||
|| (gate.in_cfg()
|
||||
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
|
||||
{
|
||||
Some(Symbol::intern(feature))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|feature| features.contains(&feature))
|
||||
.collect()
|
||||
};
|
||||
|
||||
(f(true), f(false))
|
||||
}
|
||||
|
||||
/// Given a map from target_features to whether they are enabled or disabled, ensure only valid
|
||||
/// combinations are allowed.
|
||||
pub fn check_tied_features(
|
||||
sess: &Session,
|
||||
features: &FxHashMap<&str, bool>,
|
||||
) -> Option<&'static [&'static str]> {
|
||||
if !features.is_empty() {
|
||||
for tied in sess.target.tied_target_features() {
|
||||
// Tied features must be set to the same value, or not set at all
|
||||
let mut tied_iter = tied.iter();
|
||||
let enabled = features.get(tied_iter.next().unwrap());
|
||||
if tied_iter.any(|f| enabled != features.get(f)) {
|
||||
return Some(tied);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Translates the `-Ctarget-feature` flag into a backend target feature list.
|
||||
///
|
||||
/// `to_backend_features` converts a Rust feature name into a list of backend feature names; this is
|
||||
/// used for diagnostic purposes only.
|
||||
///
|
||||
/// `extend_backend_features` extends the set of backend features (assumed to be in mutable state
|
||||
/// accessible by that closure) to enable/disable the given Rust feature name.
|
||||
pub fn flag_to_backend_features<'a, const N: usize>(
|
||||
sess: &'a Session,
|
||||
diagnostics: bool,
|
||||
to_backend_features: impl Fn(&'a str) -> SmallVec<[&'a str; N]>,
|
||||
mut extend_backend_features: impl FnMut(&'a str, /* enable */ bool),
|
||||
) {
|
||||
let known_features = sess.target.rust_target_features();
|
||||
|
||||
// Compute implied features
|
||||
let mut rust_features = vec![];
|
||||
parse_rust_feature_flag(
|
||||
sess,
|
||||
/* err_callback */
|
||||
|feature| {
|
||||
if diagnostics {
|
||||
sess.dcx().emit_warn(errors::UnknownCTargetFeaturePrefix { feature });
|
||||
}
|
||||
},
|
||||
|base_feature, new_features, enable| {
|
||||
rust_features.extend(
|
||||
UnordSet::from(new_features).to_sorted_stable_ord().iter().map(|&&s| (enable, s)),
|
||||
);
|
||||
// Check feature validity.
|
||||
if diagnostics {
|
||||
let feature_state = known_features.iter().find(|&&(v, _, _)| v == base_feature);
|
||||
match feature_state {
|
||||
None => {
|
||||
// This is definitely not a valid Rust feature name. Maybe it is a backend
|
||||
// feature name? If so, give a better error message.
|
||||
let rust_feature =
|
||||
known_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let backend_features = to_backend_features(rust_feature);
|
||||
if backend_features.contains(&base_feature)
|
||||
&& !backend_features.contains(&rust_feature)
|
||||
{
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
errors::UnknownCTargetFeature {
|
||||
feature: base_feature,
|
||||
rust_feature: errors::PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
} else {
|
||||
errors::UnknownCTargetFeature {
|
||||
feature: base_feature,
|
||||
rust_feature: errors::PossibleFeature::None,
|
||||
}
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, stability, _)) => {
|
||||
if let Err(reason) = stability.toggle_allowed() {
|
||||
sess.dcx().emit_warn(errors::ForbiddenCTargetFeature {
|
||||
feature: base_feature,
|
||||
enabled: if enable { "enabled" } else { "disabled" },
|
||||
reason,
|
||||
});
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above.
|
||||
sess.dcx().emit_warn(errors::UnstableCTargetFeature {
|
||||
feature: base_feature,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if diagnostics {
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashmap here.
|
||||
if let Some(f) = check_tied_features(
|
||||
sess,
|
||||
&FxHashMap::from_iter(rust_features.iter().map(|&(enable, feature)| (feature, enable))),
|
||||
) {
|
||||
sess.dcx().emit_err(errors::TargetFeatureDisableOrEnable {
|
||||
features: f,
|
||||
span: None,
|
||||
missing_features: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add this to the backend features.
|
||||
for (enable, feature) in rust_features {
|
||||
extend_backend_features(feature, enable);
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the backend target features to be added to account for retpoline flags.
|
||||
/// Used by both LLVM and GCC since their target features are, conveniently, the same.
|
||||
pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<String>) {
|
||||
// -Zretpoline without -Zretpoline-external-thunk enables
|
||||
// retpoline-indirect-branches and retpoline-indirect-calls target features
|
||||
let unstable_opts = &sess.opts.unstable_opts;
|
||||
if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk {
|
||||
features.push("+retpoline-indirect-branches".into());
|
||||
features.push("+retpoline-indirect-calls".into());
|
||||
}
|
||||
// -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables
|
||||
// retpoline-external-thunk, retpoline-indirect-branches and
|
||||
// retpoline-indirect-calls target features
|
||||
if unstable_opts.retpoline_external_thunk {
|
||||
features.push("+retpoline-external-thunk".into());
|
||||
features.push("+retpoline-indirect-branches".into());
|
||||
features.push("+retpoline-indirect-calls".into());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
rust_target_features: |tcx, cnum| {
|
||||
@@ -182,7 +453,8 @@ pub(crate) fn provide(providers: &mut Providers) {
|
||||
Stability::Unstable { .. } | Stability::Forbidden { .. },
|
||||
)
|
||||
| (Stability::Forbidden { .. }, Stability::Forbidden { .. }) => {
|
||||
// The stability in the entry is at least as good as the new one, just keep it.
|
||||
// The stability in the entry is at least as good as the new
|
||||
// one, just keep it.
|
||||
}
|
||||
_ => {
|
||||
// Overwrite stabilite.
|
||||
|
||||
@@ -40,11 +40,6 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it
|
||||
|
||||
session_file_write_fail = failed to write `{$path}` due to error `{$err}`
|
||||
|
||||
session_forbidden_ctarget_feature =
|
||||
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
|
||||
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
session_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64
|
||||
|
||||
session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models
|
||||
@@ -137,9 +132,6 @@ session_target_stack_protector_not_supported = `-Z stack-protector={$stack_prote
|
||||
session_unleashed_feature_help_named = skipping check for `{$gate}` feature
|
||||
session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
|
||||
|
||||
session_unstable_ctarget_feature =
|
||||
unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = this feature is not stably supported; its behavior can change in the future
|
||||
session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
|
||||
|
||||
session_unsupported_crate_type_for_target =
|
||||
|
||||
@@ -501,20 +501,3 @@ pub(crate) struct FailedToCreateProfiler {
|
||||
#[note]
|
||||
#[note(session_soft_float_deprecated_issue)]
|
||||
pub(crate) struct SoftFloatDeprecated;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_forbidden_ctarget_feature)]
|
||||
#[note]
|
||||
#[note(session_forbidden_ctarget_feature_issue)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub enabled: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(session_unstable_ctarget_feature)]
|
||||
#[note]
|
||||
pub(crate) struct UnstableCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
use rustc_target::target_features::Stability;
|
||||
|
||||
use crate::Session;
|
||||
use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature};
|
||||
|
||||
pub trait StabilityExt {
|
||||
/// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
|
||||
/// Otherwise, some features also may only be enabled by flag (target modifier).
|
||||
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
|
||||
/// `requires_nightly`.)
|
||||
fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>;
|
||||
|
||||
/// Check that feature is correctly enabled/disabled by command line flag (emits warnings)
|
||||
fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str);
|
||||
}
|
||||
|
||||
impl StabilityExt for Stability {
|
||||
fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> {
|
||||
match self {
|
||||
Stability::Forbidden { reason } => Err(reason),
|
||||
Stability::TargetModifierOnly { reason, flag } => {
|
||||
if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) }
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) {
|
||||
if let Err(reason) = self.is_toggle_permitted(sess) {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: if enable { "enabled" } else { "disabled" },
|
||||
reason,
|
||||
});
|
||||
} else if self.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) {
|
||||
// -Zretpoline without -Zretpoline-external-thunk enables
|
||||
// retpoline-indirect-branches and retpoline-indirect-calls target features
|
||||
let unstable_opts = &sess.opts.unstable_opts;
|
||||
if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk {
|
||||
features.push("+retpoline-indirect-branches");
|
||||
features.push("+retpoline-indirect-calls");
|
||||
}
|
||||
// -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables
|
||||
// retpoline-external-thunk, retpoline-indirect-branches and
|
||||
// retpoline-indirect-calls target features
|
||||
if unstable_opts.retpoline_external_thunk {
|
||||
features.push("+retpoline-external-thunk");
|
||||
features.push("+retpoline-indirect-branches");
|
||||
features.push("+retpoline-indirect-calls");
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@
|
||||
pub mod output;
|
||||
|
||||
pub use getopts;
|
||||
pub mod features;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
|
||||
@@ -290,14 +290,6 @@ pub fn gather_target_modifiers(&self) -> Vec<TargetModifier> {
|
||||
mods.sort_by(|a, b| a.opt.cmp(&b.opt));
|
||||
mods
|
||||
}
|
||||
|
||||
pub fn target_feature_flag_enabled(&self, flag: &str) -> bool {
|
||||
match flag {
|
||||
"retpoline" => self.unstable_opts.retpoline,
|
||||
"retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
/// These exist globally and are not in the target-specific lists below.
|
||||
pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
|
||||
|
||||
/// Features that require special handling when passing to LLVM:
|
||||
/// these are target-specific (i.e., must also be listed in the target-specific list below)
|
||||
/// but do not correspond to an LLVM target feature.
|
||||
pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"];
|
||||
|
||||
/// Stability information for target features.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Stability {
|
||||
@@ -34,9 +29,6 @@ pub enum Stability {
|
||||
/// particular for features are actually ABI configuration flags (not all targets are as nice as
|
||||
/// RISC-V and have an explicit way to set the ABI separate from target features).
|
||||
Forbidden { reason: &'static str },
|
||||
/// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set
|
||||
/// by target modifier flag. Target modifier flags are tracked to be consistent in linked modules.
|
||||
TargetModifierOnly { reason: &'static str, flag: &'static str },
|
||||
}
|
||||
use Stability::*;
|
||||
|
||||
@@ -52,7 +44,6 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
Stability::Forbidden { reason } => {
|
||||
reason.hash_stable(hcx, hasher);
|
||||
}
|
||||
Stability::TargetModifierOnly { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,7 +53,7 @@ impl Stability {
|
||||
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
|
||||
/// `requires_nightly`.)
|
||||
pub fn in_cfg(&self) -> bool {
|
||||
!matches!(self, Stability::Forbidden { .. })
|
||||
matches!(self, Stability::Stable | Stability::Unstable { .. })
|
||||
}
|
||||
|
||||
/// Returns the nightly feature that is required to toggle this target feature via
|
||||
@@ -78,7 +69,16 @@ pub fn requires_nightly(&self) -> Option<Symbol> {
|
||||
Stability::Unstable(nightly_feature) => Some(nightly_feature),
|
||||
Stability::Stable { .. } => None,
|
||||
Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
|
||||
Stability::TargetModifierOnly { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
|
||||
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
|
||||
/// `requires_nightly`.)
|
||||
pub fn toggle_allowed(&self) -> Result<(), &'static str> {
|
||||
match self {
|
||||
Stability::Unstable(_) | Stability::Stable { .. } => Ok(()),
|
||||
Stability::Forbidden { reason } => Err(reason),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,12 +270,7 @@ pub fn requires_nightly(&self) -> Option<Symbol> {
|
||||
("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]),
|
||||
// FEAT_RDM
|
||||
("rdm", Stable, &["neon"]),
|
||||
// This is needed for inline assembly, but shouldn't be stabilized as-is
|
||||
// since it should be enabled globally using -Zfixed-x18, not
|
||||
// #[target_feature].
|
||||
// Note that cfg(target_feature = "reserve-x18") is currently not set for
|
||||
// targets that reserve x18 by default.
|
||||
("reserve-x18", Unstable(sym::aarch64_unstable_target_feature), &[]),
|
||||
("reserve-x18", Forbidden { reason: "use `-Zfixed-x18` compiler flag instead" }, &[]),
|
||||
// FEAT_SB
|
||||
("sb", Stable, &[]),
|
||||
// FEAT_SHA1 & FEAT_SHA256
|
||||
@@ -450,26 +445,17 @@ pub fn requires_nightly(&self) -> Option<Symbol> {
|
||||
("rdseed", Stable, &[]),
|
||||
(
|
||||
"retpoline-external-thunk",
|
||||
Stability::TargetModifierOnly {
|
||||
reason: "use `retpoline-external-thunk` target modifier flag instead",
|
||||
flag: "retpoline-external-thunk",
|
||||
},
|
||||
Stability::Forbidden { reason: "use `-Zretpoline-external-thunk` compiler flag instead" },
|
||||
&[],
|
||||
),
|
||||
(
|
||||
"retpoline-indirect-branches",
|
||||
Stability::TargetModifierOnly {
|
||||
reason: "use `retpoline` target modifier flag instead",
|
||||
flag: "retpoline",
|
||||
},
|
||||
Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" },
|
||||
&[],
|
||||
),
|
||||
(
|
||||
"retpoline-indirect-calls",
|
||||
Stability::TargetModifierOnly {
|
||||
reason: "use `retpoline` target modifier flag instead",
|
||||
flag: "retpoline",
|
||||
},
|
||||
Stability::Forbidden { reason: "use `-Zretpoline` compiler flag instead" },
|
||||
&[],
|
||||
),
|
||||
("rtm", Unstable(sym::rtm_target_feature), &[]),
|
||||
@@ -732,6 +718,7 @@ pub fn requires_nightly(&self) -> Option<Symbol> {
|
||||
#[rustfmt::skip]
|
||||
const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
// For "backchain", https://github.com/rust-lang/rust/issues/142412 is a stabilization blocker
|
||||
("backchain", Unstable(sym::s390x_target_feature), &[]),
|
||||
("concurrent-functions", Unstable(sym::s390x_target_feature), &[]),
|
||||
("deflate-conversion", Unstable(sym::s390x_target_feature), &[]),
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
use rustc_hir::def_id::{DefId, DefIdSet};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::features::StabilityExt;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustdoc_json_types as types;
|
||||
// It's important to use the FxHashMap from rustdoc_json_types here, instead of
|
||||
@@ -148,7 +147,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
|
||||
.copied()
|
||||
.filter(|(_, stability, _)| {
|
||||
// Describe only target features which the user can toggle
|
||||
stability.is_toggle_permitted(sess).is_ok()
|
||||
stability.toggle_allowed().is_ok()
|
||||
})
|
||||
.map(|(name, stability, implied_features)| {
|
||||
types::TargetFeature {
|
||||
@@ -164,7 +163,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
|
||||
// Imply only target features which the user can toggle
|
||||
feature_stability
|
||||
.get(name)
|
||||
.map(|stability| stability.is_toggle_permitted(sess).is_ok())
|
||||
.map(|stability| stability.toggle_allowed().is_ok())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.map(String::from)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//@ add-core-stubs
|
||||
//@ revisions: enable-backchain disable-backchain
|
||||
//@ revisions: enable-backchain disable-backchain default-backchain
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -Copt-level=3 --crate-type=lib --target=s390x-unknown-linux-gnu
|
||||
//@ needs-llvm-components: systemz
|
||||
@@ -26,6 +26,8 @@ extern "C" fn test_backchain() -> i32 {
|
||||
// enable-backchain: stg [[REG1]], 0(%r15)
|
||||
// disable-backchain: aghi %r15, -160
|
||||
// disable-backchain-NOT: stg %r{{.*}}, 0(%r15)
|
||||
// default-backchain: aghi %r15, -160
|
||||
// default-backchain-NOT: stg %r{{.*}}, 0(%r15)
|
||||
unsafe {
|
||||
extern_func();
|
||||
}
|
||||
@@ -35,6 +37,7 @@ extern "C" fn test_backchain() -> i32 {
|
||||
// Make sure that the expected return value is written into %r2 (return register):
|
||||
// enable-backchain-NEXT: lghi %r2, 1
|
||||
// disable-backchain: lghi %r2, 0
|
||||
// default-backchain: lghi %r2, 0
|
||||
#[cfg(target_feature = "backchain")]
|
||||
{
|
||||
1
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//@ add-core-stubs
|
||||
//@ needs-llvm-components: x86
|
||||
//@ compile-flags: --target=x86_64-unknown-linux-gnu
|
||||
//@ compile-flags: -Ctarget-feature=-avx2
|
||||
|
||||
#![feature(no_core, lang_items)]
|
||||
#![crate_type = "lib"]
|
||||
#![no_core]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn banana() {
|
||||
// CHECK-LABEL: @banana()
|
||||
// CHECK-SAME: [[BANANAATTRS:#[0-9]+]] {
|
||||
}
|
||||
|
||||
// CHECK: attributes [[BANANAATTRS]]
|
||||
// CHECK-SAME: -avx512
|
||||
@@ -1,3 +1,4 @@
|
||||
// ignore-tidy-linelength
|
||||
//@ add-core-stubs
|
||||
//@ revisions: COMPAT INCOMPAT
|
||||
//@ needs-llvm-components: x86
|
||||
@@ -39,7 +40,7 @@ pub unsafe fn banana() -> u32 {
|
||||
|
||||
// CHECK: attributes [[APPLEATTRS]]
|
||||
// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
|
||||
// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
|
||||
// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}},+avx{{(,\+[^,]+)*}}"
|
||||
// CHECK: attributes [[BANANAATTRS]]
|
||||
// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
|
||||
// INCOMPAT-SAME: "target-features"="-avx2,-avx"
|
||||
// INCOMPAT-SAME: "target-features"="{{(-[^,]+,)*}}-avx2{{(,-[^,]+)*}},-avx{{(,-[^,]+)*}}"
|
||||
|
||||
@@ -4,14 +4,23 @@
|
||||
//@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
|
||||
//@ needs-llvm-components: aarch64
|
||||
|
||||
// Rust made SVE require neon.
|
||||
//@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0
|
||||
// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
|
||||
// ENABLE_SVE: attributes #0
|
||||
// ENABLE_SVE-SAME: +neon
|
||||
// ENABLE_SVE-SAME: +sve
|
||||
|
||||
// However, disabling SVE does not disable neon.
|
||||
//@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
|
||||
// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(-sve,?)|(\+neon,?))*}}" }
|
||||
// DISABLE_SVE: attributes #0
|
||||
// DISABLE_SVE-NOT: -neon
|
||||
// DISABLE_SVE-SAME: -sve
|
||||
|
||||
// OTOH, neon fn `fp-armv8` are fully tied; toggling neon must toggle `fp-armv8` the same way.
|
||||
//@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0
|
||||
// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(-fp-armv8,?)|(-neon,?))*}}" }
|
||||
// DISABLE_NEON: attributes #0
|
||||
// DISABLE_NEON-SAME: -neon
|
||||
// DISABLE_NEON-SAME: -fp-armv8
|
||||
|
||||
//@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0
|
||||
// ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}}" }
|
||||
|
||||
@@ -211,10 +211,6 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
|
||||
`reference-types`
|
||||
`relax`
|
||||
`relaxed-simd`
|
||||
`reserve-x18`
|
||||
`retpoline-external-thunk`
|
||||
`retpoline-indirect-branches`
|
||||
`retpoline-indirect-calls`
|
||||
`rtm`
|
||||
`sb`
|
||||
`scq`
|
||||
|
||||
@@ -7,13 +7,5 @@ warning: unstable feature specified for `-Ctarget-feature`: `d`
|
||||
|
|
||||
= note: this feature is not stably supported; its behavior can change in the future
|
||||
|
||||
warning: unstable feature specified for `-Ctarget-feature`: `f`
|
||||
|
|
||||
= note: this feature is not stably supported; its behavior can change in the future
|
||||
|
||||
warning: unstable feature specified for `-Ctarget-feature`: `zicsr`
|
||||
|
|
||||
= note: this feature is not stably supported; its behavior can change in the future
|
||||
|
||||
warning: 4 warnings emitted
|
||||
warning: 2 warnings emitted
|
||||
|
||||
|
||||
@@ -24,5 +24,3 @@ pub trait Freeze {}
|
||||
|
||||
//~? WARN must be disabled to ensure that the ABI of the current target can be implemented correctly
|
||||
//~? WARN unstable feature specified for `-Ctarget-feature`
|
||||
//[riscv]~? WARN unstable feature specified for `-Ctarget-feature`
|
||||
//[riscv]~? WARN unstable feature specified for `-Ctarget-feature`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
|
||||
warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline-external-thunk` compiler flag instead
|
||||
|
|
||||
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
|
||||
warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline` compiler flag instead
|
||||
|
|
||||
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
|
||||
warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `-Zretpoline` compiler flag instead
|
||||
|
|
||||
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
@@ -16,6 +16,6 @@
|
||||
#![no_core]
|
||||
extern crate minicore;
|
||||
|
||||
//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
|
||||
//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
|
||||
//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
|
||||
//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`
|
||||
//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`
|
||||
//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`
|
||||
|
||||
Reference in New Issue
Block a user