mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Rollup merge of #128221 - calebzulawski:implied-target-features, r=Amanieu
Add implied target features to target_feature attribute See [zulip](https://rust-lang.zulipchat.com/#narrow/stream/208962-t-libs.2Fstdarch/topic/Why.20would.20target-feature.20include.20implied.20features.3F) for some context. Adds implied target features, e.g. `#[target_feature(enable = "avx2")]` acts like `#[target_feature(enable = "avx2,avx,sse4.2,sse4.1...")]`. Fixes #128125, fixes #128426 The implied feature sets are taken from [the rust reference](https://doc.rust-lang.org/reference/attributes/codegen.html?highlight=target-fea#x86-or-x86_64), there are certainly more features and targets to add. Please feel free to reassign this to whoever should review it. r? ``@Amanieu``
This commit is contained in:
commit
904f5795a0
@ -75,7 +75,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
|
||||
let function_features = codegen_fn_attrs
|
||||
.target_features
|
||||
.iter()
|
||||
.map(|features| features.as_str())
|
||||
.map(|features| features.name.as_str())
|
||||
.collect::<Vec<&str>>();
|
||||
|
||||
if let Some(features) = check_tied_features(
|
||||
|
@ -65,8 +65,8 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
||||
|
||||
let feature = backend_feature_name(s)?;
|
||||
// Warn against use of GCC specific feature names on the CLI.
|
||||
if diagnostics && !supported_features.iter().any(|&(v, _)| v == feature) {
|
||||
let rust_feature = supported_features.iter().find_map(|&(rust_feature, _)| {
|
||||
if diagnostics && !supported_features.iter().any(|&(v, _, _)| v == feature) {
|
||||
let rust_feature = supported_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)
|
||||
|
@ -486,7 +486,7 @@ pub fn target_features(
|
||||
sess.target
|
||||
.supported_target_features()
|
||||
.iter()
|
||||
.filter_map(|&(feature, gate)| {
|
||||
.filter_map(|&(feature, gate, _)| {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
|
||||
Some(feature)
|
||||
} else {
|
||||
|
@ -496,7 +496,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
|
||||
to_add.extend(tune_cpu_attr(cx));
|
||||
|
||||
let function_features =
|
||||
codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
|
||||
codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
|
||||
|
||||
if let Some(f) = llvm_util::check_tied_features(
|
||||
cx.tcx.sess,
|
||||
|
@ -95,11 +95,14 @@ pub fn write_output_file<'ll>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine {
|
||||
pub fn create_informational_target_machine(
|
||||
sess: &Session,
|
||||
only_base_features: bool,
|
||||
) -> OwnedTargetMachine {
|
||||
let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None };
|
||||
// Can't use query system here quite yet because this function is invoked before the query
|
||||
// system/tcx is set up.
|
||||
let features = llvm_util::global_llvm_features(sess, false);
|
||||
let features = llvm_util::global_llvm_features(sess, false, only_base_features);
|
||||
target_machine_factory(sess, config::OptLevel::No, &features)(config)
|
||||
.unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise())
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ pub unsafe fn create_module<'ll>(
|
||||
|
||||
// Ensure the data-layout values hardcoded remain the defaults.
|
||||
{
|
||||
let tm = crate::back::write::create_informational_target_machine(tcx.sess);
|
||||
let tm = crate::back::write::create_informational_target_machine(tcx.sess, false);
|
||||
unsafe {
|
||||
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ impl CodegenBackend for LlvmCodegenBackend {
|
||||
|
||||
fn provide(&self, providers: &mut Providers) {
|
||||
providers.global_backend_features =
|
||||
|tcx, ()| llvm_util::global_llvm_features(tcx.sess, true)
|
||||
|tcx, ()| llvm_util::global_llvm_features(tcx.sess, true, false)
|
||||
}
|
||||
|
||||
fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {
|
||||
@ -434,7 +434,7 @@ impl ModuleLlvm {
|
||||
ModuleLlvm {
|
||||
llmod_raw,
|
||||
llcx,
|
||||
tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)),
|
||||
tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use libc::c_int;
|
||||
use rustc_codegen_ssa::base::wants_wasm_eh;
|
||||
use rustc_data_structures::fx::{FxHashMap, 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::config::{PrintKind, PrintRequest};
|
||||
@ -239,40 +240,8 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
|
||||
}
|
||||
// In LLVM neon implicitly enables fp, but we manually enable
|
||||
// neon when a feature only implicitly enables fp
|
||||
("aarch64", "f32mm") => {
|
||||
LLVMFeature::with_dependency("f32mm", TargetFeatureFoldStrength::EnableOnly("neon"))
|
||||
}
|
||||
("aarch64", "f64mm") => {
|
||||
LLVMFeature::with_dependency("f64mm", TargetFeatureFoldStrength::EnableOnly("neon"))
|
||||
}
|
||||
("aarch64", "fhm") => {
|
||||
LLVMFeature::with_dependency("fp16fml", TargetFeatureFoldStrength::EnableOnly("neon"))
|
||||
}
|
||||
("aarch64", "fp16") => {
|
||||
LLVMFeature::with_dependency("fullfp16", TargetFeatureFoldStrength::EnableOnly("neon"))
|
||||
}
|
||||
("aarch64", "jsconv") => {
|
||||
LLVMFeature::with_dependency("jsconv", TargetFeatureFoldStrength::EnableOnly("neon"))
|
||||
}
|
||||
("aarch64", "sve") => {
|
||||
LLVMFeature::with_dependency("sve", TargetFeatureFoldStrength::EnableOnly("neon"))
|
||||
}
|
||||
("aarch64", "sve2") => {
|
||||
LLVMFeature::with_dependency("sve2", TargetFeatureFoldStrength::EnableOnly("neon"))
|
||||
}
|
||||
("aarch64", "sve2-aes") => {
|
||||
LLVMFeature::with_dependency("sve2-aes", TargetFeatureFoldStrength::EnableOnly("neon"))
|
||||
}
|
||||
("aarch64", "sve2-sm4") => {
|
||||
LLVMFeature::with_dependency("sve2-sm4", TargetFeatureFoldStrength::EnableOnly("neon"))
|
||||
}
|
||||
("aarch64", "sve2-sha3") => {
|
||||
LLVMFeature::with_dependency("sve2-sha3", TargetFeatureFoldStrength::EnableOnly("neon"))
|
||||
}
|
||||
("aarch64", "sve2-bitperm") => LLVMFeature::with_dependency(
|
||||
"sve2-bitperm",
|
||||
TargetFeatureFoldStrength::EnableOnly("neon"),
|
||||
),
|
||||
("aarch64", "fhm") => LLVMFeature::new("fp16fml"),
|
||||
("aarch64", "fp16") => LLVMFeature::new("fullfp16"),
|
||||
// In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called
|
||||
// `fast-unaligned-access`. In LLVM 19, it was split back out.
|
||||
("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => {
|
||||
@ -308,11 +277,53 @@ pub fn check_tied_features(
|
||||
/// Used to generate cfg variables and apply features
|
||||
/// Must express features in the way Rust understands them
|
||||
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
let target_machine = create_informational_target_machine(sess);
|
||||
let mut features = vec![];
|
||||
|
||||
// Add base features for the target
|
||||
let target_machine = create_informational_target_machine(sess, true);
|
||||
features.extend(
|
||||
sess.target
|
||||
.supported_target_features()
|
||||
.iter()
|
||||
.filter(|(feature, _, _)| {
|
||||
// skip checking special features, as LLVM may not understands them
|
||||
if RUSTC_SPECIAL_FEATURES.contains(feature) {
|
||||
return true;
|
||||
}
|
||||
// check that all features in a given smallvec are enabled
|
||||
for llvm_feature in to_llvm_features(sess, feature) {
|
||||
let cstr = SmallCStr::new(llvm_feature);
|
||||
if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
})
|
||||
.map(|(feature, _, _)| Symbol::intern(feature)),
|
||||
);
|
||||
|
||||
// Add enabled 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 {
|
||||
features.extend(sess.target.implied_target_features(std::iter::once(feature)));
|
||||
} else {
|
||||
features.retain(|f| {
|
||||
!sess.target.implied_target_features(std::iter::once(*f)).contains(&feature)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Filter enabled features based on feature gates
|
||||
sess.target
|
||||
.supported_target_features()
|
||||
.iter()
|
||||
.filter_map(|&(feature, gate)| {
|
||||
.filter_map(|&(feature, gate, _)| {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
|
||||
Some(feature)
|
||||
} else {
|
||||
@ -320,18 +331,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
}
|
||||
})
|
||||
.filter(|feature| {
|
||||
// skip checking special features, as LLVM may not understands them
|
||||
if RUSTC_SPECIAL_FEATURES.contains(feature) {
|
||||
return true;
|
||||
}
|
||||
// check that all features in a given smallvec are enabled
|
||||
for llvm_feature in to_llvm_features(sess, feature) {
|
||||
let cstr = SmallCStr::new(llvm_feature);
|
||||
if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
RUSTC_SPECIAL_FEATURES.contains(feature) || features.contains(&Symbol::intern(feature))
|
||||
})
|
||||
.map(|feature| Symbol::intern(feature))
|
||||
.collect()
|
||||
@ -386,7 +386,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
|
||||
.target
|
||||
.supported_target_features()
|
||||
.iter()
|
||||
.map(|(feature, _gate)| {
|
||||
.map(|(feature, _gate, _implied)| {
|
||||
// LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
|
||||
let llvm_feature = to_llvm_features(sess, *feature).llvm_feature_name;
|
||||
let desc =
|
||||
@ -440,7 +440,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
|
||||
|
||||
pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) {
|
||||
require_inited();
|
||||
let tm = create_informational_target_machine(sess);
|
||||
let tm = create_informational_target_machine(sess, false);
|
||||
match req.kind {
|
||||
PrintKind::TargetCPUs => {
|
||||
// SAFETY generate a C compatible string from a byte slice to pass
|
||||
@ -488,7 +488,11 @@ pub fn target_cpu(sess: &Session) -> &str {
|
||||
|
||||
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
||||
/// `--target` and similar).
|
||||
pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<String> {
|
||||
pub(crate) fn global_llvm_features(
|
||||
sess: &Session,
|
||||
diagnostics: bool,
|
||||
only_base_features: bool,
|
||||
) -> Vec<String> {
|
||||
// Features that come earlier are overridden by conflicting features later in the string.
|
||||
// Typically we'll want more explicit settings to override the implicit ones, so:
|
||||
//
|
||||
@ -548,94 +552,124 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
|
||||
}
|
||||
|
||||
// -Ctarget-features
|
||||
let supported_features = sess.target.supported_target_features();
|
||||
let (llvm_major, _, _) = get_version();
|
||||
let mut featsmap = FxHashMap::default();
|
||||
let feats = sess
|
||||
.opts
|
||||
.cg
|
||||
.target_feature
|
||||
.split(',')
|
||||
.filter_map(|s| {
|
||||
let enable_disable = match s.chars().next() {
|
||||
None => return None,
|
||||
Some(c @ ('+' | '-')) => c,
|
||||
Some(_) => {
|
||||
if diagnostics {
|
||||
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
|
||||
if !only_base_features {
|
||||
let supported_features = sess.target.supported_target_features();
|
||||
let (llvm_major, _, _) = get_version();
|
||||
let mut featsmap = FxHashMap::default();
|
||||
|
||||
// insert implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',') {
|
||||
match feature.strip_prefix('+') {
|
||||
Some(feature) => all_rust_features.extend(
|
||||
UnordSet::from(
|
||||
sess.target
|
||||
.implied_target_features(std::iter::once(Symbol::intern(feature))),
|
||||
)
|
||||
.to_sorted_stable_ord()
|
||||
.iter()
|
||||
.map(|s| format!("+{}", s.as_str())),
|
||||
),
|
||||
_ => all_rust_features.push(feature.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
let feats = all_rust_features
|
||||
.iter()
|
||||
.filter_map(|s| {
|
||||
let enable_disable = match s.chars().next() {
|
||||
None => return None,
|
||||
Some(c @ ('+' | '-')) => c,
|
||||
Some(_) => {
|
||||
if diagnostics {
|
||||
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
|
||||
}
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let feature = backend_feature_name(sess, s)?;
|
||||
// Warn against use of LLVM specific feature names and unstable features on the CLI.
|
||||
if diagnostics {
|
||||
let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature);
|
||||
if feature_state.is_none() {
|
||||
let rust_feature =
|
||||
supported_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);
|
||||
} else if feature_state
|
||||
.is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable())
|
||||
{
|
||||
// An unstable feature. Warn about using it.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
}
|
||||
|
||||
if diagnostics {
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable_disable == '+');
|
||||
}
|
||||
|
||||
// rustc-specific features do not get passed down to LLVM…
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let feature = backend_feature_name(sess, s)?;
|
||||
// Warn against use of LLVM specific feature names and unstable features on the CLI.
|
||||
if diagnostics {
|
||||
let feature_state = supported_features.iter().find(|&&(v, _)| v == feature);
|
||||
if feature_state.is_none() {
|
||||
let rust_feature = supported_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);
|
||||
} else if feature_state
|
||||
.is_some_and(|(_name, feature_gate)| !feature_gate.is_stable())
|
||||
{
|
||||
// An unstable feature. Warn about using it.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
// if the target-feature is "backchain" and LLVM version is greater than 18
|
||||
// then we also need to add "+backchain" to the target-features attribute.
|
||||
// otherwise, we will only add the naked `backchain` attribute to the attribute-group.
|
||||
if feature == "backchain" && llvm_major < 18 {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
// ... otherwise though 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);
|
||||
|
||||
if diagnostics {
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable_disable == '+');
|
||||
}
|
||||
|
||||
// rustc-specific features do not get passed down to LLVM…
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// if the target-feature is "backchain" and LLVM version is greater than 18
|
||||
// then we also need to add "+backchain" to the target-features attribute.
|
||||
// otherwise, we will only add the naked `backchain` attribute to the attribute-group.
|
||||
if feature == "backchain" && llvm_major < 18 {
|
||||
return None;
|
||||
}
|
||||
// ... otherwise though 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);
|
||||
|
||||
Some(
|
||||
std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name))
|
||||
.chain(llvm_feature.dependency.into_iter().filter_map(move |feat| {
|
||||
match (enable_disable, feat) {
|
||||
Some(
|
||||
std::iter::once(format!(
|
||||
"{}{}",
|
||||
enable_disable, llvm_feature.llvm_feature_name
|
||||
))
|
||||
.chain(llvm_feature.dependency.into_iter().filter_map(
|
||||
move |feat| match (enable_disable, feat) {
|
||||
('-' | '+', TargetFeatureFoldStrength::Both(f))
|
||||
| ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
|
||||
Some(format!("{enable_disable}{f}"))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})),
|
||||
)
|
||||
})
|
||||
.flatten();
|
||||
features.extend(feats);
|
||||
},
|
||||
)),
|
||||
)
|
||||
})
|
||||
.flatten();
|
||||
features.extend(feats);
|
||||
|
||||
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
|
||||
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
|
||||
features: f,
|
||||
span: None,
|
||||
missing_features: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// -Zfixed-x18
|
||||
if sess.opts.unstable_opts.fixed_x18 {
|
||||
@ -646,30 +680,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
|
||||
}
|
||||
}
|
||||
|
||||
// This is a workaround for a LLVM bug that doesn't implicitly enable
|
||||
// `simd128` when `relaxed-simd` is.
|
||||
// See <https://github.com/llvm/llvm-project/pull/99803>, which didn't make
|
||||
// it into a released version of LLVM yet.
|
||||
//
|
||||
// This doesn't use the "implicit target feature" system because it is only
|
||||
// used for function attributes in other targets, which fixes this bug as
|
||||
// well on the function attribute level.
|
||||
if sess.target.families.contains(&"wasm".into()) {
|
||||
if features.iter().any(|f| f == "+relaxed-simd")
|
||||
&& !features.iter().any(|f| f == "+simd128")
|
||||
{
|
||||
features.push("+simd128".into());
|
||||
}
|
||||
}
|
||||
|
||||
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
|
||||
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
|
||||
features: f,
|
||||
span: None,
|
||||
missing_features: None,
|
||||
});
|
||||
}
|
||||
|
||||
features
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
use rustc_ast::ast;
|
||||
use rustc_attr::InstructionSetAttr;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::parse::feature_err;
|
||||
@ -18,7 +19,7 @@ pub fn from_target_feature(
|
||||
tcx: TyCtxt<'_>,
|
||||
attr: &ast::Attribute,
|
||||
supported_target_features: &UnordMap<String, Option<Symbol>>,
|
||||
target_features: &mut Vec<Symbol>,
|
||||
target_features: &mut Vec<TargetFeature>,
|
||||
) {
|
||||
let Some(list) = attr.meta_item_list() else { return };
|
||||
let bad_item = |span| {
|
||||
@ -30,6 +31,7 @@ pub fn from_target_feature(
|
||||
.emit();
|
||||
};
|
||||
let rust_features = tcx.features();
|
||||
let mut added_target_features = Vec::new();
|
||||
for item in list {
|
||||
// Only `enable = ...` is accepted in the meta-item list.
|
||||
if !item.has_name(sym::enable) {
|
||||
@ -44,7 +46,7 @@ pub fn from_target_feature(
|
||||
};
|
||||
|
||||
// We allow comma separation to enable multiple features.
|
||||
target_features.extend(value.as_str().split(',').filter_map(|feature| {
|
||||
added_target_features.extend(value.as_str().split(',').filter_map(|feature| {
|
||||
let Some(feature_gate) = supported_target_features.get(feature) else {
|
||||
let msg = format!("the feature named `{feature}` is not valid for this target");
|
||||
let mut err = tcx.dcx().struct_span_err(item.span(), msg);
|
||||
@ -98,13 +100,26 @@ pub fn from_target_feature(
|
||||
}));
|
||||
}
|
||||
|
||||
for (feature, requires) in tcx.sess.target.implicit_target_features() {
|
||||
if target_features.iter().any(|f| f.as_str() == *feature)
|
||||
&& !target_features.iter().any(|f| f.as_str() == *requires)
|
||||
{
|
||||
target_features.push(Symbol::intern(requires));
|
||||
}
|
||||
// Add explicit features
|
||||
target_features.extend(
|
||||
added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }),
|
||||
);
|
||||
|
||||
// Add implied features
|
||||
let mut implied_target_features = UnordSet::new();
|
||||
for feature in added_target_features.iter() {
|
||||
implied_target_features.extend(tcx.implied_target_features(*feature).clone());
|
||||
}
|
||||
for feature in added_target_features.iter() {
|
||||
implied_target_features.remove(feature);
|
||||
}
|
||||
target_features.extend(
|
||||
implied_target_features
|
||||
.into_sorted_stable_ord()
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|name| TargetFeature { name, implied: true }),
|
||||
)
|
||||
}
|
||||
|
||||
/// Computes the set of target features used in a function for the purposes of
|
||||
@ -113,7 +128,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
|
||||
let mut target_features = tcx.sess.unstable_target_features.clone();
|
||||
if tcx.def_kind(did).has_codegen_attrs() {
|
||||
let attrs = tcx.codegen_fn_attrs(did);
|
||||
target_features.extend(&attrs.target_features);
|
||||
target_features.extend(attrs.target_features.iter().map(|feature| feature.name));
|
||||
match attrs.instruction_set {
|
||||
None => {}
|
||||
Some(InstructionSetAttr::ArmA32) => {
|
||||
@ -158,10 +173,14 @@ pub(crate) fn provide(providers: &mut Providers) {
|
||||
.target
|
||||
.supported_target_features()
|
||||
.iter()
|
||||
.map(|&(a, b)| (a.to_string(), b.as_feature_name()))
|
||||
.map(|&(a, b, _)| (a.to_string(), b.as_feature_name()))
|
||||
.collect()
|
||||
}
|
||||
},
|
||||
implied_target_features: |tcx, feature| {
|
||||
UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature)))
|
||||
.into_sorted_stable_ord()
|
||||
},
|
||||
asm_target_features,
|
||||
..*providers
|
||||
}
|
||||
|
@ -317,19 +317,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
&& attrs
|
||||
.target_features
|
||||
.iter()
|
||||
.any(|feature| !self.tcx.sess.target_features.contains(feature))
|
||||
.any(|feature| !self.tcx.sess.target_features.contains(&feature.name))
|
||||
{
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_unavailable_target_features_for_fn,
|
||||
unavailable_feats = attrs
|
||||
.target_features
|
||||
.iter()
|
||||
.filter(|&feature| !self.tcx.sess.target_features.contains(feature))
|
||||
.filter(|&feature| !feature.implied
|
||||
&& !self.tcx.sess.target_features.contains(&feature.name))
|
||||
.fold(String::new(), |mut s, feature| {
|
||||
if !s.is_empty() {
|
||||
s.push_str(", ");
|
||||
}
|
||||
s.push_str(feature.as_str());
|
||||
s.push_str(feature.name.as_str());
|
||||
s
|
||||
}),
|
||||
);
|
||||
|
@ -28,7 +28,7 @@ pub struct CodegenFnAttrs {
|
||||
pub link_ordinal: Option<u16>,
|
||||
/// The `#[target_feature(enable = "...")]` attribute and the enabled
|
||||
/// features (only enabled features are supported right now).
|
||||
pub target_features: Vec<Symbol>,
|
||||
pub target_features: Vec<TargetFeature>,
|
||||
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
|
||||
pub linkage: Option<Linkage>,
|
||||
/// The `#[linkage = "..."]` attribute on foreign items and the value we found.
|
||||
@ -51,6 +51,15 @@ pub struct CodegenFnAttrs {
|
||||
pub patchable_function_entry: Option<PatchableFunctionEntry>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct TargetFeature {
|
||||
/// The name of the target feature (e.g. "avx")
|
||||
pub name: Symbol,
|
||||
/// The feature is implied by another feature, rather than explicitly added by the
|
||||
/// `#[target_feature]` attribute
|
||||
pub implied: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct PatchableFunctionEntry {
|
||||
/// Nops to prepend to the function
|
||||
|
@ -2183,6 +2183,12 @@ rustc_queries! {
|
||||
desc { "looking up supported target features" }
|
||||
}
|
||||
|
||||
query implied_target_features(feature: Symbol) -> &'tcx Vec<Symbol> {
|
||||
arena_cache
|
||||
eval_always
|
||||
desc { "looking up implied target features" }
|
||||
}
|
||||
|
||||
query features_query(_: ()) -> &'tcx rustc_feature::Features {
|
||||
feedable
|
||||
desc { "looking up enabled feature gates" }
|
||||
|
@ -5,6 +5,7 @@ use std::ops::Bound;
|
||||
use rustc_errors::DiagArgValue;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
|
||||
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
|
||||
use rustc_middle::mir::BorrowKind;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::thir::visit::Visitor;
|
||||
@ -31,7 +32,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
|
||||
safety_context: SafetyContext,
|
||||
/// The `#[target_feature]` attributes of the body. Used for checking
|
||||
/// calls to functions with `#[target_feature]` (RFC 2396).
|
||||
body_target_features: &'tcx [Symbol],
|
||||
body_target_features: &'tcx [TargetFeature],
|
||||
/// When inside the LHS of an assignment to a field, this is the type
|
||||
/// of the LHS and the span of the assignment expression.
|
||||
assignment_info: Option<Ty<'tcx>>,
|
||||
@ -442,14 +443,21 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
// is_like_wasm check in hir_analysis/src/collect.rs
|
||||
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
|
||||
if !self.tcx.sess.target.options.is_like_wasm
|
||||
&& !callee_features
|
||||
.iter()
|
||||
.all(|feature| self.body_target_features.contains(feature))
|
||||
&& !callee_features.iter().all(|feature| {
|
||||
self.body_target_features.iter().any(|f| f.name == feature.name)
|
||||
})
|
||||
{
|
||||
let missing: Vec<_> = callee_features
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|feature| !self.body_target_features.contains(feature))
|
||||
.filter(|feature| {
|
||||
!feature.implied
|
||||
&& !self
|
||||
.body_target_features
|
||||
.iter()
|
||||
.any(|body_feature| body_feature.name == feature.name)
|
||||
})
|
||||
.map(|feature| feature.name)
|
||||
.collect();
|
||||
let build_enabled = self
|
||||
.tcx
|
||||
|
@ -479,7 +479,9 @@ impl<'tcx> Inliner<'tcx> {
|
||||
return Err("incompatible instruction set");
|
||||
}
|
||||
|
||||
if callee_attrs.target_features != self.codegen_fn_attrs.target_features {
|
||||
let callee_feature_names = callee_attrs.target_features.iter().map(|f| f.name);
|
||||
let this_feature_names = self.codegen_fn_attrs.target_features.iter().map(|f| f.name);
|
||||
if callee_feature_names.ne(this_feature_names) {
|
||||
// In general it is not correct to inline a callee with target features that are a
|
||||
// subset of the caller. This is because the callee might contain calls, and the ABI of
|
||||
// those calls depends on the target features of the surrounding function. By moving a
|
||||
|
@ -1,3 +1,4 @@
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
/// Features that control behaviour of rustc, rather than the codegen.
|
||||
@ -53,136 +54,154 @@ impl Stability {
|
||||
//
|
||||
// Stabilizing a target feature requires t-lang approval.
|
||||
|
||||
const ARM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
type ImpliedFeatures = &'static [&'static str];
|
||||
|
||||
const ARM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("aclass", Unstable(sym::arm_target_feature)),
|
||||
("aes", Unstable(sym::arm_target_feature)),
|
||||
("crc", Unstable(sym::arm_target_feature)),
|
||||
("d32", Unstable(sym::arm_target_feature)),
|
||||
("dotprod", Unstable(sym::arm_target_feature)),
|
||||
("dsp", Unstable(sym::arm_target_feature)),
|
||||
("fp-armv8", Unstable(sym::arm_target_feature)),
|
||||
("i8mm", Unstable(sym::arm_target_feature)),
|
||||
("mclass", Unstable(sym::arm_target_feature)),
|
||||
("neon", Unstable(sym::arm_target_feature)),
|
||||
("rclass", Unstable(sym::arm_target_feature)),
|
||||
("sha2", Unstable(sym::arm_target_feature)),
|
||||
("aclass", Unstable(sym::arm_target_feature), &[]),
|
||||
("aes", Unstable(sym::arm_target_feature), &["neon"]),
|
||||
("crc", Unstable(sym::arm_target_feature), &[]),
|
||||
("d32", Unstable(sym::arm_target_feature), &[]),
|
||||
("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
|
||||
("dsp", Unstable(sym::arm_target_feature), &[]),
|
||||
("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]),
|
||||
("i8mm", Unstable(sym::arm_target_feature), &["neon"]),
|
||||
("mclass", Unstable(sym::arm_target_feature), &[]),
|
||||
("neon", Unstable(sym::arm_target_feature), &["vfp3"]),
|
||||
("rclass", Unstable(sym::arm_target_feature), &[]),
|
||||
("sha2", Unstable(sym::arm_target_feature), &["neon"]),
|
||||
// This is needed for inline assembly, but shouldn't be stabilized as-is
|
||||
// since it should be enabled per-function using #[instruction_set], not
|
||||
// #[target_feature].
|
||||
("thumb-mode", Unstable(sym::arm_target_feature)),
|
||||
("thumb2", Unstable(sym::arm_target_feature)),
|
||||
("trustzone", Unstable(sym::arm_target_feature)),
|
||||
("v5te", Unstable(sym::arm_target_feature)),
|
||||
("v6", Unstable(sym::arm_target_feature)),
|
||||
("v6k", Unstable(sym::arm_target_feature)),
|
||||
("v6t2", Unstable(sym::arm_target_feature)),
|
||||
("v7", Unstable(sym::arm_target_feature)),
|
||||
("v8", Unstable(sym::arm_target_feature)),
|
||||
("vfp2", Unstable(sym::arm_target_feature)),
|
||||
("vfp3", Unstable(sym::arm_target_feature)),
|
||||
("vfp4", Unstable(sym::arm_target_feature)),
|
||||
("virtualization", Unstable(sym::arm_target_feature)),
|
||||
("thumb-mode", Unstable(sym::arm_target_feature), &[]),
|
||||
("thumb2", Unstable(sym::arm_target_feature), &[]),
|
||||
("trustzone", Unstable(sym::arm_target_feature), &[]),
|
||||
("v5te", Unstable(sym::arm_target_feature), &[]),
|
||||
("v6", Unstable(sym::arm_target_feature), &["v5te"]),
|
||||
("v6k", Unstable(sym::arm_target_feature), &["v6"]),
|
||||
("v6t2", Unstable(sym::arm_target_feature), &["v6k", "thumb2"]),
|
||||
("v7", Unstable(sym::arm_target_feature), &["v6t2"]),
|
||||
("v8", Unstable(sym::arm_target_feature), &["v7"]),
|
||||
("vfp2", Unstable(sym::arm_target_feature), &[]),
|
||||
("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]),
|
||||
("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]),
|
||||
("virtualization", Unstable(sym::arm_target_feature), &[]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
// FEAT_AES & FEAT_PMULL
|
||||
("aes", Stable),
|
||||
("aes", Stable, &["neon"]),
|
||||
// FEAT_BF16
|
||||
("bf16", Stable),
|
||||
("bf16", Stable, &[]),
|
||||
// FEAT_BTI
|
||||
("bti", Stable),
|
||||
("bti", Stable, &[]),
|
||||
// FEAT_CRC
|
||||
("crc", Stable),
|
||||
("crc", Stable, &[]),
|
||||
// FEAT_DIT
|
||||
("dit", Stable),
|
||||
("dit", Stable, &[]),
|
||||
// FEAT_DotProd
|
||||
("dotprod", Stable),
|
||||
("dotprod", Stable, &["neon"]),
|
||||
// FEAT_DPB
|
||||
("dpb", Stable),
|
||||
("dpb", Stable, &[]),
|
||||
// FEAT_DPB2
|
||||
("dpb2", Stable),
|
||||
("dpb2", Stable, &["dpb"]),
|
||||
// FEAT_F32MM
|
||||
("f32mm", Stable),
|
||||
("f32mm", Stable, &["sve"]),
|
||||
// FEAT_F64MM
|
||||
("f64mm", Stable),
|
||||
("f64mm", Stable, &["sve"]),
|
||||
// FEAT_FCMA
|
||||
("fcma", Stable),
|
||||
("fcma", Stable, &["neon"]),
|
||||
// FEAT_FHM
|
||||
("fhm", Stable),
|
||||
("fhm", Stable, &["fp16"]),
|
||||
// FEAT_FLAGM
|
||||
("flagm", Stable),
|
||||
("flagm", Stable, &[]),
|
||||
// FEAT_FP16
|
||||
("fp16", Stable),
|
||||
// Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
|
||||
("fp16", Stable, &["neon"]),
|
||||
// FEAT_FRINTTS
|
||||
("frintts", Stable),
|
||||
("frintts", Stable, &[]),
|
||||
// FEAT_I8MM
|
||||
("i8mm", Stable),
|
||||
("i8mm", Stable, &[]),
|
||||
// FEAT_JSCVT
|
||||
("jsconv", Stable),
|
||||
// Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
|
||||
("jsconv", Stable, &["neon"]),
|
||||
// FEAT_LOR
|
||||
("lor", Stable),
|
||||
("lor", Stable, &[]),
|
||||
// FEAT_LSE
|
||||
("lse", Stable),
|
||||
("lse", Stable, &[]),
|
||||
// FEAT_MTE & FEAT_MTE2
|
||||
("mte", Stable),
|
||||
("mte", Stable, &[]),
|
||||
// FEAT_AdvSimd & FEAT_FP
|
||||
("neon", Stable),
|
||||
("neon", Stable, &[]),
|
||||
// FEAT_PAUTH (address authentication)
|
||||
("paca", Stable),
|
||||
("paca", Stable, &[]),
|
||||
// FEAT_PAUTH (generic authentication)
|
||||
("pacg", Stable),
|
||||
("pacg", Stable, &[]),
|
||||
// FEAT_PAN
|
||||
("pan", Stable),
|
||||
("pan", Stable, &[]),
|
||||
// FEAT_PMUv3
|
||||
("pmuv3", Stable),
|
||||
("pmuv3", Stable, &[]),
|
||||
// FEAT_RAND
|
||||
("rand", Stable),
|
||||
("rand", Stable, &[]),
|
||||
// FEAT_RAS & FEAT_RASv1p1
|
||||
("ras", Stable),
|
||||
("ras", Stable, &[]),
|
||||
// FEAT_RCPC
|
||||
("rcpc", Stable),
|
||||
("rcpc", Stable, &[]),
|
||||
// FEAT_RCPC2
|
||||
("rcpc2", Stable),
|
||||
("rcpc2", Stable, &["rcpc"]),
|
||||
// FEAT_RDM
|
||||
("rdm", Stable),
|
||||
("rdm", Stable, &["neon"]),
|
||||
// FEAT_SB
|
||||
("sb", Stable),
|
||||
("sb", Stable, &[]),
|
||||
// FEAT_SHA1 & FEAT_SHA256
|
||||
("sha2", Stable),
|
||||
("sha2", Stable, &["neon"]),
|
||||
// FEAT_SHA512 & FEAT_SHA3
|
||||
("sha3", Stable),
|
||||
("sha3", Stable, &["sha2"]),
|
||||
// FEAT_SM3 & FEAT_SM4
|
||||
("sm4", Stable),
|
||||
("sm4", Stable, &["neon"]),
|
||||
// FEAT_SPE
|
||||
("spe", Stable),
|
||||
("spe", Stable, &[]),
|
||||
// FEAT_SSBS & FEAT_SSBS2
|
||||
("ssbs", Stable),
|
||||
("ssbs", Stable, &[]),
|
||||
// FEAT_SVE
|
||||
("sve", Stable),
|
||||
// It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608
|
||||
//
|
||||
// LLVM doesn't enable Neon for SVE. ARM indicates that they're separate, but probably always
|
||||
// exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2
|
||||
//
|
||||
// "For backwards compatibility, Neon and VFP are required in the latest architectures."
|
||||
("sve", Stable, &["neon"]),
|
||||
// FEAT_SVE2
|
||||
("sve2", Stable),
|
||||
("sve2", Stable, &["sve"]),
|
||||
// FEAT_SVE2_AES
|
||||
("sve2-aes", Stable),
|
||||
("sve2-aes", Stable, &["sve2", "aes"]),
|
||||
// FEAT_SVE2_BitPerm
|
||||
("sve2-bitperm", Stable),
|
||||
("sve2-bitperm", Stable, &["sve2"]),
|
||||
// FEAT_SVE2_SHA3
|
||||
("sve2-sha3", Stable),
|
||||
("sve2-sha3", Stable, &["sve2", "sha3"]),
|
||||
// FEAT_SVE2_SM4
|
||||
("sve2-sm4", Stable),
|
||||
("sve2-sm4", Stable, &["sve2", "sm4"]),
|
||||
// FEAT_TME
|
||||
("tme", Stable),
|
||||
("v8.1a", Unstable(sym::aarch64_ver_target_feature)),
|
||||
("v8.2a", Unstable(sym::aarch64_ver_target_feature)),
|
||||
("v8.3a", Unstable(sym::aarch64_ver_target_feature)),
|
||||
("v8.4a", Unstable(sym::aarch64_ver_target_feature)),
|
||||
("v8.5a", Unstable(sym::aarch64_ver_target_feature)),
|
||||
("v8.6a", Unstable(sym::aarch64_ver_target_feature)),
|
||||
("v8.7a", Unstable(sym::aarch64_ver_target_feature)),
|
||||
("tme", Stable, &[]),
|
||||
(
|
||||
"v8.1a",
|
||||
Unstable(sym::aarch64_ver_target_feature),
|
||||
&["crc", "lse", "rdm", "pan", "lor", "vh"],
|
||||
),
|
||||
("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]),
|
||||
(
|
||||
"v8.3a",
|
||||
Unstable(sym::aarch64_ver_target_feature),
|
||||
&["v8.2a", "rcpc", "paca", "pacg", "jsconv"],
|
||||
),
|
||||
("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]),
|
||||
("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]),
|
||||
("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]),
|
||||
("v8.7a", Unstable(sym::aarch64_ver_target_feature), &[]),
|
||||
// FEAT_VHE
|
||||
("vh", Stable),
|
||||
("vh", Stable, &[]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
@ -190,224 +209,223 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
|
||||
&["paca", "pacg"], // Together these represent `pauth` in LLVM
|
||||
];
|
||||
|
||||
const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
const X86_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("adx", Stable),
|
||||
("aes", Stable),
|
||||
("amx-bf16", Unstable(sym::x86_amx_intrinsics)),
|
||||
("amx-complex", Unstable(sym::x86_amx_intrinsics)),
|
||||
("amx-fp16", Unstable(sym::x86_amx_intrinsics)),
|
||||
("amx-int8", Unstable(sym::x86_amx_intrinsics)),
|
||||
("amx-tile", Unstable(sym::x86_amx_intrinsics)),
|
||||
("avx", Stable),
|
||||
("avx2", Stable),
|
||||
("avx512bf16", Unstable(sym::avx512_target_feature)),
|
||||
("avx512bitalg", Unstable(sym::avx512_target_feature)),
|
||||
("avx512bw", Unstable(sym::avx512_target_feature)),
|
||||
("avx512cd", Unstable(sym::avx512_target_feature)),
|
||||
("avx512dq", Unstable(sym::avx512_target_feature)),
|
||||
("avx512f", Unstable(sym::avx512_target_feature)),
|
||||
("avx512fp16", Unstable(sym::avx512_target_feature)),
|
||||
("avx512ifma", Unstable(sym::avx512_target_feature)),
|
||||
("avx512vbmi", Unstable(sym::avx512_target_feature)),
|
||||
("avx512vbmi2", Unstable(sym::avx512_target_feature)),
|
||||
("avx512vl", Unstable(sym::avx512_target_feature)),
|
||||
("avx512vnni", Unstable(sym::avx512_target_feature)),
|
||||
("avx512vp2intersect", Unstable(sym::avx512_target_feature)),
|
||||
("avx512vpopcntdq", Unstable(sym::avx512_target_feature)),
|
||||
("avxifma", Unstable(sym::avx512_target_feature)),
|
||||
("avxneconvert", Unstable(sym::avx512_target_feature)),
|
||||
("avxvnni", Unstable(sym::avx512_target_feature)),
|
||||
("avxvnniint16", Unstable(sym::avx512_target_feature)),
|
||||
("avxvnniint8", Unstable(sym::avx512_target_feature)),
|
||||
("bmi1", Stable),
|
||||
("bmi2", Stable),
|
||||
("cmpxchg16b", Stable),
|
||||
("ermsb", Unstable(sym::ermsb_target_feature)),
|
||||
("f16c", Stable),
|
||||
("fma", Stable),
|
||||
("fxsr", Stable),
|
||||
("gfni", Unstable(sym::avx512_target_feature)),
|
||||
("lahfsahf", Unstable(sym::lahfsahf_target_feature)),
|
||||
("lzcnt", Stable),
|
||||
("movbe", Stable),
|
||||
("pclmulqdq", Stable),
|
||||
("popcnt", Stable),
|
||||
("prfchw", Unstable(sym::prfchw_target_feature)),
|
||||
("rdrand", Stable),
|
||||
("rdseed", Stable),
|
||||
("rtm", Unstable(sym::rtm_target_feature)),
|
||||
("sha", Stable),
|
||||
("sha512", Unstable(sym::sha512_sm_x86)),
|
||||
("sm3", Unstable(sym::sha512_sm_x86)),
|
||||
("sm4", Unstable(sym::sha512_sm_x86)),
|
||||
("sse", Stable),
|
||||
("sse2", Stable),
|
||||
("sse3", Stable),
|
||||
("sse4.1", Stable),
|
||||
("sse4.2", Stable),
|
||||
("sse4a", Unstable(sym::sse4a_target_feature)),
|
||||
("ssse3", Stable),
|
||||
("tbm", Unstable(sym::tbm_target_feature)),
|
||||
("vaes", Unstable(sym::avx512_target_feature)),
|
||||
("vpclmulqdq", Unstable(sym::avx512_target_feature)),
|
||||
("xop", Unstable(sym::xop_target_feature)),
|
||||
("xsave", Stable),
|
||||
("xsavec", Stable),
|
||||
("xsaveopt", Stable),
|
||||
("xsaves", Stable),
|
||||
("adx", Stable, &[]),
|
||||
("aes", Stable, &["sse2"]),
|
||||
("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
|
||||
("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
|
||||
("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
|
||||
("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
|
||||
("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]),
|
||||
("avx", Stable, &["sse4.2"]),
|
||||
("avx2", Stable, &["avx"]),
|
||||
("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]),
|
||||
("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]),
|
||||
("avx512bw", Unstable(sym::avx512_target_feature), &["avx512f"]),
|
||||
("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]),
|
||||
("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]),
|
||||
("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]),
|
||||
("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]),
|
||||
("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]),
|
||||
("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]),
|
||||
("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]),
|
||||
("avx512vl", Unstable(sym::avx512_target_feature), &["avx512f"]),
|
||||
("avx512vnni", Unstable(sym::avx512_target_feature), &["avx512f"]),
|
||||
("avx512vp2intersect", Unstable(sym::avx512_target_feature), &["avx512f"]),
|
||||
("avx512vpopcntdq", Unstable(sym::avx512_target_feature), &["avx512f"]),
|
||||
("avxifma", Unstable(sym::avx512_target_feature), &["avx2"]),
|
||||
("avxneconvert", Unstable(sym::avx512_target_feature), &["avx2"]),
|
||||
("avxvnni", Unstable(sym::avx512_target_feature), &["avx2"]),
|
||||
("avxvnniint16", Unstable(sym::avx512_target_feature), &["avx2"]),
|
||||
("avxvnniint8", Unstable(sym::avx512_target_feature), &["avx2"]),
|
||||
("bmi1", Stable, &[]),
|
||||
("bmi2", Stable, &[]),
|
||||
("cmpxchg16b", Stable, &[]),
|
||||
("ermsb", Unstable(sym::ermsb_target_feature), &[]),
|
||||
("f16c", Stable, &["avx"]),
|
||||
("fma", Stable, &["avx"]),
|
||||
("fxsr", Stable, &[]),
|
||||
("gfni", Unstable(sym::avx512_target_feature), &["sse2"]),
|
||||
("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
|
||||
("lzcnt", Stable, &[]),
|
||||
("movbe", Stable, &[]),
|
||||
("pclmulqdq", Stable, &[]),
|
||||
("popcnt", Stable, &[]),
|
||||
("prfchw", Unstable(sym::prfchw_target_feature), &[]),
|
||||
("rdrand", Stable, &[]),
|
||||
("rdseed", Stable, &[]),
|
||||
("rtm", Unstable(sym::rtm_target_feature), &[]),
|
||||
("sha", Stable, &["sse2"]),
|
||||
("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
|
||||
("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
|
||||
("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
|
||||
("sse", Stable, &[]),
|
||||
("sse2", Stable, &["sse"]),
|
||||
("sse3", Stable, &["sse2"]),
|
||||
("sse4.1", Stable, &["ssse3"]),
|
||||
("sse4.2", Stable, &["sse4.1"]),
|
||||
("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]),
|
||||
("ssse3", Stable, &["sse3"]),
|
||||
("tbm", Unstable(sym::tbm_target_feature), &[]),
|
||||
("vaes", Unstable(sym::avx512_target_feature), &["avx2", "aes"]),
|
||||
("vpclmulqdq", Unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
|
||||
("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
|
||||
("xsave", Stable, &[]),
|
||||
("xsavec", Stable, &["xsave"]),
|
||||
("xsaveopt", Stable, &["xsave"]),
|
||||
("xsaves", Stable, &["xsave"]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("hvx", Unstable(sym::hexagon_target_feature)),
|
||||
("hvx-length128b", Unstable(sym::hexagon_target_feature)),
|
||||
("hvx", Unstable(sym::hexagon_target_feature), &[]),
|
||||
("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const POWERPC_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
const POWERPC_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("altivec", Unstable(sym::powerpc_target_feature)),
|
||||
("power10-vector", Unstable(sym::powerpc_target_feature)),
|
||||
("power8-altivec", Unstable(sym::powerpc_target_feature)),
|
||||
("power8-vector", Unstable(sym::powerpc_target_feature)),
|
||||
("power9-altivec", Unstable(sym::powerpc_target_feature)),
|
||||
("power9-vector", Unstable(sym::powerpc_target_feature)),
|
||||
("vsx", Unstable(sym::powerpc_target_feature)),
|
||||
("altivec", Unstable(sym::powerpc_target_feature), &[]),
|
||||
("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]),
|
||||
("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]),
|
||||
("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
|
||||
("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
|
||||
("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
|
||||
("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const MIPS_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("fp64", Unstable(sym::mips_target_feature)),
|
||||
("msa", Unstable(sym::mips_target_feature)),
|
||||
("virt", Unstable(sym::mips_target_feature)),
|
||||
("fp64", Unstable(sym::mips_target_feature), &[]),
|
||||
("msa", Unstable(sym::mips_target_feature), &[]),
|
||||
("virt", Unstable(sym::mips_target_feature), &[]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const RISCV_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("a", Stable),
|
||||
("c", Stable),
|
||||
("d", Unstable(sym::riscv_target_feature)),
|
||||
("e", Unstable(sym::riscv_target_feature)),
|
||||
("f", Unstable(sym::riscv_target_feature)),
|
||||
("m", Stable),
|
||||
("relax", Unstable(sym::riscv_target_feature)),
|
||||
("unaligned-scalar-mem", Unstable(sym::riscv_target_feature)),
|
||||
("v", Unstable(sym::riscv_target_feature)),
|
||||
("zba", Stable),
|
||||
("zbb", Stable),
|
||||
("zbc", Stable),
|
||||
("zbkb", Stable),
|
||||
("zbkc", Stable),
|
||||
("zbkx", Stable),
|
||||
("zbs", Stable),
|
||||
("zdinx", Unstable(sym::riscv_target_feature)),
|
||||
("zfh", Unstable(sym::riscv_target_feature)),
|
||||
("zfhmin", Unstable(sym::riscv_target_feature)),
|
||||
("zfinx", Unstable(sym::riscv_target_feature)),
|
||||
("zhinx", Unstable(sym::riscv_target_feature)),
|
||||
("zhinxmin", Unstable(sym::riscv_target_feature)),
|
||||
("zk", Stable),
|
||||
("zkn", Stable),
|
||||
("zknd", Stable),
|
||||
("zkne", Stable),
|
||||
("zknh", Stable),
|
||||
("zkr", Stable),
|
||||
("zks", Stable),
|
||||
("zksed", Stable),
|
||||
("zksh", Stable),
|
||||
("zkt", Stable),
|
||||
("a", Stable, &[]),
|
||||
("c", Stable, &[]),
|
||||
("d", Unstable(sym::riscv_target_feature), &["f"]),
|
||||
("e", Unstable(sym::riscv_target_feature), &[]),
|
||||
("f", Unstable(sym::riscv_target_feature), &[]),
|
||||
("m", Stable, &[]),
|
||||
("relax", Unstable(sym::riscv_target_feature), &[]),
|
||||
("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
|
||||
("v", Unstable(sym::riscv_target_feature), &[]),
|
||||
("zba", Stable, &[]),
|
||||
("zbb", Stable, &[]),
|
||||
("zbc", Stable, &[]),
|
||||
("zbkb", Stable, &[]),
|
||||
("zbkc", Stable, &[]),
|
||||
("zbkx", Stable, &[]),
|
||||
("zbs", Stable, &[]),
|
||||
("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
|
||||
("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
|
||||
("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
|
||||
("zfinx", Unstable(sym::riscv_target_feature), &[]),
|
||||
("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
|
||||
("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
|
||||
("zk", Stable, &["zkn", "zkr", "zkt"]),
|
||||
("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
|
||||
("zknd", Stable, &[]),
|
||||
("zkne", Stable, &[]),
|
||||
("zknh", Stable, &[]),
|
||||
("zkr", Stable, &[]),
|
||||
("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
|
||||
("zksed", Stable, &[]),
|
||||
("zksh", Stable, &[]),
|
||||
("zkt", Stable, &[]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
const WASM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("atomics", Unstable(sym::wasm_target_feature)),
|
||||
("bulk-memory", Stable),
|
||||
("exception-handling", Unstable(sym::wasm_target_feature)),
|
||||
("extended-const", Stable),
|
||||
("multivalue", Unstable(sym::wasm_target_feature)),
|
||||
("mutable-globals", Stable),
|
||||
("nontrapping-fptoint", Stable),
|
||||
("reference-types", Unstable(sym::wasm_target_feature)),
|
||||
("relaxed-simd", Stable),
|
||||
("sign-ext", Stable),
|
||||
("simd128", Stable),
|
||||
("atomics", Unstable(sym::wasm_target_feature), &[]),
|
||||
("bulk-memory", Stable, &[]),
|
||||
("exception-handling", Unstable(sym::wasm_target_feature), &[]),
|
||||
("extended-const", Stable, &[]),
|
||||
("multivalue", Unstable(sym::wasm_target_feature), &[]),
|
||||
("mutable-globals", Stable, &[]),
|
||||
("nontrapping-fptoint", Stable, &[]),
|
||||
("reference-types", Unstable(sym::wasm_target_feature), &[]),
|
||||
("relaxed-simd", Stable, &["simd128"]),
|
||||
("sign-ext", Stable, &[]),
|
||||
("simd128", Stable, &[]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const WASM_IMPLICIT_FEATURES: &[(&str, &str)] = &[("relaxed-simd", "simd128")];
|
||||
const BPF_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
|
||||
&[("alu32", Unstable(sym::bpf_target_feature), &[])];
|
||||
|
||||
const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))];
|
||||
|
||||
const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
const CSKY_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("10e60", Unstable(sym::csky_target_feature)),
|
||||
("2e3", Unstable(sym::csky_target_feature)),
|
||||
("3e3r1", Unstable(sym::csky_target_feature)),
|
||||
("3e3r2", Unstable(sym::csky_target_feature)),
|
||||
("3e3r3", Unstable(sym::csky_target_feature)),
|
||||
("3e7", Unstable(sym::csky_target_feature)),
|
||||
("7e10", Unstable(sym::csky_target_feature)),
|
||||
("cache", Unstable(sym::csky_target_feature)),
|
||||
("doloop", Unstable(sym::csky_target_feature)),
|
||||
("dsp1e2", Unstable(sym::csky_target_feature)),
|
||||
("dspe60", Unstable(sym::csky_target_feature)),
|
||||
("e1", Unstable(sym::csky_target_feature)),
|
||||
("e2", Unstable(sym::csky_target_feature)),
|
||||
("edsp", Unstable(sym::csky_target_feature)),
|
||||
("elrw", Unstable(sym::csky_target_feature)),
|
||||
("float1e2", Unstable(sym::csky_target_feature)),
|
||||
("float1e3", Unstable(sym::csky_target_feature)),
|
||||
("float3e4", Unstable(sym::csky_target_feature)),
|
||||
("float7e60", Unstable(sym::csky_target_feature)),
|
||||
("floate1", Unstable(sym::csky_target_feature)),
|
||||
("hard-tp", Unstable(sym::csky_target_feature)),
|
||||
("high-registers", Unstable(sym::csky_target_feature)),
|
||||
("hwdiv", Unstable(sym::csky_target_feature)),
|
||||
("mp", Unstable(sym::csky_target_feature)),
|
||||
("mp1e2", Unstable(sym::csky_target_feature)),
|
||||
("nvic", Unstable(sym::csky_target_feature)),
|
||||
("trust", Unstable(sym::csky_target_feature)),
|
||||
("vdsp2e60f", Unstable(sym::csky_target_feature)),
|
||||
("vdspv1", Unstable(sym::csky_target_feature)),
|
||||
("vdspv2", Unstable(sym::csky_target_feature)),
|
||||
("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
|
||||
("2e3", Unstable(sym::csky_target_feature), &["e2"]),
|
||||
("3e3r1", Unstable(sym::csky_target_feature), &[]),
|
||||
("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
|
||||
("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]),
|
||||
("3e7", Unstable(sym::csky_target_feature), &["2e3"]),
|
||||
("7e10", Unstable(sym::csky_target_feature), &["3e7"]),
|
||||
("cache", Unstable(sym::csky_target_feature), &[]),
|
||||
("doloop", Unstable(sym::csky_target_feature), &[]),
|
||||
("dsp1e2", Unstable(sym::csky_target_feature), &[]),
|
||||
("dspe60", Unstable(sym::csky_target_feature), &[]),
|
||||
("e1", Unstable(sym::csky_target_feature), &["elrw"]),
|
||||
("e2", Unstable(sym::csky_target_feature), &["e2"]),
|
||||
("edsp", Unstable(sym::csky_target_feature), &[]),
|
||||
("elrw", Unstable(sym::csky_target_feature), &[]),
|
||||
("float1e2", Unstable(sym::csky_target_feature), &[]),
|
||||
("float1e3", Unstable(sym::csky_target_feature), &[]),
|
||||
("float3e4", Unstable(sym::csky_target_feature), &[]),
|
||||
("float7e60", Unstable(sym::csky_target_feature), &[]),
|
||||
("floate1", Unstable(sym::csky_target_feature), &[]),
|
||||
("hard-tp", Unstable(sym::csky_target_feature), &[]),
|
||||
("high-registers", Unstable(sym::csky_target_feature), &[]),
|
||||
("hwdiv", Unstable(sym::csky_target_feature), &[]),
|
||||
("mp", Unstable(sym::csky_target_feature), &["2e3"]),
|
||||
("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]),
|
||||
("nvic", Unstable(sym::csky_target_feature), &[]),
|
||||
("trust", Unstable(sym::csky_target_feature), &[]),
|
||||
("vdsp2e60f", Unstable(sym::csky_target_feature), &[]),
|
||||
("vdspv1", Unstable(sym::csky_target_feature), &[]),
|
||||
("vdspv2", Unstable(sym::csky_target_feature), &[]),
|
||||
// tidy-alphabetical-end
|
||||
//fpu
|
||||
// tidy-alphabetical-start
|
||||
("fdivdu", Unstable(sym::csky_target_feature)),
|
||||
("fpuv2_df", Unstable(sym::csky_target_feature)),
|
||||
("fpuv2_sf", Unstable(sym::csky_target_feature)),
|
||||
("fpuv3_df", Unstable(sym::csky_target_feature)),
|
||||
("fpuv3_hf", Unstable(sym::csky_target_feature)),
|
||||
("fpuv3_hi", Unstable(sym::csky_target_feature)),
|
||||
("fpuv3_sf", Unstable(sym::csky_target_feature)),
|
||||
("hard-float", Unstable(sym::csky_target_feature)),
|
||||
("hard-float-abi", Unstable(sym::csky_target_feature)),
|
||||
("fdivdu", Unstable(sym::csky_target_feature), &[]),
|
||||
("fpuv2_df", Unstable(sym::csky_target_feature), &[]),
|
||||
("fpuv2_sf", Unstable(sym::csky_target_feature), &[]),
|
||||
("fpuv3_df", Unstable(sym::csky_target_feature), &[]),
|
||||
("fpuv3_hf", Unstable(sym::csky_target_feature), &[]),
|
||||
("fpuv3_hi", Unstable(sym::csky_target_feature), &[]),
|
||||
("fpuv3_sf", Unstable(sym::csky_target_feature), &[]),
|
||||
("hard-float", Unstable(sym::csky_target_feature), &[]),
|
||||
("hard-float-abi", Unstable(sym::csky_target_feature), &[]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("d", Unstable(sym::loongarch_target_feature)),
|
||||
("f", Unstable(sym::loongarch_target_feature)),
|
||||
("frecipe", Unstable(sym::loongarch_target_feature)),
|
||||
("lasx", Unstable(sym::loongarch_target_feature)),
|
||||
("lbt", Unstable(sym::loongarch_target_feature)),
|
||||
("lsx", Unstable(sym::loongarch_target_feature)),
|
||||
("lvz", Unstable(sym::loongarch_target_feature)),
|
||||
("relax", Unstable(sym::loongarch_target_feature)),
|
||||
("ual", Unstable(sym::loongarch_target_feature)),
|
||||
("d", Unstable(sym::loongarch_target_feature), &["f"]),
|
||||
("f", Unstable(sym::loongarch_target_feature), &[]),
|
||||
("frecipe", Unstable(sym::loongarch_target_feature), &[]),
|
||||
("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]),
|
||||
("lbt", Unstable(sym::loongarch_target_feature), &[]),
|
||||
("lsx", Unstable(sym::loongarch_target_feature), &["d"]),
|
||||
("lvz", Unstable(sym::loongarch_target_feature), &[]),
|
||||
("relax", Unstable(sym::loongarch_target_feature), &[]),
|
||||
("ual", Unstable(sym::loongarch_target_feature), &[]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[
|
||||
const IBMZ_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("backchain", Unstable(sym::s390x_target_feature)),
|
||||
("vector", Unstable(sym::s390x_target_feature)),
|
||||
("backchain", Unstable(sym::s390x_target_feature), &[]),
|
||||
("vector", Unstable(sym::s390x_target_feature), &[]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
@ -430,10 +448,13 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> {
|
||||
.chain(LOONGARCH_ALLOWED_FEATURES)
|
||||
.chain(IBMZ_ALLOWED_FEATURES)
|
||||
.cloned()
|
||||
.map(|(f, s, _)| (f, s))
|
||||
}
|
||||
|
||||
impl super::spec::Target {
|
||||
pub fn supported_target_features(&self) -> &'static [(&'static str, Stability)] {
|
||||
pub fn supported_target_features(
|
||||
&self,
|
||||
) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
|
||||
match &*self.arch {
|
||||
"arm" => ARM_ALLOWED_FEATURES,
|
||||
"aarch64" | "arm64ec" => AARCH64_ALLOWED_FEATURES,
|
||||
@ -458,12 +479,27 @@ impl super::spec::Target {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a list of target features. Each items first target feature
|
||||
/// implicitly enables the second one.
|
||||
pub fn implicit_target_features(&self) -> &'static [(&'static str, &'static str)] {
|
||||
match &*self.arch {
|
||||
"wasm32" | "wasm64" => WASM_IMPLICIT_FEATURES,
|
||||
_ => &[],
|
||||
pub fn implied_target_features(
|
||||
&self,
|
||||
base_features: impl Iterator<Item = Symbol>,
|
||||
) -> FxHashSet<Symbol> {
|
||||
let implied_features = self
|
||||
.supported_target_features()
|
||||
.iter()
|
||||
.map(|(f, _, i)| (Symbol::intern(f), i))
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
|
||||
// implied target features have their own 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 = base_features.collect::<Vec<Symbol>>();
|
||||
while let Some(new_feature) = new_features.pop() {
|
||||
if features.insert(new_feature) {
|
||||
if let Some(implied_features) = implied_features.get(&new_feature) {
|
||||
new_features.extend(implied_features.iter().copied().map(Symbol::intern))
|
||||
}
|
||||
}
|
||||
}
|
||||
features
|
||||
}
|
||||
}
|
||||
|
@ -12,4 +12,4 @@ pub unsafe fn crc32sse(v: u8) -> u32 {
|
||||
_mm_crc32_u8(out, v)
|
||||
}
|
||||
|
||||
// CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32"}}
|
||||
// CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32.*"}}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//@ revisions: COMPAT INCOMPAT
|
||||
//@ needs-llvm-components: x86
|
||||
//@ compile-flags: --target=x86_64-unknown-linux-gnu -Copt-level=3
|
||||
//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2,+avx
|
||||
//@ [COMPAT] compile-flags: -Ctarget-feature=+avx2
|
||||
//@ [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx
|
||||
|
||||
// See also tests/assembly/target-feature-multiple.rs
|
||||
@ -39,8 +39,8 @@ pub unsafe fn banana() -> u32 {
|
||||
}
|
||||
|
||||
// CHECK: attributes [[APPLEATTRS]]
|
||||
// COMPAT-SAME: "target-features"="+avx2,+avx,+avx"
|
||||
// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx"
|
||||
// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
|
||||
// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
|
||||
// CHECK: attributes [[BANANAATTRS]]
|
||||
// COMPAT-SAME: "target-features"="+avx2,+avx"
|
||||
// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
|
||||
// INCOMPAT-SAME: "target-features"="-avx2,-avx"
|
||||
|
@ -8,7 +8,7 @@
|
||||
// is LLVM-14 we can remove the optional regex matching for this feature.
|
||||
|
||||
//@ [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0
|
||||
// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(\+sve,?)|(\+neon,?))*}}" }
|
||||
// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
|
||||
|
||||
//@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
|
||||
// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(-sve,?)|(\+neon,?))*}}" }
|
||||
|
@ -34,6 +34,7 @@ fn foo() {
|
||||
|
||||
#[target_feature(enable = "sse2")]
|
||||
fn bar() {
|
||||
sse2();
|
||||
avx_bmi2();
|
||||
//~^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
|
||||
Quux.avx_bmi2();
|
||||
@ -43,7 +44,6 @@ fn bar() {
|
||||
#[target_feature(enable = "avx")]
|
||||
fn baz() {
|
||||
sse2();
|
||||
//~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
|
||||
avx_bmi2();
|
||||
//~^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
|
||||
Quux.avx_bmi2();
|
||||
@ -54,7 +54,8 @@ fn baz() {
|
||||
#[target_feature(enable = "bmi2")]
|
||||
fn qux() {
|
||||
sse2();
|
||||
//~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
|
||||
avx_bmi2();
|
||||
Quux.avx_bmi2();
|
||||
}
|
||||
|
||||
const _: () = sse2();
|
||||
@ -64,8 +65,6 @@ const _: () = sse2_and_fxsr();
|
||||
//~^ ERROR call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe
|
||||
|
||||
#[deny(unsafe_op_in_unsafe_fn)]
|
||||
#[target_feature(enable = "avx")]
|
||||
#[target_feature(enable = "bmi2")]
|
||||
unsafe fn needs_unsafe_block() {
|
||||
sse2();
|
||||
//~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
|
||||
|
@ -24,7 +24,7 @@ LL | Quux.avx_bmi2();
|
||||
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
|
||||
|
||||
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
|
||||
--> $DIR/safe-calls.rs:37:5
|
||||
--> $DIR/safe-calls.rs:38:5
|
||||
|
|
||||
LL | avx_bmi2();
|
||||
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
||||
@ -32,22 +32,13 @@ LL | avx_bmi2();
|
||||
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
|
||||
|
||||
error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
|
||||
--> $DIR/safe-calls.rs:39:5
|
||||
--> $DIR/safe-calls.rs:40:5
|
||||
|
|
||||
LL | Quux.avx_bmi2();
|
||||
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
||||
|
|
||||
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
|
||||
|
||||
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
|
||||
--> $DIR/safe-calls.rs:45:5
|
||||
|
|
||||
LL | sse2();
|
||||
| ^^^^^^ call to function with `#[target_feature]`
|
||||
|
|
||||
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
|
||||
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
|
||||
|
||||
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
|
||||
--> $DIR/safe-calls.rs:47:5
|
||||
|
|
||||
@ -65,16 +56,7 @@ LL | Quux.avx_bmi2();
|
||||
= help: in order for the call to be safe, the context requires the following additional target feature: bmi2
|
||||
|
||||
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
|
||||
--> $DIR/safe-calls.rs:56:5
|
||||
|
|
||||
LL | sse2();
|
||||
| ^^^^^^ call to function with `#[target_feature]`
|
||||
|
|
||||
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
|
||||
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
|
||||
|
||||
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
|
||||
--> $DIR/safe-calls.rs:60:15
|
||||
--> $DIR/safe-calls.rs:61:15
|
||||
|
|
||||
LL | const _: () = sse2();
|
||||
| ^^^^^^ call to function with `#[target_feature]`
|
||||
@ -83,7 +65,7 @@ LL | const _: () = sse2();
|
||||
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
|
||||
|
||||
error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block
|
||||
--> $DIR/safe-calls.rs:63:15
|
||||
--> $DIR/safe-calls.rs:64:15
|
||||
|
|
||||
LL | const _: () = sse2_and_fxsr();
|
||||
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
||||
@ -92,7 +74,7 @@ LL | const _: () = sse2_and_fxsr();
|
||||
= note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
|
||||
|
||||
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block
|
||||
--> $DIR/safe-calls.rs:70:5
|
||||
--> $DIR/safe-calls.rs:69:5
|
||||
|
|
||||
LL | sse2();
|
||||
| ^^^^^^ call to function with `#[target_feature]`
|
||||
@ -101,16 +83,16 @@ LL | sse2();
|
||||
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
|
||||
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
|
||||
note: an unsafe function restricts its caller, but its body is safe by default
|
||||
--> $DIR/safe-calls.rs:69:1
|
||||
--> $DIR/safe-calls.rs:68:1
|
||||
|
|
||||
LL | unsafe fn needs_unsafe_block() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: the lint level is defined here
|
||||
--> $DIR/safe-calls.rs:66:8
|
||||
--> $DIR/safe-calls.rs:67:8
|
||||
|
|
||||
LL | #[deny(unsafe_op_in_unsafe_fn)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0133`.
|
||||
|
10
tests/ui/target-feature/asm-implied-features-issue-128125.rs
Normal file
10
tests/ui/target-feature/asm-implied-features-issue-128125.rs
Normal file
@ -0,0 +1,10 @@
|
||||
//@ only-x86_64
|
||||
//@ build-pass
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[target_feature(enable = "avx2")]
|
||||
unsafe fn demo(v: std::arch::x86_64::__m256i) {
|
||||
std::arch::asm!("/* {v} */", v = in(ymm_reg) v);
|
||||
}
|
||||
|
||||
fn main() {}
|
24
tests/ui/target-feature/implied-features.rs
Normal file
24
tests/ui/target-feature/implied-features.rs
Normal file
@ -0,0 +1,24 @@
|
||||
//@ only-x86_64
|
||||
//@ build-pass
|
||||
#![feature(target_feature_11)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[target_feature(enable = "ssse3")]
|
||||
fn call_ssse3() {}
|
||||
|
||||
#[target_feature(enable = "avx")]
|
||||
fn call_avx() {}
|
||||
|
||||
#[target_feature(enable = "avx2")]
|
||||
fn test_avx2() {
|
||||
call_ssse3();
|
||||
call_avx();
|
||||
}
|
||||
|
||||
#[target_feature(enable = "fma")]
|
||||
fn test_fma() {
|
||||
call_ssse3();
|
||||
call_avx();
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user