Skip to content

Commit aab5145

Browse files
committed
move cfg(target_feature) computation into shared place
1 parent 50517d2 commit aab5145

File tree

3 files changed

+119
-116
lines changed

3 files changed

+119
-116
lines changed

compiler/rustc_codegen_gcc/src/lib.rs

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ use rustc_data_structures::sync::IntoDynSyncSend;
108108
use rustc_errors::DiagCtxtHandle;
109109
use rustc_metadata::EncodedMetadata;
110110
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
111+
use rustc_middle::target_features;
111112
use rustc_middle::ty::TyCtxt;
112113
use rustc_middle::util::Providers;
113114
use rustc_session::Session;
@@ -486,40 +487,20 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
486487

487488
/// Returns the features that should be set in `cfg(target_feature)`.
488489
fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig {
489-
// TODO(antoyo): use global_gcc_features.
490-
let f = |allow_unstable| {
491-
sess.target
492-
.rust_target_features()
493-
.iter()
494-
.filter_map(|&(feature, gate, _)| {
495-
if allow_unstable
496-
|| (gate.in_cfg()
497-
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
498-
{
499-
Some(feature)
500-
} else {
501-
None
502-
}
503-
})
504-
.filter(|feature| {
505-
// TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
506-
if *feature == "neon" {
507-
return false;
508-
}
509-
target_info.cpu_supports(feature)
510-
/*
511-
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
512-
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
513-
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
514-
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
515-
*/
516-
})
517-
.map(Symbol::intern)
518-
.collect()
519-
};
520-
521-
let target_features = f(false);
522-
let unstable_target_features = f(true);
490+
let (unstable_target_features, target_features) =
491+
target_features::cfg(sess, /* FIXME: we ignore `-Ctarget-feature` */ "", |feature| {
492+
// TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
493+
if feature == "neon" {
494+
return false;
495+
}
496+
target_info.cpu_supports(feature)
497+
/*
498+
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
499+
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
500+
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
501+
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
502+
*/
503+
});
523504

524505
TargetConfig {
525506
target_features,

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 7 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1313
use rustc_data_structures::small_c_str::SmallCStr;
1414
use rustc_data_structures::unord::UnordSet;
1515
use rustc_fs_util::path_to_c_string;
16-
use rustc_middle::bug;
16+
use rustc_middle::{bug, target_features};
1717
use rustc_session::Session;
1818
use rustc_session::config::{PrintKind, PrintRequest};
19-
use rustc_span::Symbol;
2019
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
21-
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
20+
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
2221
use smallvec::{SmallVec, smallvec};
2322

2423
use crate::back::write::create_informational_target_machine;
@@ -335,18 +334,11 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig {
335334
// the target CPU, that is still expanded to target features (with all their implied features)
336335
// by LLVM.
337336
let target_machine = create_informational_target_machine(sess, true);
338-
// Compute which of the known target features are enabled in the 'base' target machine. We only
339-
// consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
340-
let mut features: FxHashSet<Symbol> = sess
341-
.target
342-
.rust_target_features()
343-
.iter()
344-
.filter(|(feature, _, _)| {
345-
// skip checking special features, as LLVM may not understand them
346-
if RUSTC_SPECIAL_FEATURES.contains(feature) {
347-
return true;
348-
}
337+
338+
let (unstable_target_features, target_features) =
339+
target_features::cfg(sess, &sess.opts.cg.target_feature, |feature| {
349340
if let Some(feat) = to_llvm_features(sess, feature) {
341+
// All the LLVM features this expands to must be enabled.
350342
for llvm_feature in feat {
351343
let cstr = SmallCStr::new(llvm_feature);
352344
// `LLVMRustHasFeature` is moderately expensive. On targets with many
@@ -360,73 +352,8 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig {
360352
} else {
361353
false
362354
}
363-
})
364-
.map(|(feature, _, _)| Symbol::intern(feature))
365-
.collect();
366-
367-
// Add enabled and remove disabled features.
368-
for (enabled, feature) in
369-
sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() {
370-
Some('+') => Some((true, Symbol::intern(&s[1..]))),
371-
Some('-') => Some((false, Symbol::intern(&s[1..]))),
372-
_ => None,
373-
})
374-
{
375-
if enabled {
376-
// Also add all transitively implied features.
377-
378-
// We don't care about the order in `features` since the only thing we use it for is the
379-
// `features.contains` below.
380-
#[allow(rustc::potential_query_instability)]
381-
features.extend(
382-
sess.target
383-
.implied_target_features(feature.as_str())
384-
.iter()
385-
.map(|s| Symbol::intern(s)),
386-
);
387-
} else {
388-
// Remove transitively reverse-implied features.
389-
390-
// We don't care about the order in `features` since the only thing we use it for is the
391-
// `features.contains` below.
392-
#[allow(rustc::potential_query_instability)]
393-
features.retain(|f| {
394-
if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) {
395-
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
396-
// remove `f`. (This is the standard logical contraposition principle.)
397-
false
398-
} else {
399-
// We can keep `f`.
400-
true
401-
}
402-
});
403-
}
404-
}
405-
406-
// Filter enabled features based on feature gates.
407-
let f = |allow_unstable| {
408-
sess.target
409-
.rust_target_features()
410-
.iter()
411-
.filter_map(|(feature, gate, _)| {
412-
// The `allow_unstable` set is used by rustc internally to determined which target
413-
// features are truly available, so we want to return even perma-unstable
414-
// "forbidden" features.
415-
if allow_unstable
416-
|| (gate.in_cfg()
417-
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
418-
{
419-
Some(Symbol::intern(feature))
420-
} else {
421-
None
422-
}
423-
})
424-
.filter(|feature| features.contains(&feature))
425-
.collect()
426-
};
355+
});
427356

428-
let target_features = f(false);
429-
let unstable_target_features = f(true);
430357
let mut cfg = TargetConfig {
431358
target_features,
432359
unstable_target_features,

compiler/rustc_middle/src/target_features.rs

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
//! Shared utilities for dealing with target features that haven't (yet) found a better home.
22
use rustc_attr_data_structures::InstructionSetAttr;
3-
use rustc_data_structures::fx::FxIndexSet;
3+
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
44
use rustc_data_structures::unord::{UnordMap, UnordSet};
55
use rustc_errors::Applicability;
66
use rustc_hir as hir;
77
use rustc_hir::def::DefKind;
88
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
9+
use rustc_session::Session;
910
use rustc_session::parse::feature_err;
1011
use rustc_span::{Span, Symbol, sym};
11-
use rustc_target::target_features::{self, Stability};
12+
use rustc_target::target_features::{self, RUSTC_SPECIAL_FEATURES, Stability};
1213

1314
use crate::error;
1415
use crate::middle::codegen_fn_attrs::TargetFeature;
@@ -141,6 +142,100 @@ pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_s
141142
}
142143
}
143144

145+
/// Utility function for a codegen backend to compute `cfg(target_feature)`, or more specifically,
146+
/// to populate `sess.unstable_target_features` and `sess.target_features` (these are the first and
147+
/// 2nd component of the return value, respectively).
148+
///
149+
/// `target_feature_flag` is the value of `-Ctarget-feature` (giving the caller a chance to override it).
150+
/// `target_base_has_feature` should check whether the given feature (a Rust feature name!) is enabled
151+
/// in the "base" target machine, i.e., without applying `-Ctarget-feature`.
152+
///
153+
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled elsewhere.
154+
pub fn cfg(
155+
sess: &Session,
156+
target_feature_flag: &str,
157+
mut is_feature_enabled: impl FnMut(&str) -> bool,
158+
) -> (Vec<Symbol>, Vec<Symbol>) {
159+
// Compute which of the known target features are enabled in the 'base' target machine. We only
160+
// consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
161+
let mut features: FxHashSet<Symbol> = sess
162+
.target
163+
.rust_target_features()
164+
.iter()
165+
.filter(|(feature, _, _)| {
166+
// Skip checking special features, those are not known to the backend.
167+
if RUSTC_SPECIAL_FEATURES.contains(feature) {
168+
return true;
169+
}
170+
is_feature_enabled(feature)
171+
})
172+
.map(|(feature, _, _)| Symbol::intern(feature))
173+
.collect();
174+
175+
// Add enabled and remove disabled features.
176+
for (enabled, feature) in
177+
target_feature_flag.split(',').filter_map(|s| match s.chars().next() {
178+
Some('+') => Some((true, Symbol::intern(&s[1..]))),
179+
Some('-') => Some((false, Symbol::intern(&s[1..]))),
180+
_ => None,
181+
})
182+
{
183+
if enabled {
184+
// Also add all transitively implied features.
185+
186+
// We don't care about the order in `features` since the only thing we use it for is the
187+
// `features.contains` below.
188+
#[allow(rustc::potential_query_instability)]
189+
features.extend(
190+
sess.target
191+
.implied_target_features(feature.as_str())
192+
.iter()
193+
.map(|s| Symbol::intern(s)),
194+
);
195+
} else {
196+
// Remove transitively reverse-implied features.
197+
198+
// We don't care about the order in `features` since the only thing we use it for is the
199+
// `features.contains` below.
200+
#[allow(rustc::potential_query_instability)]
201+
features.retain(|f| {
202+
if sess.target.implied_target_features(f.as_str()).contains(&feature.as_str()) {
203+
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
204+
// remove `f`. (This is the standard logical contraposition principle.)
205+
false
206+
} else {
207+
// We can keep `f`.
208+
true
209+
}
210+
});
211+
}
212+
}
213+
214+
// Filter enabled features based on feature gates.
215+
let f = |allow_unstable| {
216+
sess.target
217+
.rust_target_features()
218+
.iter()
219+
.filter_map(|(feature, gate, _)| {
220+
// The `allow_unstable` set is used by rustc internally to determine which target
221+
// features are truly available, so we want to return even perma-unstable
222+
// "forbidden" features.
223+
if allow_unstable
224+
|| (gate.in_cfg()
225+
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
226+
{
227+
Some(Symbol::intern(feature))
228+
} else {
229+
None
230+
}
231+
})
232+
.filter(|feature| features.contains(&feature))
233+
.collect()
234+
};
235+
236+
(f(true), f(false))
237+
}
238+
144239
pub(crate) fn provide(providers: &mut Providers) {
145240
*providers = Providers {
146241
rust_target_features: |tcx, cnum| {

0 commit comments

Comments
 (0)