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:
Matthias Krüger 2024-08-07 20:28:16 +02:00 committed by GitHub
commit 904f5795a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 594 additions and 485 deletions

View file

@ -75,7 +75,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
let function_features = codegen_fn_attrs let function_features = codegen_fn_attrs
.target_features .target_features
.iter() .iter()
.map(|features| features.as_str()) .map(|features| features.name.as_str())
.collect::<Vec<&str>>(); .collect::<Vec<&str>>();
if let Some(features) = check_tied_features( if let Some(features) = check_tied_features(

View file

@ -65,8 +65,8 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
let feature = backend_feature_name(s)?; let feature = backend_feature_name(s)?;
// Warn against use of GCC specific feature names on the CLI. // Warn against use of GCC specific feature names on the CLI.
if diagnostics && !supported_features.iter().any(|&(v, _)| v == feature) { if diagnostics && !supported_features.iter().any(|&(v, _, _)| v == feature) {
let rust_feature = supported_features.iter().find_map(|&(rust_feature, _)| { let rust_feature = supported_features.iter().find_map(|&(rust_feature, _, _)| {
let gcc_features = to_gcc_features(sess, rust_feature); let gcc_features = to_gcc_features(sess, rust_feature);
if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) { if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) {
Some(rust_feature) Some(rust_feature)

View file

@ -486,7 +486,7 @@ pub fn target_features(
sess.target sess.target
.supported_target_features() .supported_target_features()
.iter() .iter()
.filter_map(|&(feature, gate)| { .filter_map(|&(feature, gate, _)| {
if sess.is_nightly_build() || allow_unstable || gate.is_stable() { if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
Some(feature) Some(feature)
} else { } else {

View file

@ -496,7 +496,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
to_add.extend(tune_cpu_attr(cx)); to_add.extend(tune_cpu_attr(cx));
let function_features = 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( if let Some(f) = llvm_util::check_tied_features(
cx.tcx.sess, cx.tcx.sess,

View file

@ -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 }; 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 // Can't use query system here quite yet because this function is invoked before the query
// system/tcx is set up. // 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) target_machine_factory(sess, config::OptLevel::No, &features)(config)
.unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise()) .unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise())
} }

View file

@ -149,7 +149,7 @@ pub unsafe fn create_module<'ll>(
// Ensure the data-layout values hardcoded remain the defaults. // 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 { unsafe {
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
} }

View file

@ -269,7 +269,7 @@ impl CodegenBackend for LlvmCodegenBackend {
fn provide(&self, providers: &mut Providers) { fn provide(&self, providers: &mut Providers) {
providers.global_backend_features = 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) { fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {
@ -434,7 +434,7 @@ impl ModuleLlvm {
ModuleLlvm { ModuleLlvm {
llmod_raw, llmod_raw,
llcx, llcx,
tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)), tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)),
} }
} }
} }

View file

@ -8,6 +8,7 @@ use libc::c_int;
use rustc_codegen_ssa::base::wants_wasm_eh; use rustc_codegen_ssa::base::wants_wasm_eh;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::small_c_str::SmallCStr;
use rustc_data_structures::unord::UnordSet;
use rustc_fs_util::path_to_c_string; use rustc_fs_util::path_to_c_string;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_session::config::{PrintKind, PrintRequest}; 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 // In LLVM neon implicitly enables fp, but we manually enable
// neon when a feature only implicitly enables fp // neon when a feature only implicitly enables fp
("aarch64", "f32mm") => { ("aarch64", "fhm") => LLVMFeature::new("fp16fml"),
LLVMFeature::with_dependency("f32mm", TargetFeatureFoldStrength::EnableOnly("neon")) ("aarch64", "fp16") => LLVMFeature::new("fullfp16"),
}
("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"),
),
// In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called // 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. // `fast-unaligned-access`. In LLVM 19, it was split back out.
("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => { ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => {
@ -308,18 +277,15 @@ pub fn check_tied_features(
/// Used to generate cfg variables and apply features /// Used to generate cfg variables and apply features
/// Must express features in the way Rust understands them /// Must express features in the way Rust understands them
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> { 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 sess.target
.supported_target_features() .supported_target_features()
.iter() .iter()
.filter_map(|&(feature, gate)| { .filter(|(feature, _, _)| {
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
Some(feature)
} else {
None
}
})
.filter(|feature| {
// skip checking special features, as LLVM may not understands them // skip checking special features, as LLVM may not understands them
if RUSTC_SPECIAL_FEATURES.contains(feature) { if RUSTC_SPECIAL_FEATURES.contains(feature) {
return true; return true;
@ -333,6 +299,40 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
} }
true 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, _)| {
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
Some(feature)
} else {
None
}
})
.filter(|feature| {
RUSTC_SPECIAL_FEATURES.contains(feature) || features.contains(&Symbol::intern(feature))
})
.map(|feature| Symbol::intern(feature)) .map(|feature| Symbol::intern(feature))
.collect() .collect()
} }
@ -386,7 +386,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
.target .target
.supported_target_features() .supported_target_features()
.iter() .iter()
.map(|(feature, _gate)| { .map(|(feature, _gate, _implied)| {
// LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. // 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 llvm_feature = to_llvm_features(sess, *feature).llvm_feature_name;
let desc = 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) { pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) {
require_inited(); require_inited();
let tm = create_informational_target_machine(sess); let tm = create_informational_target_machine(sess, false);
match req.kind { match req.kind {
PrintKind::TargetCPUs => { PrintKind::TargetCPUs => {
// SAFETY generate a C compatible string from a byte slice to pass // 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`, /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar). /// `--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. // 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: // Typically we'll want more explicit settings to override the implicit ones, so:
// //
@ -548,14 +552,30 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
} }
// -Ctarget-features // -Ctarget-features
if !only_base_features {
let supported_features = sess.target.supported_target_features(); let supported_features = sess.target.supported_target_features();
let (llvm_major, _, _) = get_version(); let (llvm_major, _, _) = get_version();
let mut featsmap = FxHashMap::default(); let mut featsmap = FxHashMap::default();
let feats = sess
.opts // insert implied features
.cg let mut all_rust_features = vec![];
.target_feature for feature in sess.opts.cg.target_feature.split(',') {
.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| { .filter_map(|s| {
let enable_disable = match s.chars().next() { let enable_disable = match s.chars().next() {
None => return None, None => return None,
@ -571,11 +591,13 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
let feature = backend_feature_name(sess, s)?; let feature = backend_feature_name(sess, s)?;
// Warn against use of LLVM specific feature names and unstable features on the CLI. // Warn against use of LLVM specific feature names and unstable features on the CLI.
if diagnostics { if diagnostics {
let feature_state = supported_features.iter().find(|&&(v, _)| v == feature); let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature);
if feature_state.is_none() { if feature_state.is_none() {
let rust_feature = supported_features.iter().find_map(|&(rust_feature, _)| { let rust_feature =
supported_features.iter().find_map(|&(rust_feature, _, _)| {
let llvm_features = to_llvm_features(sess, rust_feature); let llvm_features = to_llvm_features(sess, rust_feature);
if llvm_features.contains(feature) && !llvm_features.contains(rust_feature) if llvm_features.contains(feature)
&& !llvm_features.contains(rust_feature)
{ {
Some(rust_feature) Some(rust_feature)
} else { } else {
@ -592,7 +614,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
}; };
sess.dcx().emit_warn(unknown_feature); sess.dcx().emit_warn(unknown_feature);
} else if feature_state } else if feature_state
.is_some_and(|(_name, feature_gate)| !feature_gate.is_stable()) .is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable())
{ {
// An unstable feature. Warn about using it. // An unstable feature. Warn about using it.
sess.dcx().emit_warn(UnstableCTargetFeature { feature }); sess.dcx().emit_warn(UnstableCTargetFeature { feature });
@ -622,21 +644,33 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
let llvm_feature = to_llvm_features(sess, feature); let llvm_feature = to_llvm_features(sess, feature);
Some( Some(
std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name)) std::iter::once(format!(
.chain(llvm_feature.dependency.into_iter().filter_map(move |feat| { "{}{}",
match (enable_disable, feat) { 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::Both(f))
| ('+', TargetFeatureFoldStrength::EnableOnly(f)) => { | ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
Some(format!("{enable_disable}{f}")) Some(format!("{enable_disable}{f}"))
} }
_ => None, _ => None,
} },
})), )),
) )
}) })
.flatten(); .flatten();
features.extend(feats); 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 // -Zfixed-x18
if sess.opts.unstable_opts.fixed_x18 { if sess.opts.unstable_opts.fixed_x18 {
if sess.target.arch != "aarch64" { if sess.target.arch != "aarch64" {
@ -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 features
} }

View file

@ -1,11 +1,12 @@
use rustc_ast::ast; use rustc_ast::ast;
use rustc_attr::InstructionSetAttr; use rustc_attr::InstructionSetAttr;
use rustc_data_structures::fx::FxIndexSet; 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_errors::Applicability;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
@ -18,7 +19,7 @@ pub fn from_target_feature(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
attr: &ast::Attribute, attr: &ast::Attribute,
supported_target_features: &UnordMap<String, Option<Symbol>>, 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 Some(list) = attr.meta_item_list() else { return };
let bad_item = |span| { let bad_item = |span| {
@ -30,6 +31,7 @@ pub fn from_target_feature(
.emit(); .emit();
}; };
let rust_features = tcx.features(); let rust_features = tcx.features();
let mut added_target_features = Vec::new();
for item in list { for item in list {
// Only `enable = ...` is accepted in the meta-item list. // Only `enable = ...` is accepted in the meta-item list.
if !item.has_name(sym::enable) { if !item.has_name(sym::enable) {
@ -44,7 +46,7 @@ pub fn from_target_feature(
}; };
// We allow comma separation to enable multiple features. // 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 Some(feature_gate) = supported_target_features.get(feature) else {
let msg = format!("the feature named `{feature}` is not valid for this target"); let msg = format!("the feature named `{feature}` is not valid for this target");
let mut err = tcx.dcx().struct_span_err(item.span(), msg); 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() { // Add explicit features
if target_features.iter().any(|f| f.as_str() == *feature) target_features.extend(
&& !target_features.iter().any(|f| f.as_str() == *requires) added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }),
{ );
target_features.push(Symbol::intern(requires));
// 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 /// 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(); let mut target_features = tcx.sess.unstable_target_features.clone();
if tcx.def_kind(did).has_codegen_attrs() { if tcx.def_kind(did).has_codegen_attrs() {
let attrs = tcx.codegen_fn_attrs(did); 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 { match attrs.instruction_set {
None => {} None => {}
Some(InstructionSetAttr::ArmA32) => { Some(InstructionSetAttr::ArmA32) => {
@ -158,10 +173,14 @@ pub(crate) fn provide(providers: &mut Providers) {
.target .target
.supported_target_features() .supported_target_features()
.iter() .iter()
.map(|&(a, b)| (a.to_string(), b.as_feature_name())) .map(|&(a, b, _)| (a.to_string(), b.as_feature_name()))
.collect() .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, asm_target_features,
..*providers ..*providers
} }

View file

@ -317,19 +317,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
&& attrs && attrs
.target_features .target_features
.iter() .iter()
.any(|feature| !self.tcx.sess.target_features.contains(feature)) .any(|feature| !self.tcx.sess.target_features.contains(&feature.name))
{ {
throw_ub_custom!( throw_ub_custom!(
fluent::const_eval_unavailable_target_features_for_fn, fluent::const_eval_unavailable_target_features_for_fn,
unavailable_feats = attrs unavailable_feats = attrs
.target_features .target_features
.iter() .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| { .fold(String::new(), |mut s, feature| {
if !s.is_empty() { if !s.is_empty() {
s.push_str(", "); s.push_str(", ");
} }
s.push_str(feature.as_str()); s.push_str(feature.name.as_str());
s s
}), }),
); );

View file

@ -28,7 +28,7 @@ pub struct CodegenFnAttrs {
pub link_ordinal: Option<u16>, pub link_ordinal: Option<u16>,
/// The `#[target_feature(enable = "...")]` attribute and the enabled /// The `#[target_feature(enable = "...")]` attribute and the enabled
/// features (only enabled features are supported right now). /// 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. /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
pub linkage: Option<Linkage>, pub linkage: Option<Linkage>,
/// The `#[linkage = "..."]` attribute on foreign items and the value we found. /// The `#[linkage = "..."]` attribute on foreign items and the value we found.
@ -51,6 +51,15 @@ pub struct CodegenFnAttrs {
pub patchable_function_entry: Option<PatchableFunctionEntry>, 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)] #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub struct PatchableFunctionEntry { pub struct PatchableFunctionEntry {
/// Nops to prepend to the function /// Nops to prepend to the function

View file

@ -2183,6 +2183,12 @@ rustc_queries! {
desc { "looking up supported target features" } 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 { query features_query(_: ()) -> &'tcx rustc_feature::Features {
feedable feedable
desc { "looking up enabled feature gates" } desc { "looking up enabled feature gates" }

View file

@ -5,6 +5,7 @@ use std::ops::Bound;
use rustc_errors::DiagArgValue; use rustc_errors::DiagArgValue;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability}; 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::mir::BorrowKind;
use rustc_middle::span_bug; use rustc_middle::span_bug;
use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::visit::Visitor;
@ -31,7 +32,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
safety_context: SafetyContext, safety_context: SafetyContext,
/// The `#[target_feature]` attributes of the body. Used for checking /// The `#[target_feature]` attributes of the body. Used for checking
/// calls to functions with `#[target_feature]` (RFC 2396). /// 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 /// When inside the LHS of an assignment to a field, this is the type
/// of the LHS and the span of the assignment expression. /// of the LHS and the span of the assignment expression.
assignment_info: Option<Ty<'tcx>>, 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 // is_like_wasm check in hir_analysis/src/collect.rs
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features; let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
if !self.tcx.sess.target.options.is_like_wasm if !self.tcx.sess.target.options.is_like_wasm
&& !callee_features && !callee_features.iter().all(|feature| {
.iter() self.body_target_features.iter().any(|f| f.name == feature.name)
.all(|feature| self.body_target_features.contains(feature)) })
{ {
let missing: Vec<_> = callee_features let missing: Vec<_> = callee_features
.iter() .iter()
.copied() .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(); .collect();
let build_enabled = self let build_enabled = self
.tcx .tcx

View file

@ -479,7 +479,9 @@ impl<'tcx> Inliner<'tcx> {
return Err("incompatible instruction set"); 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 // 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 // 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 // those calls depends on the target features of the surrounding function. By moving a

View file

@ -1,3 +1,4 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_span::symbol::{sym, Symbol}; use rustc_span::symbol::{sym, Symbol};
/// Features that control behaviour of rustc, rather than the codegen. /// Features that control behaviour of rustc, rather than the codegen.
@ -53,136 +54,154 @@ impl Stability {
// //
// Stabilizing a target feature requires t-lang approval. // 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 // tidy-alphabetical-start
("aclass", Unstable(sym::arm_target_feature)), ("aclass", Unstable(sym::arm_target_feature), &[]),
("aes", Unstable(sym::arm_target_feature)), ("aes", Unstable(sym::arm_target_feature), &["neon"]),
("crc", Unstable(sym::arm_target_feature)), ("crc", Unstable(sym::arm_target_feature), &[]),
("d32", Unstable(sym::arm_target_feature)), ("d32", Unstable(sym::arm_target_feature), &[]),
("dotprod", Unstable(sym::arm_target_feature)), ("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
("dsp", Unstable(sym::arm_target_feature)), ("dsp", Unstable(sym::arm_target_feature), &[]),
("fp-armv8", Unstable(sym::arm_target_feature)), ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]),
("i8mm", Unstable(sym::arm_target_feature)), ("i8mm", Unstable(sym::arm_target_feature), &["neon"]),
("mclass", Unstable(sym::arm_target_feature)), ("mclass", Unstable(sym::arm_target_feature), &[]),
("neon", Unstable(sym::arm_target_feature)), ("neon", Unstable(sym::arm_target_feature), &["vfp3"]),
("rclass", Unstable(sym::arm_target_feature)), ("rclass", Unstable(sym::arm_target_feature), &[]),
("sha2", 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 // This is needed for inline assembly, but shouldn't be stabilized as-is
// since it should be enabled per-function using #[instruction_set], not // since it should be enabled per-function using #[instruction_set], not
// #[target_feature]. // #[target_feature].
("thumb-mode", Unstable(sym::arm_target_feature)), ("thumb-mode", Unstable(sym::arm_target_feature), &[]),
("thumb2", Unstable(sym::arm_target_feature)), ("thumb2", Unstable(sym::arm_target_feature), &[]),
("trustzone", Unstable(sym::arm_target_feature)), ("trustzone", Unstable(sym::arm_target_feature), &[]),
("v5te", Unstable(sym::arm_target_feature)), ("v5te", Unstable(sym::arm_target_feature), &[]),
("v6", Unstable(sym::arm_target_feature)), ("v6", Unstable(sym::arm_target_feature), &["v5te"]),
("v6k", Unstable(sym::arm_target_feature)), ("v6k", Unstable(sym::arm_target_feature), &["v6"]),
("v6t2", Unstable(sym::arm_target_feature)), ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "thumb2"]),
("v7", Unstable(sym::arm_target_feature)), ("v7", Unstable(sym::arm_target_feature), &["v6t2"]),
("v8", Unstable(sym::arm_target_feature)), ("v8", Unstable(sym::arm_target_feature), &["v7"]),
("vfp2", Unstable(sym::arm_target_feature)), ("vfp2", Unstable(sym::arm_target_feature), &[]),
("vfp3", Unstable(sym::arm_target_feature)), ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]),
("vfp4", Unstable(sym::arm_target_feature)), ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]),
("virtualization", Unstable(sym::arm_target_feature)), ("virtualization", Unstable(sym::arm_target_feature), &[]),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
// FEAT_AES & FEAT_PMULL // FEAT_AES & FEAT_PMULL
("aes", Stable), ("aes", Stable, &["neon"]),
// FEAT_BF16 // FEAT_BF16
("bf16", Stable), ("bf16", Stable, &[]),
// FEAT_BTI // FEAT_BTI
("bti", Stable), ("bti", Stable, &[]),
// FEAT_CRC // FEAT_CRC
("crc", Stable), ("crc", Stable, &[]),
// FEAT_DIT // FEAT_DIT
("dit", Stable), ("dit", Stable, &[]),
// FEAT_DotProd // FEAT_DotProd
("dotprod", Stable), ("dotprod", Stable, &["neon"]),
// FEAT_DPB // FEAT_DPB
("dpb", Stable), ("dpb", Stable, &[]),
// FEAT_DPB2 // FEAT_DPB2
("dpb2", Stable), ("dpb2", Stable, &["dpb"]),
// FEAT_F32MM // FEAT_F32MM
("f32mm", Stable), ("f32mm", Stable, &["sve"]),
// FEAT_F64MM // FEAT_F64MM
("f64mm", Stable), ("f64mm", Stable, &["sve"]),
// FEAT_FCMA // FEAT_FCMA
("fcma", Stable), ("fcma", Stable, &["neon"]),
// FEAT_FHM // FEAT_FHM
("fhm", Stable), ("fhm", Stable, &["fp16"]),
// FEAT_FLAGM // FEAT_FLAGM
("flagm", Stable), ("flagm", Stable, &[]),
// FEAT_FP16 // FEAT_FP16
("fp16", Stable), // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
("fp16", Stable, &["neon"]),
// FEAT_FRINTTS // FEAT_FRINTTS
("frintts", Stable), ("frintts", Stable, &[]),
// FEAT_I8MM // FEAT_I8MM
("i8mm", Stable), ("i8mm", Stable, &[]),
// FEAT_JSCVT // FEAT_JSCVT
("jsconv", Stable), // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
("jsconv", Stable, &["neon"]),
// FEAT_LOR // FEAT_LOR
("lor", Stable), ("lor", Stable, &[]),
// FEAT_LSE // FEAT_LSE
("lse", Stable), ("lse", Stable, &[]),
// FEAT_MTE & FEAT_MTE2 // FEAT_MTE & FEAT_MTE2
("mte", Stable), ("mte", Stable, &[]),
// FEAT_AdvSimd & FEAT_FP // FEAT_AdvSimd & FEAT_FP
("neon", Stable), ("neon", Stable, &[]),
// FEAT_PAUTH (address authentication) // FEAT_PAUTH (address authentication)
("paca", Stable), ("paca", Stable, &[]),
// FEAT_PAUTH (generic authentication) // FEAT_PAUTH (generic authentication)
("pacg", Stable), ("pacg", Stable, &[]),
// FEAT_PAN // FEAT_PAN
("pan", Stable), ("pan", Stable, &[]),
// FEAT_PMUv3 // FEAT_PMUv3
("pmuv3", Stable), ("pmuv3", Stable, &[]),
// FEAT_RAND // FEAT_RAND
("rand", Stable), ("rand", Stable, &[]),
// FEAT_RAS & FEAT_RASv1p1 // FEAT_RAS & FEAT_RASv1p1
("ras", Stable), ("ras", Stable, &[]),
// FEAT_RCPC // FEAT_RCPC
("rcpc", Stable), ("rcpc", Stable, &[]),
// FEAT_RCPC2 // FEAT_RCPC2
("rcpc2", Stable), ("rcpc2", Stable, &["rcpc"]),
// FEAT_RDM // FEAT_RDM
("rdm", Stable), ("rdm", Stable, &["neon"]),
// FEAT_SB // FEAT_SB
("sb", Stable), ("sb", Stable, &[]),
// FEAT_SHA1 & FEAT_SHA256 // FEAT_SHA1 & FEAT_SHA256
("sha2", Stable), ("sha2", Stable, &["neon"]),
// FEAT_SHA512 & FEAT_SHA3 // FEAT_SHA512 & FEAT_SHA3
("sha3", Stable), ("sha3", Stable, &["sha2"]),
// FEAT_SM3 & FEAT_SM4 // FEAT_SM3 & FEAT_SM4
("sm4", Stable), ("sm4", Stable, &["neon"]),
// FEAT_SPE // FEAT_SPE
("spe", Stable), ("spe", Stable, &[]),
// FEAT_SSBS & FEAT_SSBS2 // FEAT_SSBS & FEAT_SSBS2
("ssbs", Stable), ("ssbs", Stable, &[]),
// FEAT_SVE // 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 // FEAT_SVE2
("sve2", Stable), ("sve2", Stable, &["sve"]),
// FEAT_SVE2_AES // FEAT_SVE2_AES
("sve2-aes", Stable), ("sve2-aes", Stable, &["sve2", "aes"]),
// FEAT_SVE2_BitPerm // FEAT_SVE2_BitPerm
("sve2-bitperm", Stable), ("sve2-bitperm", Stable, &["sve2"]),
// FEAT_SVE2_SHA3 // FEAT_SVE2_SHA3
("sve2-sha3", Stable), ("sve2-sha3", Stable, &["sve2", "sha3"]),
// FEAT_SVE2_SM4 // FEAT_SVE2_SM4
("sve2-sm4", Stable), ("sve2-sm4", Stable, &["sve2", "sm4"]),
// FEAT_TME // FEAT_TME
("tme", Stable), ("tme", Stable, &[]),
("v8.1a", Unstable(sym::aarch64_ver_target_feature)), (
("v8.2a", Unstable(sym::aarch64_ver_target_feature)), "v8.1a",
("v8.3a", Unstable(sym::aarch64_ver_target_feature)), Unstable(sym::aarch64_ver_target_feature),
("v8.4a", Unstable(sym::aarch64_ver_target_feature)), &["crc", "lse", "rdm", "pan", "lor", "vh"],
("v8.5a", Unstable(sym::aarch64_ver_target_feature)), ),
("v8.6a", Unstable(sym::aarch64_ver_target_feature)), ("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]),
("v8.7a", Unstable(sym::aarch64_ver_target_feature)), (
"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 // FEAT_VHE
("vh", Stable), ("vh", Stable, &[]),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
@ -190,224 +209,223 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
&["paca", "pacg"], // Together these represent `pauth` in LLVM &["paca", "pacg"], // Together these represent `pauth` in LLVM
]; ];
const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const X86_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
("adx", Stable), ("adx", Stable, &[]),
("aes", Stable), ("aes", Stable, &["sse2"]),
("amx-bf16", Unstable(sym::x86_amx_intrinsics)), ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
("amx-complex", Unstable(sym::x86_amx_intrinsics)), ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
("amx-fp16", Unstable(sym::x86_amx_intrinsics)), ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
("amx-int8", Unstable(sym::x86_amx_intrinsics)), ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]),
("amx-tile", Unstable(sym::x86_amx_intrinsics)), ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]),
("avx", Stable), ("avx", Stable, &["sse4.2"]),
("avx2", Stable), ("avx2", Stable, &["avx"]),
("avx512bf16", Unstable(sym::avx512_target_feature)), ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]),
("avx512bitalg", Unstable(sym::avx512_target_feature)), ("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]),
("avx512bw", Unstable(sym::avx512_target_feature)), ("avx512bw", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512cd", Unstable(sym::avx512_target_feature)), ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512dq", Unstable(sym::avx512_target_feature)), ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512f", Unstable(sym::avx512_target_feature)), ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]),
("avx512fp16", Unstable(sym::avx512_target_feature)), ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]),
("avx512ifma", Unstable(sym::avx512_target_feature)), ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512vbmi", Unstable(sym::avx512_target_feature)), ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]),
("avx512vbmi2", Unstable(sym::avx512_target_feature)), ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]),
("avx512vl", Unstable(sym::avx512_target_feature)), ("avx512vl", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512vnni", Unstable(sym::avx512_target_feature)), ("avx512vnni", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512vp2intersect", Unstable(sym::avx512_target_feature)), ("avx512vp2intersect", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avx512vpopcntdq", Unstable(sym::avx512_target_feature)), ("avx512vpopcntdq", Unstable(sym::avx512_target_feature), &["avx512f"]),
("avxifma", Unstable(sym::avx512_target_feature)), ("avxifma", Unstable(sym::avx512_target_feature), &["avx2"]),
("avxneconvert", Unstable(sym::avx512_target_feature)), ("avxneconvert", Unstable(sym::avx512_target_feature), &["avx2"]),
("avxvnni", Unstable(sym::avx512_target_feature)), ("avxvnni", Unstable(sym::avx512_target_feature), &["avx2"]),
("avxvnniint16", Unstable(sym::avx512_target_feature)), ("avxvnniint16", Unstable(sym::avx512_target_feature), &["avx2"]),
("avxvnniint8", Unstable(sym::avx512_target_feature)), ("avxvnniint8", Unstable(sym::avx512_target_feature), &["avx2"]),
("bmi1", Stable), ("bmi1", Stable, &[]),
("bmi2", Stable), ("bmi2", Stable, &[]),
("cmpxchg16b", Stable), ("cmpxchg16b", Stable, &[]),
("ermsb", Unstable(sym::ermsb_target_feature)), ("ermsb", Unstable(sym::ermsb_target_feature), &[]),
("f16c", Stable), ("f16c", Stable, &["avx"]),
("fma", Stable), ("fma", Stable, &["avx"]),
("fxsr", Stable), ("fxsr", Stable, &[]),
("gfni", Unstable(sym::avx512_target_feature)), ("gfni", Unstable(sym::avx512_target_feature), &["sse2"]),
("lahfsahf", Unstable(sym::lahfsahf_target_feature)), ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
("lzcnt", Stable), ("lzcnt", Stable, &[]),
("movbe", Stable), ("movbe", Stable, &[]),
("pclmulqdq", Stable), ("pclmulqdq", Stable, &[]),
("popcnt", Stable), ("popcnt", Stable, &[]),
("prfchw", Unstable(sym::prfchw_target_feature)), ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
("rdrand", Stable), ("rdrand", Stable, &[]),
("rdseed", Stable), ("rdseed", Stable, &[]),
("rtm", Unstable(sym::rtm_target_feature)), ("rtm", Unstable(sym::rtm_target_feature), &[]),
("sha", Stable), ("sha", Stable, &["sse2"]),
("sha512", Unstable(sym::sha512_sm_x86)), ("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
("sm3", Unstable(sym::sha512_sm_x86)), ("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
("sm4", Unstable(sym::sha512_sm_x86)), ("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
("sse", Stable), ("sse", Stable, &[]),
("sse2", Stable), ("sse2", Stable, &["sse"]),
("sse3", Stable), ("sse3", Stable, &["sse2"]),
("sse4.1", Stable), ("sse4.1", Stable, &["ssse3"]),
("sse4.2", Stable), ("sse4.2", Stable, &["sse4.1"]),
("sse4a", Unstable(sym::sse4a_target_feature)), ("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]),
("ssse3", Stable), ("ssse3", Stable, &["sse3"]),
("tbm", Unstable(sym::tbm_target_feature)), ("tbm", Unstable(sym::tbm_target_feature), &[]),
("vaes", Unstable(sym::avx512_target_feature)), ("vaes", Unstable(sym::avx512_target_feature), &["avx2", "aes"]),
("vpclmulqdq", Unstable(sym::avx512_target_feature)), ("vpclmulqdq", Unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
("xop", Unstable(sym::xop_target_feature)), ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
("xsave", Stable), ("xsave", Stable, &[]),
("xsavec", Stable), ("xsavec", Stable, &["xsave"]),
("xsaveopt", Stable), ("xsaveopt", Stable, &["xsave"]),
("xsaves", Stable), ("xsaves", Stable, &["xsave"]),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
("hvx", Unstable(sym::hexagon_target_feature)), ("hvx", Unstable(sym::hexagon_target_feature), &[]),
("hvx-length128b", Unstable(sym::hexagon_target_feature)), ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
const POWERPC_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const POWERPC_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
("altivec", Unstable(sym::powerpc_target_feature)), ("altivec", Unstable(sym::powerpc_target_feature), &[]),
("power10-vector", Unstable(sym::powerpc_target_feature)), ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]),
("power8-altivec", Unstable(sym::powerpc_target_feature)), ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]),
("power8-vector", Unstable(sym::powerpc_target_feature)), ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
("power9-altivec", Unstable(sym::powerpc_target_feature)), ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
("power9-vector", Unstable(sym::powerpc_target_feature)), ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
("vsx", Unstable(sym::powerpc_target_feature)), ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
const MIPS_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
("fp64", Unstable(sym::mips_target_feature)), ("fp64", Unstable(sym::mips_target_feature), &[]),
("msa", Unstable(sym::mips_target_feature)), ("msa", Unstable(sym::mips_target_feature), &[]),
("virt", Unstable(sym::mips_target_feature)), ("virt", Unstable(sym::mips_target_feature), &[]),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
const RISCV_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
("a", Stable), ("a", Stable, &[]),
("c", Stable), ("c", Stable, &[]),
("d", Unstable(sym::riscv_target_feature)), ("d", Unstable(sym::riscv_target_feature), &["f"]),
("e", Unstable(sym::riscv_target_feature)), ("e", Unstable(sym::riscv_target_feature), &[]),
("f", Unstable(sym::riscv_target_feature)), ("f", Unstable(sym::riscv_target_feature), &[]),
("m", Stable), ("m", Stable, &[]),
("relax", Unstable(sym::riscv_target_feature)), ("relax", Unstable(sym::riscv_target_feature), &[]),
("unaligned-scalar-mem", Unstable(sym::riscv_target_feature)), ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
("v", Unstable(sym::riscv_target_feature)), ("v", Unstable(sym::riscv_target_feature), &[]),
("zba", Stable), ("zba", Stable, &[]),
("zbb", Stable), ("zbb", Stable, &[]),
("zbc", Stable), ("zbc", Stable, &[]),
("zbkb", Stable), ("zbkb", Stable, &[]),
("zbkc", Stable), ("zbkc", Stable, &[]),
("zbkx", Stable), ("zbkx", Stable, &[]),
("zbs", Stable), ("zbs", Stable, &[]),
("zdinx", Unstable(sym::riscv_target_feature)), ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
("zfh", Unstable(sym::riscv_target_feature)), ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
("zfhmin", Unstable(sym::riscv_target_feature)), ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
("zfinx", Unstable(sym::riscv_target_feature)), ("zfinx", Unstable(sym::riscv_target_feature), &[]),
("zhinx", Unstable(sym::riscv_target_feature)), ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
("zhinxmin", Unstable(sym::riscv_target_feature)), ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
("zk", Stable), ("zk", Stable, &["zkn", "zkr", "zkt"]),
("zkn", Stable), ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
("zknd", Stable), ("zknd", Stable, &[]),
("zkne", Stable), ("zkne", Stable, &[]),
("zknh", Stable), ("zknh", Stable, &[]),
("zkr", Stable), ("zkr", Stable, &[]),
("zks", Stable), ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
("zksed", Stable), ("zksed", Stable, &[]),
("zksh", Stable), ("zksh", Stable, &[]),
("zkt", Stable), ("zkt", Stable, &[]),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const WASM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
("atomics", Unstable(sym::wasm_target_feature)), ("atomics", Unstable(sym::wasm_target_feature), &[]),
("bulk-memory", Stable), ("bulk-memory", Stable, &[]),
("exception-handling", Unstable(sym::wasm_target_feature)), ("exception-handling", Unstable(sym::wasm_target_feature), &[]),
("extended-const", Stable), ("extended-const", Stable, &[]),
("multivalue", Unstable(sym::wasm_target_feature)), ("multivalue", Unstable(sym::wasm_target_feature), &[]),
("mutable-globals", Stable), ("mutable-globals", Stable, &[]),
("nontrapping-fptoint", Stable), ("nontrapping-fptoint", Stable, &[]),
("reference-types", Unstable(sym::wasm_target_feature)), ("reference-types", Unstable(sym::wasm_target_feature), &[]),
("relaxed-simd", Stable), ("relaxed-simd", Stable, &["simd128"]),
("sign-ext", Stable), ("sign-ext", Stable, &[]),
("simd128", Stable), ("simd128", Stable, &[]),
// tidy-alphabetical-end // 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, ImpliedFeatures)] = &[
const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
("10e60", Unstable(sym::csky_target_feature)), ("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
("2e3", Unstable(sym::csky_target_feature)), ("2e3", Unstable(sym::csky_target_feature), &["e2"]),
("3e3r1", Unstable(sym::csky_target_feature)), ("3e3r1", Unstable(sym::csky_target_feature), &[]),
("3e3r2", Unstable(sym::csky_target_feature)), ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]),
("3e3r3", Unstable(sym::csky_target_feature)), ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]),
("3e7", Unstable(sym::csky_target_feature)), ("3e7", Unstable(sym::csky_target_feature), &["2e3"]),
("7e10", Unstable(sym::csky_target_feature)), ("7e10", Unstable(sym::csky_target_feature), &["3e7"]),
("cache", Unstable(sym::csky_target_feature)), ("cache", Unstable(sym::csky_target_feature), &[]),
("doloop", Unstable(sym::csky_target_feature)), ("doloop", Unstable(sym::csky_target_feature), &[]),
("dsp1e2", Unstable(sym::csky_target_feature)), ("dsp1e2", Unstable(sym::csky_target_feature), &[]),
("dspe60", Unstable(sym::csky_target_feature)), ("dspe60", Unstable(sym::csky_target_feature), &[]),
("e1", Unstable(sym::csky_target_feature)), ("e1", Unstable(sym::csky_target_feature), &["elrw"]),
("e2", Unstable(sym::csky_target_feature)), ("e2", Unstable(sym::csky_target_feature), &["e2"]),
("edsp", Unstable(sym::csky_target_feature)), ("edsp", Unstable(sym::csky_target_feature), &[]),
("elrw", Unstable(sym::csky_target_feature)), ("elrw", Unstable(sym::csky_target_feature), &[]),
("float1e2", Unstable(sym::csky_target_feature)), ("float1e2", Unstable(sym::csky_target_feature), &[]),
("float1e3", Unstable(sym::csky_target_feature)), ("float1e3", Unstable(sym::csky_target_feature), &[]),
("float3e4", Unstable(sym::csky_target_feature)), ("float3e4", Unstable(sym::csky_target_feature), &[]),
("float7e60", Unstable(sym::csky_target_feature)), ("float7e60", Unstable(sym::csky_target_feature), &[]),
("floate1", Unstable(sym::csky_target_feature)), ("floate1", Unstable(sym::csky_target_feature), &[]),
("hard-tp", Unstable(sym::csky_target_feature)), ("hard-tp", Unstable(sym::csky_target_feature), &[]),
("high-registers", Unstable(sym::csky_target_feature)), ("high-registers", Unstable(sym::csky_target_feature), &[]),
("hwdiv", Unstable(sym::csky_target_feature)), ("hwdiv", Unstable(sym::csky_target_feature), &[]),
("mp", Unstable(sym::csky_target_feature)), ("mp", Unstable(sym::csky_target_feature), &["2e3"]),
("mp1e2", Unstable(sym::csky_target_feature)), ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]),
("nvic", Unstable(sym::csky_target_feature)), ("nvic", Unstable(sym::csky_target_feature), &[]),
("trust", Unstable(sym::csky_target_feature)), ("trust", Unstable(sym::csky_target_feature), &[]),
("vdsp2e60f", Unstable(sym::csky_target_feature)), ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]),
("vdspv1", Unstable(sym::csky_target_feature)), ("vdspv1", Unstable(sym::csky_target_feature), &[]),
("vdspv2", Unstable(sym::csky_target_feature)), ("vdspv2", Unstable(sym::csky_target_feature), &[]),
// tidy-alphabetical-end // tidy-alphabetical-end
//fpu //fpu
// tidy-alphabetical-start // tidy-alphabetical-start
("fdivdu", Unstable(sym::csky_target_feature)), ("fdivdu", Unstable(sym::csky_target_feature), &[]),
("fpuv2_df", Unstable(sym::csky_target_feature)), ("fpuv2_df", Unstable(sym::csky_target_feature), &[]),
("fpuv2_sf", Unstable(sym::csky_target_feature)), ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]),
("fpuv3_df", Unstable(sym::csky_target_feature)), ("fpuv3_df", Unstable(sym::csky_target_feature), &[]),
("fpuv3_hf", Unstable(sym::csky_target_feature)), ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]),
("fpuv3_hi", Unstable(sym::csky_target_feature)), ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]),
("fpuv3_sf", Unstable(sym::csky_target_feature)), ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]),
("hard-float", Unstable(sym::csky_target_feature)), ("hard-float", Unstable(sym::csky_target_feature), &[]),
("hard-float-abi", Unstable(sym::csky_target_feature)), ("hard-float-abi", Unstable(sym::csky_target_feature), &[]),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
("d", Unstable(sym::loongarch_target_feature)), ("d", Unstable(sym::loongarch_target_feature), &["f"]),
("f", Unstable(sym::loongarch_target_feature)), ("f", Unstable(sym::loongarch_target_feature), &[]),
("frecipe", Unstable(sym::loongarch_target_feature)), ("frecipe", Unstable(sym::loongarch_target_feature), &[]),
("lasx", Unstable(sym::loongarch_target_feature)), ("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]),
("lbt", Unstable(sym::loongarch_target_feature)), ("lbt", Unstable(sym::loongarch_target_feature), &[]),
("lsx", Unstable(sym::loongarch_target_feature)), ("lsx", Unstable(sym::loongarch_target_feature), &["d"]),
("lvz", Unstable(sym::loongarch_target_feature)), ("lvz", Unstable(sym::loongarch_target_feature), &[]),
("relax", Unstable(sym::loongarch_target_feature)), ("relax", Unstable(sym::loongarch_target_feature), &[]),
("ual", Unstable(sym::loongarch_target_feature)), ("ual", Unstable(sym::loongarch_target_feature), &[]),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[ const IBMZ_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
("backchain", Unstable(sym::s390x_target_feature)), ("backchain", Unstable(sym::s390x_target_feature), &[]),
("vector", Unstable(sym::s390x_target_feature)), ("vector", Unstable(sym::s390x_target_feature), &[]),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
@ -430,10 +448,13 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> {
.chain(LOONGARCH_ALLOWED_FEATURES) .chain(LOONGARCH_ALLOWED_FEATURES)
.chain(IBMZ_ALLOWED_FEATURES) .chain(IBMZ_ALLOWED_FEATURES)
.cloned() .cloned()
.map(|(f, s, _)| (f, s))
} }
impl super::spec::Target { 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 { match &*self.arch {
"arm" => ARM_ALLOWED_FEATURES, "arm" => ARM_ALLOWED_FEATURES,
"aarch64" | "arm64ec" => AARCH64_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 pub fn implied_target_features(
/// implicitly enables the second one. &self,
pub fn implicit_target_features(&self) -> &'static [(&'static str, &'static str)] { base_features: impl Iterator<Item = Symbol>,
match &*self.arch { ) -> FxHashSet<Symbol> {
"wasm32" | "wasm64" => WASM_IMPLICIT_FEATURES, 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
}
}

View file

@ -12,4 +12,4 @@ pub unsafe fn crc32sse(v: u8) -> u32 {
_mm_crc32_u8(out, v) _mm_crc32_u8(out, v)
} }
// CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32"}} // CHECK: attributes #0 {{.*"target-features"=".*\+sse4.2,\+crc32.*"}}

View file

@ -1,7 +1,7 @@
//@ revisions: COMPAT INCOMPAT //@ revisions: COMPAT INCOMPAT
//@ needs-llvm-components: x86 //@ needs-llvm-components: x86
//@ compile-flags: --target=x86_64-unknown-linux-gnu -Copt-level=3 //@ 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 //@ [INCOMPAT] compile-flags: -Ctarget-feature=-avx2,-avx
// See also tests/assembly/target-feature-multiple.rs // See also tests/assembly/target-feature-multiple.rs
@ -39,8 +39,8 @@ pub unsafe fn banana() -> u32 {
} }
// CHECK: attributes [[APPLEATTRS]] // CHECK: attributes [[APPLEATTRS]]
// COMPAT-SAME: "target-features"="+avx2,+avx,+avx" // COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx" // INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
// CHECK: attributes [[BANANAATTRS]] // CHECK: attributes [[BANANAATTRS]]
// COMPAT-SAME: "target-features"="+avx2,+avx" // COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
// INCOMPAT-SAME: "target-features"="-avx2,-avx" // INCOMPAT-SAME: "target-features"="-avx2,-avx"

View file

@ -8,7 +8,7 @@
// is LLVM-14 we can remove the optional regex matching for this feature. // 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] 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] compile-flags: -C target-feature=-sve -Copt-level=0
// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(-sve,?)|(\+neon,?))*}}" } // DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(-sve,?)|(\+neon,?))*}}" }

View file

@ -34,6 +34,7 @@ fn foo() {
#[target_feature(enable = "sse2")] #[target_feature(enable = "sse2")]
fn bar() { fn bar() {
sse2();
avx_bmi2(); avx_bmi2();
//~^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe //~^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
Quux.avx_bmi2(); Quux.avx_bmi2();
@ -43,7 +44,6 @@ fn bar() {
#[target_feature(enable = "avx")] #[target_feature(enable = "avx")]
fn baz() { fn baz() {
sse2(); sse2();
//~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe
avx_bmi2(); avx_bmi2();
//~^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe //~^ ERROR call to function `avx_bmi2` with `#[target_feature]` is unsafe
Quux.avx_bmi2(); Quux.avx_bmi2();
@ -54,7 +54,8 @@ fn baz() {
#[target_feature(enable = "bmi2")] #[target_feature(enable = "bmi2")]
fn qux() { fn qux() {
sse2(); sse2();
//~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe avx_bmi2();
Quux.avx_bmi2();
} }
const _: () = sse2(); const _: () = sse2();
@ -64,8 +65,6 @@ const _: () = sse2_and_fxsr();
//~^ ERROR call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe //~^ ERROR call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe
#[deny(unsafe_op_in_unsafe_fn)] #[deny(unsafe_op_in_unsafe_fn)]
#[target_feature(enable = "avx")]
#[target_feature(enable = "bmi2")]
unsafe fn needs_unsafe_block() { unsafe fn needs_unsafe_block() {
sse2(); sse2();
//~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe //~^ ERROR call to function `sse2` with `#[target_feature]` is unsafe

View file

@ -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 = 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 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(); LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]` | ^^^^^^^^^^ 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 = 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 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(); LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | ^^^^^^^^^^^^^^^ 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 = 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 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:47:5 --> $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 = 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 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:56:5 --> $DIR/safe-calls.rs:61:15
|
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
| |
LL | const _: () = sse2(); LL | const _: () = sse2();
| ^^^^^^ call to function with `#[target_feature]` | ^^^^^^ 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]` = 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 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(); LL | const _: () = sse2_and_fxsr();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | ^^^^^^^^^^^^^^^ 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]` = 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 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(); LL | sse2();
| ^^^^^^ call to function with `#[target_feature]` | ^^^^^^ 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 = 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: 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 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() { LL | unsafe fn needs_unsafe_block() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here 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)] 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`. For more information about this error, try `rustc --explain E0133`.

View 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() {}

View 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() {}