diff options
| author | Ralf Jung <post@ralfj.de> | 2025-05-10 22:53:38 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2025-06-19 09:42:35 +0900 |
| commit | d70ec32ea7e03e3a082a45eeba6c8aa4c653efb4 (patch) | |
| tree | 214833f4ba7753aec677b422eed7a911c1bfdb76 /compiler/rustc_codegen_ssa/src | |
| parent | 044514eb26511d2d8aa999fdf27e85df6beb6576 (diff) | |
| download | rust-d70ec32ea7e03e3a082a45eeba6c8aa4c653efb4.tar.gz rust-d70ec32ea7e03e3a082a45eeba6c8aa4c653efb4.zip | |
move cfg(target_feature) computation into shared place
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/target_features.rs | 99 |
1 files changed, 97 insertions, 2 deletions
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 640d197c219..476671d6855 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,5 +1,5 @@ use rustc_attr_data_structures::InstructionSetAttr; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -8,11 +8,12 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_session::Session; use rustc_session::features::StabilityExt; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use rustc_target::target_features::{self, Stability}; +use rustc_target::target_features::{self, RUSTC_SPECIAL_FEATURES, Stability}; use crate::errors; @@ -156,6 +157,100 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, } } +/// Utility function for a codegen backend to compute `cfg(target_feature)`, or more specifically, +/// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and +/// 2nd component of the return value, respectively). +/// +/// `target_feature_flag` is the value of `-Ctarget-feature` (giving the caller a chance to override it). +/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is enabled +/// in the "base" target machine, i.e., without applying `-Ctarget-feature`. +/// +/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere. +pub fn cfg_target_feature( + sess: &Session, + target_feature_flag: &str, + mut is_feature_enabled: impl FnMut(&str) -> bool, +) -> (Vec<Symbol>, Vec<Symbol>) { + // Compute which of the known target features are enabled in the 'base' target machine. We only + // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now. + let mut features: FxHashSet<Symbol> = sess + .target + .rust_target_features() + .iter() + .filter(|(feature, _, _)| { + // Skip checking special features, those are not known to the backend. + if RUSTC_SPECIAL_FEATURES.contains(feature) { + return true; + } + is_feature_enabled(feature) + }) + .map(|(feature, _, _)| Symbol::intern(feature)) + .collect(); + + // Add enabled and remove disabled features. + for (enabled, feature) in + target_feature_flag.split(',').filter_map(|s| match s.chars().next() { + Some('+') => Some((true, Symbol::intern(&s[1..]))), + Some('-') => Some((false, Symbol::intern(&s[1..]))), + _ => None, + }) + { + if enabled { + // Also add all transitively implied features. + + // We don't care about the order in `features` since the only thing we use it for is the + // `features.contains` below. + #[allow(rustc::potential_query_instability)] + features.extend( + sess.target + .implied_target_features(feature.as_str()) + .iter() + .map(|s| Symbol::intern(s)), + ); + } else { + // Remove transitively reverse-implied features. + + // We don't care about the order in `features` since the only thing we use it for is the + // `features.contains` below. + #[allow(rustc::potential_query_instability)] + features.retain(|f| { + if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) { + // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to + // remove `f`. (This is the standard logical contraposition principle.) + false + } else { + // We can keep `f`. + true + } + }); + } + } + + // Filter enabled features based on feature gates. + let f = |allow_unstable| { + sess.target + .rust_target_features() + .iter() + .filter_map(|(feature, gate, _)| { + // The `allow_unstable` set is used by rustc internally to determine which target + // features are truly available, so we want to return even perma-unstable + // "forbidden" features. + if allow_unstable + || (gate.in_cfg() + && (sess.is_nightly_build() || gate.requires_nightly().is_none())) + { + Some(Symbol::intern(feature)) + } else { + None + } + }) + .filter(|feature| features.contains(&feature)) + .collect() + }; + + (f(true), f(false)) +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { rust_target_features: |tcx, cnum| { |
