Skip to content

Commit 0b8e5fb

Browse files
committed
move cfg(target_feature) computation into shared place
1 parent af49554 commit 0b8e5fb

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,15 +1,16 @@
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};
99
use rustc_lint_defs::builtin::AARCH64_SOFTFLOAT_NEON;
10+
use rustc_session::Session;
1011
use rustc_session::parse::feature_err;
1112
use rustc_span::{Span, Symbol, sym};
12-
use rustc_target::target_features::{self, Stability};
13+
use rustc_target::target_features::{self, RUSTC_SPECIAL_FEATURES, Stability};
1314

1415
use crate::error;
1516
use crate::middle::codegen_fn_attrs::TargetFeature;
@@ -154,6 +155,100 @@ pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_s
154155
}
155156
}
156157

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

0 commit comments

Comments
 (0)