From 74653b61a67ae7db9f77ea1e09e65e40686c9058 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 26 Jul 2024 00:05:20 -0400 Subject: [PATCH 01/14] Add implied target features to target_feature attribute --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 16 ----- .../rustc_codegen_ssa/src/target_features.rs | 40 ++++++++++--- compiler/rustc_middle/src/query/mod.rs | 6 ++ compiler/rustc_target/src/target_features.rs | 58 +++++++++++++++++-- tests/ui/target-feature/implied-features.rs | 24 ++++++++ 5 files changed, 113 insertions(+), 31 deletions(-) create mode 100644 tests/ui/target-feature/implied-features.rs diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index af8a9be1ccbfd..dc21b92a95f76 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -646,22 +646,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec, 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, diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 127244a34f8f0..1bf842b53a3c5 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,7 +1,7 @@ use rustc_ast::ast; use rustc_attr::InstructionSetAttr; -use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::unord::UnordMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +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}; @@ -30,6 +30,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 +45,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 +99,12 @@ 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 implied features + for feature in added_target_features.iter() { + target_features + .extend(tcx.implied_target_features(*feature).clone().into_sorted_stable_ord()); } + target_features.extend(added_target_features) } /// Computes the set of target features used in a function for the purposes of @@ -162,6 +162,28 @@ pub(crate) fn provide(providers: &mut Providers) { .collect() } }, + implied_target_features: |tcx, feature| { + let implied_features = tcx + .sess + .target + .implied_target_features() + .iter() + .map(|(f, i)| (Symbol::intern(f), i)) + .collect::>(); + + // 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 = UnordSet::new(); + let mut new_features = vec![feature]; + 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 + }, asm_target_features, ..*providers } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c22c2e985abba..b6a2943265034 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2183,6 +2183,12 @@ rustc_queries! { desc { "looking up supported target features" } } + query implied_target_features(feature: Symbol) -> &'tcx UnordSet { + arena_cache + eval_always + desc { "looking up implied target features" } + } + query features_query(_: ()) -> &'tcx rustc_feature::Features { feedable desc { "looking up enabled feature gates" } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 4e2617c467949..5b79495831a34 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -339,8 +339,6 @@ const WASM_ALLOWED_FEATURES: &[(&str, Stability)] = &[ // tidy-alphabetical-end ]; -const WASM_IMPLICIT_FEATURES: &[(&str, &str)] = &[("relaxed-simd", "simd128")]; - const BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))]; const CSKY_ALLOWED_FEATURES: &[(&str, Stability)] = &[ @@ -411,6 +409,54 @@ const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[ // tidy-alphabetical-end ]; +const X86_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ + // tidy-alphabetical-start + ("aes", &["sse2"]), + ("avx", &["sse4.2"]), + ("avx2", &["avx"]), + ("f16c", &["avx"]), + ("fma", &["avx"]), + ("pclmulqdq", &["sse2"]), + ("sha", &["sse2"]), + ("sse2", &["sse"]), + ("sse3", &["sse2"]), + ("sse4.1", &["ssse3"]), + ("sse4.2", &["sse4.1"]), + ("ssse3", &["sse3"]), + // tidy-alphabetical-end +]; + +const AARCH64_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ + // tidy-alphabetical-start + ("aes", &["neon"]), + ("f32mm", &["sve"]), + ("f64mm", &["sve"]), + ("fcma", &["neon"]), + ("fhm", &["fp16"]), + ("fp16", &["neon"]), + ("jsconv", &["neon"]), + ("rcpc2", &["rcpc"]), + ("sha2", &["neon"]), + ("sha3", &["sha2"]), + ("sm4", &["neon"]), + ("sve", &["fp16"]), + ("sve2", &["sve"]), + ("sve2-aes", &["sve2", "aes"]), + ("sve2-bitperm", &["sve2"]), + ("sve2-sha3", &["sve2", "sha3"]), + ("sve2-sm4", &["sve2", "sm4"]), + // tidy-alphabetical-end +]; + +const RISCV_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ + // tidy-alphabetical-start + ("zb", &["zba", "zbc", "zbs"]), + ("zk", &["zkn", "zkr", "zks", "zkt", "zbkb", "zbkc", "zkbx"]), + ("zkn", &["zknd", "zkne", "zknh", "zbkb", "zbkc", "zkbx"]), + ("zks", &["zksed", "zksh", "zbkb", "zbkc", "zkbx"]), + // tidy-alphabetical-end +]; + /// When rustdoc is running, provide a list of all known features so that all their respective /// primitives may be documented. /// @@ -458,11 +504,11 @@ 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)] { + pub fn implied_target_features(&self) -> &'static [(&'static str, &'static [&'static str])] { match &*self.arch { - "wasm32" | "wasm64" => WASM_IMPLICIT_FEATURES, + "aarch4" => AARCH64_IMPLIED_FEATURES, + "riscv32" | "riscv64" => RISCV_IMPLIED_FEATURES, + "x86" | "x86_64" => X86_IMPLIED_FEATURES, _ => &[], } } diff --git a/tests/ui/target-feature/implied-features.rs b/tests/ui/target-feature/implied-features.rs new file mode 100644 index 0000000000000..c6d9ba78c21e6 --- /dev/null +++ b/tests/ui/target-feature/implied-features.rs @@ -0,0 +1,24 @@ +//@ only-x86_64 +//@ run-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() {} From 22c59529441da1cca8eb2cc50d4162e3adf95355 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 26 Jul 2024 10:04:27 -0400 Subject: [PATCH 02/14] Add test to ensure implied target features work with asm, and fix failing tests --- .../rustc_codegen_ssa/src/target_features.rs | 12 ++-- .../const-eval/const_fn_target_feature.stderr | 2 +- .../rfc-2396-target_feature-11/safe-calls.rs | 7 +-- .../safe-calls.stderr | 60 +++++++------------ .../asm-implied-features-issue-128125.rs | 10 ++++ tests/ui/target-feature/implied-features.rs | 2 +- 6 files changed, 44 insertions(+), 49 deletions(-) create mode 100644 tests/ui/target-feature/asm-implied-features-issue-128125.rs diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 1bf842b53a3c5..24b2c9c51c6e1 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,7 +1,7 @@ use rustc_ast::ast; use rustc_attr::InstructionSetAttr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_data_structures::unord::{UnordMap, UnordSet}; +use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; @@ -99,12 +99,14 @@ pub fn from_target_feature( })); } - // Add implied features + // Add both explicit and implied target features, using a set to deduplicate + let mut target_features_set = UnordSet::new(); for feature in added_target_features.iter() { - target_features - .extend(tcx.implied_target_features(*feature).clone().into_sorted_stable_ord()); + target_features_set + .extend_unord(tcx.implied_target_features(*feature).clone().into_items()); } - target_features.extend(added_target_features) + target_features_set.extend(added_target_features); + target_features.extend(target_features_set.into_sorted_stable_ord()) } /// Computes the set of target features used in a function for the purposes of diff --git a/tests/ui/consts/const-eval/const_fn_target_feature.stderr b/tests/ui/consts/const-eval/const_fn_target_feature.stderr index d3a00b57ebb50..ad40d733546af 100644 --- a/tests/ui/consts/const-eval/const_fn_target_feature.stderr +++ b/tests/ui/consts/const-eval/const_fn_target_feature.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const_fn_target_feature.rs:11:24 | LL | const B: () = unsafe { avx2_fn() }; - | ^^^^^^^^^ calling a function that requires unavailable target features: avx2 + | ^^^^^^^^^ calling a function that requires unavailable target features: avx, avx2, sse4.1, sse4.2 error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs index de002ef71d7d3..fec4e75290fc8 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs @@ -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 diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr index 537819ab8595c..c2227f8e84783 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr @@ -4,8 +4,8 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req 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]` + = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2 + = note: the sse 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 `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block --> $DIR/safe-calls.rs:29:5 @@ -13,7 +13,8 @@ error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and LL | 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 + = help: in order for the call to be safe, the context requires the following additional target features: avx, sse, sse2, sse3, sse4.1, sse4.2, ssse3, and bmi2 + = note: the sse 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 `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block --> $DIR/safe-calls.rs:31:5 @@ -21,32 +22,24 @@ error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsa 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 + = help: in order for the call to be safe, the context requires the following additional target features: avx, sse, sse2, sse3, sse4.1, sse4.2, ssse3, and bmi2 + = note: the sse 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 `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]` | - = 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, sse3, sse4.1, sse4.2, ssse3, 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]` + = help: in order for the call to be safe, the context requires the following additional target features: avx, sse3, sse4.1, sse4.2, ssse3, and bmi2 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,52 +58,43 @@ 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]` | - = 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]` + = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2 + = note: the sse 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_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]` | - = help: in order for the call to be safe, the context requires the following additional target features: 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]` + = help: in order for the call to be safe, the context requires the following additional target features: sse, sse2, and fxsr + = note: the fxsr, sse, 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]` | = note: for more information, see issue #71668 - = 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]` + = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2 + = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them 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`. diff --git a/tests/ui/target-feature/asm-implied-features-issue-128125.rs b/tests/ui/target-feature/asm-implied-features-issue-128125.rs new file mode 100644 index 0000000000000..2b4f1d7df8563 --- /dev/null +++ b/tests/ui/target-feature/asm-implied-features-issue-128125.rs @@ -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() {} diff --git a/tests/ui/target-feature/implied-features.rs b/tests/ui/target-feature/implied-features.rs index c6d9ba78c21e6..4fdd843e6c289 100644 --- a/tests/ui/target-feature/implied-features.rs +++ b/tests/ui/target-feature/implied-features.rs @@ -1,5 +1,5 @@ //@ only-x86_64 -//@ run-pass +//@ build-pass #![feature(target_feature_11)] #![allow(dead_code)] From 520a5a535f4a1432d7f9742171a11d21f518f652 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 26 Jul 2024 11:27:21 -0400 Subject: [PATCH 03/14] Fix codegen tests --- tests/codegen/sse42-implies-crc32.rs | 2 +- tests/codegen/target-feature-overrides.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/codegen/sse42-implies-crc32.rs b/tests/codegen/sse42-implies-crc32.rs index 94fcd77bc8842..8a9c496a3a541 100644 --- a/tests/codegen/sse42-implies-crc32.rs +++ b/tests/codegen/sse42-implies-crc32.rs @@ -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.*"}} diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs index 1e2c364dbbc9a..87783706d9535 100644 --- a/tests/codegen/target-feature-overrides.rs +++ b/tests/codegen/target-feature-overrides.rs @@ -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,+avx,+sse4.2,+sse4.1,+ssse3,+sse3 //@ [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"="+avx2,+avx,{{.*}}" +// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}" // CHECK: attributes [[BANANAATTRS]] -// COMPAT-SAME: "target-features"="+avx2,+avx" +// COMPAT-SAME: "target-features"="+avx2,+avx,{{.*}}" // INCOMPAT-SAME: "target-features"="-avx2,-avx" From c866e1f812b7436abce2b03ec56d62c77d6684a2 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 29 Jul 2024 00:09:47 -0400 Subject: [PATCH 04/14] Add missing features --- compiler/rustc_target/src/target_features.rs | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 5b79495831a34..64f966d7a305e 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -414,8 +414,22 @@ const X86_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ ("aes", &["sse2"]), ("avx", &["sse4.2"]), ("avx2", &["avx"]), + ("avx512bf16", &["avx512bw"]), + ("avx512bitalg", &["avx512bw"]), + ("avx512bw", &["avx512f"]), + ("avx512cd", &["avx512f"]), + ("avx512dq", &["avx512f"]), + ("avx512f", &["avx2"]), + ("avx512fp16", &["avx512bw", "avx512vl", "avx512dq"]), + ("avx512vbmi", &["avx512bw"]), + ("avx512vbmi2", &["avx512bw"]), + ("avx512vl", &["avx512f"]), + ("avx512vnni", &["avx512f"]), + ("avx512vp2intersect", &["avx512f"]), + ("avx512vpopcntdq", &["avx512f"]), ("f16c", &["avx"]), ("fma", &["avx"]), + ("gfni", &["sse2"]), ("pclmulqdq", &["sse2"]), ("sha", &["sse2"]), ("sse2", &["sse"]), @@ -423,6 +437,11 @@ const X86_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ ("sse4.1", &["ssse3"]), ("sse4.2", &["sse4.1"]), ("ssse3", &["sse3"]), + ("vaes", &["avx", "aes"]), + ("vpclmulqdq", &["avx", "pclmulqdq"]), + ("xsavec", &["xsave"]), + ("xsaveopt", &["xsave"]), + ("xsaves", &["xsave"]), // tidy-alphabetical-end ]; @@ -457,6 +476,12 @@ const RISCV_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ // tidy-alphabetical-end ]; +const WASM_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ + // tidy-alphabetical-start + ("relaxed-simd", &["simd128"]), + // tidy-alphabetical-end +]; + /// When rustdoc is running, provide a list of all known features so that all their respective /// primitives may be documented. /// @@ -509,6 +534,7 @@ impl super::spec::Target { "aarch4" => AARCH64_IMPLIED_FEATURES, "riscv32" | "riscv64" => RISCV_IMPLIED_FEATURES, "x86" | "x86_64" => X86_IMPLIED_FEATURES, + "wasm32" | "wasm64" => WASM_IMPLIED_FEATURES, _ => &[], } } From 34f29a24bbd471cf60f0517457ae024f90ec2263 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Tue, 30 Jul 2024 23:58:51 -0400 Subject: [PATCH 05/14] Add +sse4.2 due to #128426 --- src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs | 2 +- src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs | 2 +- src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs | 2 +- src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs index 7363c75361779..13ebe56146381 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs @@ -7,7 +7,7 @@ //@ignore-target-s390x //@ignore-target-thumbv7em //@ignore-target-wasm32 -//@compile-flags: -C target-feature=+aes,+vaes,+avx512f +//@compile-flags: -C target-feature=+aes,+vaes,+avx512f,+sse4.2 #![feature(avx512_target_feature, stdarch_x86_avx512)] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs index 728f57d48f17e..18693a2a97d11 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs @@ -7,7 +7,7 @@ //@ignore-target-s390x //@ignore-target-thumbv7em //@ignore-target-wasm32 -//@compile-flags: -C target-feature=+avx +//@compile-flags: -C target-feature=+avx,+sse4.2 #[cfg(target_arch = "x86")] use std::arch::x86::*; diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs index 80d125bb85650..f42ff6dfb51b2 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs @@ -7,7 +7,7 @@ //@ignore-target-s390x //@ignore-target-thumbv7em //@ignore-target-wasm32 -//@compile-flags: -C target-feature=+avx2 +//@compile-flags: -C target-feature=+avx2,+sse4.2 #[cfg(target_arch = "x86")] use std::arch::x86::*; diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs index 66bfcb20f1c99..7d25854ccc075 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs @@ -7,7 +7,7 @@ //@ignore-target-s390x //@ignore-target-thumbv7em //@ignore-target-wasm32 -//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq +//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq,+sse4.2 #![feature(avx512_target_feature)] #![feature(stdarch_x86_avx512)] From 3c48f6548bce89b459952f8d7ca077cfa99159aa Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Wed, 31 Jul 2024 01:50:02 -0400 Subject: [PATCH 06/14] Bless tests --- .../fail/function_calls/simd_feature_flag_difference.stderr | 4 ++-- src/tools/miri/tests/fail/function_calls/target_feature.rs | 2 +- .../miri/tests/fail/function_calls/target_feature.stderr | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr index 2544421c7e8c7..8ebd5d2726ffd 100644 --- a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr +++ b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function that requires unavailable target features: avx +error: Undefined Behavior: calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3 --> $DIR/simd_feature_flag_difference.rs:LL:CC | LL | unsafe { foo(0.0, x) } - | ^^^^^^^^^^^ calling a function that requires unavailable target features: avx + | ^^^^^^^^^^^ calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.rs b/src/tools/miri/tests/fail/function_calls/target_feature.rs index 84e01eb4803fe..713d7c16f4c25 100644 --- a/src/tools/miri/tests/fail/function_calls/target_feature.rs +++ b/src/tools/miri/tests/fail/function_calls/target_feature.rs @@ -4,7 +4,7 @@ fn main() { assert!(!is_x86_feature_detected!("ssse3")); unsafe { - ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: ssse3 + ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: sse3, ssse3 } } diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.stderr b/src/tools/miri/tests/fail/function_calls/target_feature.stderr index 4d3cf6e9d3bc0..74a862c7b681c 100644 --- a/src/tools/miri/tests/fail/function_calls/target_feature.stderr +++ b/src/tools/miri/tests/fail/function_calls/target_feature.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function that requires unavailable target features: ssse3 +error: Undefined Behavior: calling a function that requires unavailable target features: sse3, ssse3 --> $DIR/target_feature.rs:LL:CC | LL | ssse3_fn(); - | ^^^^^^^^^^ calling a function that requires unavailable target features: ssse3 + | ^^^^^^^^^^ calling a function that requires unavailable target features: sse3, ssse3 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From fbd618d4aa8f3a6c998b81aa83a543d4c09d9bb3 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 2 Aug 2024 00:20:49 -0400 Subject: [PATCH 07/14] Refactor and fill out target feature lists --- compiler/rustc_codegen_gcc/src/gcc_util.rs | 4 +- compiler/rustc_codegen_gcc/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 28 +- .../rustc_codegen_ssa/src/target_features.rs | 6 +- compiler/rustc_target/src/target_features.rs | 613 ++++++++---------- 5 files changed, 293 insertions(+), 360 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 8bb90efe6fb7c..5308ccdb61469 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -65,8 +65,8 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec Vec { 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 { @@ -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 = @@ -571,17 +571,19 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec Vec>(); // implied target features have their own implied target features, so we traverse the diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 64f966d7a305e..f408db1dcbad2 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -53,136 +53,146 @@ 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), + ("fp16", Stable, &[]), // FEAT_FRINTTS - ("frintts", Stable), + ("frintts", Stable, &[]), // FEAT_I8MM - ("i8mm", Stable), + ("i8mm", Stable, &[]), // FEAT_JSCVT - ("jsconv", Stable), + ("jsconv", Stable, &[]), // 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), + ("sve", Stable, &[]), // 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,295 +200,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", "bzkc", "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 BPF_ALLOWED_FEATURES: &[(&str, Stability)] = &[("alu32", Unstable(sym::bpf_target_feature))]; +const BPF_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = + &[("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)), - // tidy-alphabetical-end -]; - -const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability)] = &[ - // 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)), - // tidy-alphabetical-end -]; - -const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[ - // tidy-alphabetical-start - ("backchain", Unstable(sym::s390x_target_feature)), - ("vector", Unstable(sym::s390x_target_feature)), - // tidy-alphabetical-end -]; - -const X86_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ - // tidy-alphabetical-start - ("aes", &["sse2"]), - ("avx", &["sse4.2"]), - ("avx2", &["avx"]), - ("avx512bf16", &["avx512bw"]), - ("avx512bitalg", &["avx512bw"]), - ("avx512bw", &["avx512f"]), - ("avx512cd", &["avx512f"]), - ("avx512dq", &["avx512f"]), - ("avx512f", &["avx2"]), - ("avx512fp16", &["avx512bw", "avx512vl", "avx512dq"]), - ("avx512vbmi", &["avx512bw"]), - ("avx512vbmi2", &["avx512bw"]), - ("avx512vl", &["avx512f"]), - ("avx512vnni", &["avx512f"]), - ("avx512vp2intersect", &["avx512f"]), - ("avx512vpopcntdq", &["avx512f"]), - ("f16c", &["avx"]), - ("fma", &["avx"]), - ("gfni", &["sse2"]), - ("pclmulqdq", &["sse2"]), - ("sha", &["sse2"]), - ("sse2", &["sse"]), - ("sse3", &["sse2"]), - ("sse4.1", &["ssse3"]), - ("sse4.2", &["sse4.1"]), - ("ssse3", &["sse3"]), - ("vaes", &["avx", "aes"]), - ("vpclmulqdq", &["avx", "pclmulqdq"]), - ("xsavec", &["xsave"]), - ("xsaveopt", &["xsave"]), - ("xsaves", &["xsave"]), - // tidy-alphabetical-end -]; - -const AARCH64_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ - // tidy-alphabetical-start - ("aes", &["neon"]), - ("f32mm", &["sve"]), - ("f64mm", &["sve"]), - ("fcma", &["neon"]), - ("fhm", &["fp16"]), - ("fp16", &["neon"]), - ("jsconv", &["neon"]), - ("rcpc2", &["rcpc"]), - ("sha2", &["neon"]), - ("sha3", &["sha2"]), - ("sm4", &["neon"]), - ("sve", &["fp16"]), - ("sve2", &["sve"]), - ("sve2-aes", &["sve2", "aes"]), - ("sve2-bitperm", &["sve2"]), - ("sve2-sha3", &["sve2", "sha3"]), - ("sve2-sm4", &["sve2", "sm4"]), + ("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 RISCV_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ +const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("zb", &["zba", "zbc", "zbs"]), - ("zk", &["zkn", "zkr", "zks", "zkt", "zbkb", "zbkc", "zkbx"]), - ("zkn", &["zknd", "zkne", "zknh", "zbkb", "zbkc", "zkbx"]), - ("zks", &["zksed", "zksh", "zbkb", "zbkc", "zkbx"]), + ("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 WASM_IMPLIED_FEATURES: &[(&str, &[&str])] = &[ +const IBMZ_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("relaxed-simd", &["simd128"]), + ("backchain", Unstable(sym::s390x_target_feature), &[]), + ("vector", Unstable(sym::s390x_target_feature), &[]), // tidy-alphabetical-end ]; @@ -501,10 +439,13 @@ pub fn all_known_features() -> impl Iterator { .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, @@ -528,14 +469,4 @@ impl super::spec::Target { _ => &[], } } - - pub fn implied_target_features(&self) -> &'static [(&'static str, &'static [&'static str])] { - match &*self.arch { - "aarch4" => AARCH64_IMPLIED_FEATURES, - "riscv32" | "riscv64" => RISCV_IMPLIED_FEATURES, - "x86" | "x86_64" => X86_IMPLIED_FEATURES, - "wasm32" | "wasm64" => WASM_IMPLIED_FEATURES, - _ => &[], - } - } } From 484aca885765739d5fa1f3d77e082552d8c4bc58 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 3 Aug 2024 04:45:48 -0400 Subject: [PATCH 08/14] Don't use LLVM's target features --- compiler/rustc_codegen_llvm/src/back/write.rs | 8 ++- compiler/rustc_codegen_llvm/src/context.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 63 ++++++++++++++----- .../rustc_codegen_ssa/src/target_features.rs | 23 +------ compiler/rustc_target/src/target_features.rs | 25 ++++++++ 6 files changed, 84 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 5a7909d151139..890fcf508a8bd 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -95,11 +95,15 @@ pub fn write_output_file<'ll>( } } -pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine { +pub fn create_informational_target_machine( + sess: &Session, + extra_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 = + if extra_features { llvm_util::global_llvm_features(sess, false) } else { Vec::new() }; target_machine_factory(sess, config::OptLevel::No, &features)(config) .unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise()) } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ea930421b5869..1dc3fbfc7b303 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -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, true); unsafe { llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 41e9cfd1066b9..333f1fdf6e03a 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -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, true)), } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index c70f6dd8180bf..e85974b7cc1ec 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -308,7 +308,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 { - let target_machine = create_informational_target_machine(sess); + let rust_features = sess + .target + .supported_target_features() + .iter() + .map(|(feature, _, _)| { + (to_llvm_features(sess, feature).llvm_feature_name, Symbol::intern(feature)) + }) + .collect::>(); + + let mut features = FxHashSet::default(); + + // Add base features for the target + let target_machine = create_informational_target_machine(sess, false); + 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 llvm_feature in global_llvm_features(sess, false) { + let (add, llvm_feature) = llvm_feature.split_at(1); + let feature = + rust_features.get(llvm_feature).cloned().unwrap_or(Symbol::intern(llvm_feature)); + if add == "+" { + features.extend(sess.target.implied_target_features(std::iter::once(feature))); + } else if add == "-" { + features.remove(&feature); + } + } + + // Filter enabled features based on feature gates sess.target .supported_target_features() .iter() @@ -320,18 +366,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { } }) .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() @@ -440,7 +475,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, true); match req.kind { PrintKind::TargetCPUs => { // SAFETY generate a C compatible string from a byte slice to pass diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 536f39375bb90..c84b844cd0401 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,6 +1,6 @@ use rustc_ast::ast; use rustc_attr::InstructionSetAttr; -use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir::def::DefKind; @@ -165,26 +165,7 @@ pub(crate) fn provide(providers: &mut Providers) { } }, implied_target_features: |tcx, feature| { - let implied_features = tcx - .sess - .target - .supported_target_features() - .iter() - .map(|(f, _, i)| (Symbol::intern(f), i)) - .collect::>(); - - // 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 = UnordSet::new(); - let mut new_features = vec![feature]; - 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 + tcx.sess.target.implied_target_features(std::iter::once(feature)).into() }, asm_target_features, ..*providers diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index f408db1dcbad2..0e9979e1bb7f6 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -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. @@ -469,4 +470,28 @@ impl super::spec::Target { _ => &[], } } + + pub fn implied_target_features( + &self, + base_features: impl Iterator, + ) -> FxHashSet { + let implied_features = self + .supported_target_features() + .iter() + .map(|(f, _, i)| (Symbol::intern(f), i)) + .collect::>(); + + // 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::>(); + 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 + } } From a25da077cf7606f42ffad17ee1562f932aa19b12 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 3 Aug 2024 23:51:37 -0400 Subject: [PATCH 09/14] Don't use LLVM to compute -Ctarget-feature --- compiler/rustc_codegen_llvm/src/back/write.rs | 5 +- compiler/rustc_codegen_llvm/src/context.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 211 +++++++++--------- compiler/rustc_target/src/target_features.rs | 8 +- tests/codegen/target-feature-overrides.rs | 2 +- 6 files changed, 120 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 890fcf508a8bd..a1f2433ab6f3b 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -97,13 +97,12 @@ pub fn write_output_file<'ll>( pub fn create_informational_target_machine( sess: &Session, - extra_features: bool, + 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 = - if extra_features { llvm_util::global_llvm_features(sess, false) } else { Vec::new() }; + 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()) } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1dc3fbfc7b303..173b8a479efc5 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -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, true); + let tm = crate::back::write::create_informational_target_machine(tcx.sess, false); unsafe { llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 333f1fdf6e03a..518a86e0cb06d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -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, true)), + tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)), } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index e85974b7cc1ec..3190853a84c90 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -308,19 +308,10 @@ 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 { - let rust_features = sess - .target - .supported_target_features() - .iter() - .map(|(feature, _, _)| { - (to_llvm_features(sess, feature).llvm_feature_name, Symbol::intern(feature)) - }) - .collect::>(); - let mut features = FxHashSet::default(); // Add base features for the target - let target_machine = create_informational_target_machine(sess, false); + let target_machine = create_informational_target_machine(sess, true); features.extend( sess.target .supported_target_features() @@ -343,13 +334,16 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { ); // Add enabled features - for llvm_feature in global_llvm_features(sess, false) { - let (add, llvm_feature) = llvm_feature.split_at(1); - let feature = - rust_features.get(llvm_feature).cloned().unwrap_or(Symbol::intern(llvm_feature)); - if add == "+" { + 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 if add == "-" { + } else { features.remove(&feature); } } @@ -475,7 +469,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, true); + 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 @@ -523,7 +517,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 { +pub(crate) fn global_llvm_features( + sess: &Session, + diagnostics: bool, + only_base_features: bool, +) -> Vec { // 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: // @@ -583,96 +581,109 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec 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(); + 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 }); + } + return None; } - 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 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 }, } - }); - 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 }); + } 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 == '+'); - } + 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; - } + // 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) { + // 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) { ('-' | '+', 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 { @@ -683,14 +694,6 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec Date: Sun, 4 Aug 2024 01:02:53 -0400 Subject: [PATCH 10/14] Remove redundant implied features --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 36 ++------------------ compiler/rustc_target/src/target_features.rs | 6 ++-- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 3190853a84c90..10cba179c7564 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -239,40 +239,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 => { diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 63bdcfddfc5f7..746926308b6b4 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -118,13 +118,15 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // FEAT_FLAGM ("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, &[]), // FEAT_I8MM ("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, &[]), // FEAT_LSE From 6b96a60611c5edaa107b109b5a50e58a64a33fc2 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sun, 4 Aug 2024 15:32:17 -0400 Subject: [PATCH 11/14] Add implied features to non-target-feature functions --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 26 ++++++++++++++++---- tests/codegen/target-feature-overrides.rs | 6 ++--- tests/codegen/tied-features-strength.rs | 2 +- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 10cba179c7564..1a80824a3b70d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -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}; @@ -553,11 +554,26 @@ pub(crate) fn global_llvm_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(',') + + // 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, diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs index 5b7489c96cf97..f38a1ae72de5d 100644 --- a/tests/codegen/target-feature-overrides.rs +++ b/tests/codegen/target-feature-overrides.rs @@ -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,{{.*}}" +// 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" diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs index 7f0805bc1b435..1b4596ae2cb57 100644 --- a/tests/codegen/tied-features-strength.rs +++ b/tests/codegen/tied-features-strength.rs @@ -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,?))*}}" } From 83276f568032f14b1af7e5cd9f7d928734af8d09 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sun, 4 Aug 2024 23:51:59 -0400 Subject: [PATCH 12/14] Hide implicit target features from diagnostics when possible --- compiler/rustc_codegen_gcc/src/attributes.rs | 2 +- compiler/rustc_codegen_llvm/src/attributes.rs | 2 +- .../rustc_codegen_ssa/src/target_features.rs | 28 ++++++++++++++----- .../rustc_const_eval/src/interpret/call.rs | 13 +++++++-- .../src/middle/codegen_fn_attrs.rs | 11 +++++++- .../rustc_mir_build/src/check_unsafety.rs | 26 +++++++++++++---- compiler/rustc_mir_transform/src/inline.rs | 4 ++- .../simd_feature_flag_difference.stderr | 4 +-- .../fail/function_calls/target_feature.rs | 2 +- .../fail/function_calls/target_feature.stderr | 4 +-- .../pass/shims/x86/intrinsics-x86-aes-vaes.rs | 2 +- .../pass/shims/x86/intrinsics-x86-avx.rs | 2 +- .../pass/shims/x86/intrinsics-x86-avx2.rs | 2 +- .../pass/shims/x86/intrinsics-x86-avx512.rs | 2 +- .../const-eval/const_fn_target_feature.stderr | 2 +- .../safe-calls.stderr | 26 ++++++++--------- 16 files changed, 89 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index e521551304ef8..5fdf2680aac88 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -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::>(); if let Some(features) = check_tied_features( diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index ad38814a68b6d..876f05c6277c1 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -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::>(); + codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::>(); if let Some(f) = llvm_util::check_tied_features( cx.tcx.sess, diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index c84b844cd0401..145b1ece23007 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -6,6 +6,7 @@ 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>, - target_features: &mut Vec, + target_features: &mut Vec, ) { let Some(list) = attr.meta_item_list() else { return }; let bad_item = |span| { @@ -99,14 +100,27 @@ pub fn from_target_feature( })); } - // Add both explicit and implied target features, using a set to deduplicate - let mut target_features_set = UnordSet::new(); + // 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() { - target_features_set + implied_target_features .extend_unord(tcx.implied_target_features(*feature).clone().into_items()); } - target_features_set.extend(added_target_features); - target_features.extend(target_features_set.into_sorted_stable_ord()) + 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 @@ -115,7 +129,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet { 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) => { diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 2c5147678e8cb..e5c195f08d71b 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -317,19 +317,26 @@ 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)) { + // Don't include implicit features in the error, unless only implicit features are + // missing. This should be rare, because it can only happen when an implicit feature + // is disabled, e.g. `+avx2,-avx` + let missing_explicit_features = attrs.target_features.iter().any(|feature| { + !feature.implied && !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| !(missing_explicit_features && 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 }), ); diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index ff6a3a9c12d36..b7d290e58d22b 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -28,7 +28,7 @@ pub struct CodegenFnAttrs { pub link_ordinal: Option, /// The `#[target_feature(enable = "...")]` attribute and the enabled /// features (only enabled features are supported right now). - pub target_features: Vec, + pub target_features: Vec, /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found. pub linkage: Option, /// The `#[linkage = "..."]` attribute on foreign items and the value we found. @@ -51,6 +51,15 @@ pub struct CodegenFnAttrs { pub patchable_function_entry: Option, } +#[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 diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 48018fcaa36df..0b4f0632f2b36 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -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>, @@ -442,14 +443,29 @@ 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) + }) { + // Don't include implicit features in the error, unless only implicit + // features are missing. + let missing_explicit_features = callee_features.iter().any(|feature| { + !feature.implied + && !self.body_target_features.iter().any(|body_feature| { + !feature.implied && body_feature.name == feature.name + }) + }); let missing: Vec<_> = callee_features .iter() .copied() - .filter(|feature| !self.body_target_features.contains(feature)) + .filter(|feature| { + !(missing_explicit_features && 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 diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index f30732e6aaf3b..0f012242c3738 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -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 diff --git a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr index 8ebd5d2726ffd..2544421c7e8c7 100644 --- a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr +++ b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3 +error: Undefined Behavior: calling a function that requires unavailable target features: avx --> $DIR/simd_feature_flag_difference.rs:LL:CC | LL | unsafe { foo(0.0, x) } - | ^^^^^^^^^^^ calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3 + | ^^^^^^^^^^^ calling a function that requires unavailable target features: avx | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.rs b/src/tools/miri/tests/fail/function_calls/target_feature.rs index 713d7c16f4c25..84e01eb4803fe 100644 --- a/src/tools/miri/tests/fail/function_calls/target_feature.rs +++ b/src/tools/miri/tests/fail/function_calls/target_feature.rs @@ -4,7 +4,7 @@ fn main() { assert!(!is_x86_feature_detected!("ssse3")); unsafe { - ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: sse3, ssse3 + ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: ssse3 } } diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.stderr b/src/tools/miri/tests/fail/function_calls/target_feature.stderr index 74a862c7b681c..4d3cf6e9d3bc0 100644 --- a/src/tools/miri/tests/fail/function_calls/target_feature.stderr +++ b/src/tools/miri/tests/fail/function_calls/target_feature.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: calling a function that requires unavailable target features: sse3, ssse3 +error: Undefined Behavior: calling a function that requires unavailable target features: ssse3 --> $DIR/target_feature.rs:LL:CC | LL | ssse3_fn(); - | ^^^^^^^^^^ calling a function that requires unavailable target features: sse3, ssse3 + | ^^^^^^^^^^ calling a function that requires unavailable target features: ssse3 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs index 13ebe56146381..7363c75361779 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs @@ -7,7 +7,7 @@ //@ignore-target-s390x //@ignore-target-thumbv7em //@ignore-target-wasm32 -//@compile-flags: -C target-feature=+aes,+vaes,+avx512f,+sse4.2 +//@compile-flags: -C target-feature=+aes,+vaes,+avx512f #![feature(avx512_target_feature, stdarch_x86_avx512)] diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs index 18693a2a97d11..728f57d48f17e 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs @@ -7,7 +7,7 @@ //@ignore-target-s390x //@ignore-target-thumbv7em //@ignore-target-wasm32 -//@compile-flags: -C target-feature=+avx,+sse4.2 +//@compile-flags: -C target-feature=+avx #[cfg(target_arch = "x86")] use std::arch::x86::*; diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs index f42ff6dfb51b2..80d125bb85650 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs @@ -7,7 +7,7 @@ //@ignore-target-s390x //@ignore-target-thumbv7em //@ignore-target-wasm32 -//@compile-flags: -C target-feature=+avx2,+sse4.2 +//@compile-flags: -C target-feature=+avx2 #[cfg(target_arch = "x86")] use std::arch::x86::*; diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs index 7d25854ccc075..66bfcb20f1c99 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs @@ -7,7 +7,7 @@ //@ignore-target-s390x //@ignore-target-thumbv7em //@ignore-target-wasm32 -//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq,+sse4.2 +//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq #![feature(avx512_target_feature)] #![feature(stdarch_x86_avx512)] diff --git a/tests/ui/consts/const-eval/const_fn_target_feature.stderr b/tests/ui/consts/const-eval/const_fn_target_feature.stderr index ad40d733546af..d3a00b57ebb50 100644 --- a/tests/ui/consts/const-eval/const_fn_target_feature.stderr +++ b/tests/ui/consts/const-eval/const_fn_target_feature.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const_fn_target_feature.rs:11:24 | LL | const B: () = unsafe { avx2_fn() }; - | ^^^^^^^^^ calling a function that requires unavailable target features: avx, avx2, sse4.1, sse4.2 + | ^^^^^^^^^ calling a function that requires unavailable target features: avx2 error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr index c2227f8e84783..1ddf05b40a606 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr @@ -4,8 +4,8 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2 - = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[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:29:5 @@ -13,8 +13,7 @@ error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and LL | 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, sse, sse2, sse3, sse4.1, sse4.2, ssse3, and bmi2 - = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[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 `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block --> $DIR/safe-calls.rs:31:5 @@ -22,8 +21,7 @@ error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsa 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, sse, sse2, sse3, sse4.1, sse4.2, ssse3, and bmi2 - = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[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 `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block --> $DIR/safe-calls.rs:38:5 @@ -31,7 +29,7 @@ error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and LL | 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, sse3, sse4.1, sse4.2, ssse3, 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 --> $DIR/safe-calls.rs:40:5 @@ -39,7 +37,7 @@ error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsa 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, sse3, sse4.1, sse4.2, ssse3, 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 --> $DIR/safe-calls.rs:47:5 @@ -63,8 +61,8 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req LL | const _: () = sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2 - = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[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_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block --> $DIR/safe-calls.rs:64:15 @@ -72,8 +70,8 @@ error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsaf LL | const _: () = sse2_and_fxsr(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = help: in order for the call to be safe, the context requires the following additional target features: sse, sse2, and fxsr - = note: the fxsr, sse, and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]` + = help: in order for the call to be safe, the context requires the following additional target features: 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:69:5 @@ -82,8 +80,8 @@ LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | = note: for more information, see issue #71668 - = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2 - = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[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]` note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/safe-calls.rs:68:1 | From 0b98a0c72769c2549827ec2320beb5478ca3c335 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 5 Aug 2024 10:31:03 -0400 Subject: [PATCH 13/14] Fix typo Co-authored-by: Amanieu d'Antras --- compiler/rustc_target/src/target_features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 746926308b6b4..da66ba270b33c 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -335,7 +335,7 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zkne", Stable, &[]), ("zknh", Stable, &[]), ("zkr", Stable, &[]), - ("zks", Stable, &["zbkb", "bzkc", "zbkx", "zksed", "zksh"]), + ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]), ("zksed", Stable, &[]), ("zksh", Stable, &[]), ("zkt", Stable, &[]), From 8818c9552821721e4be5c19832b4e3ac64090feb Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Tue, 6 Aug 2024 00:35:32 -0400 Subject: [PATCH 14/14] Disallow enabling features without their implied features --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 6 ++++-- compiler/rustc_codegen_ssa/src/target_features.rs | 8 ++++---- compiler/rustc_const_eval/src/interpret/call.rs | 8 +------- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_mir_build/src/check_unsafety.rs | 10 +--------- 5 files changed, 11 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 1a80824a3b70d..9fd8ca43789dd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -277,7 +277,7 @@ 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 { - let mut features = FxHashSet::default(); + let mut features = vec![]; // Add base features for the target let target_machine = create_informational_target_machine(sess, true); @@ -313,7 +313,9 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { if enabled { features.extend(sess.target.implied_target_features(std::iter::once(feature))); } else { - features.remove(&feature); + features.retain(|f| { + !sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) + }); } } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 145b1ece23007..cf8f7fa25d856 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,7 +1,7 @@ use rustc_ast::ast; use rustc_attr::InstructionSetAttr; use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; +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}; @@ -108,8 +108,7 @@ pub fn from_target_feature( // Add implied features let mut implied_target_features = UnordSet::new(); for feature in added_target_features.iter() { - implied_target_features - .extend_unord(tcx.implied_target_features(*feature).clone().into_items()); + implied_target_features.extend(tcx.implied_target_features(*feature).clone()); } for feature in added_target_features.iter() { implied_target_features.remove(feature); @@ -179,7 +178,8 @@ pub(crate) fn provide(providers: &mut Providers) { } }, implied_target_features: |tcx, feature| { - tcx.sess.target.implied_target_features(std::iter::once(feature)).into() + UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature))) + .into_sorted_stable_ord() }, asm_target_features, ..*providers diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index e5c195f08d71b..b5f3d07d90b35 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -319,18 +319,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .iter() .any(|feature| !self.tcx.sess.target_features.contains(&feature.name)) { - // Don't include implicit features in the error, unless only implicit features are - // missing. This should be rare, because it can only happen when an implicit feature - // is disabled, e.g. `+avx2,-avx` - let missing_explicit_features = attrs.target_features.iter().any(|feature| { - !feature.implied && !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| !(missing_explicit_features && feature.implied) + .filter(|&feature| !feature.implied && !self.tcx.sess.target_features.contains(&feature.name)) .fold(String::new(), |mut s, feature| { if !s.is_empty() { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b6a2943265034..5b114c9515c19 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2183,7 +2183,7 @@ rustc_queries! { desc { "looking up supported target features" } } - query implied_target_features(feature: Symbol) -> &'tcx UnordSet { + query implied_target_features(feature: Symbol) -> &'tcx Vec { arena_cache eval_always desc { "looking up implied target features" } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 0b4f0632f2b36..54a4204da71e8 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -447,19 +447,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { self.body_target_features.iter().any(|f| f.name == feature.name) }) { - // Don't include implicit features in the error, unless only implicit - // features are missing. - let missing_explicit_features = callee_features.iter().any(|feature| { - !feature.implied - && !self.body_target_features.iter().any(|body_feature| { - !feature.implied && body_feature.name == feature.name - }) - }); let missing: Vec<_> = callee_features .iter() .copied() .filter(|feature| { - !(missing_explicit_features && feature.implied) + !feature.implied && !self .body_target_features .iter()