Skip to content

Commit 75d8b1e

Browse files
committed
move cfg(target_feature) computation into shared place
1 parent 8da6239 commit 75d8b1e

File tree

3 files changed

+124
-117
lines changed

3 files changed

+124
-117
lines changed

compiler/rustc_codegen_gcc/src/lib.rs

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ use rustc_codegen_ssa::back::write::{
102102
};
103103
use rustc_codegen_ssa::base::codegen_crate;
104104
use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};
105-
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig};
105+
use rustc_codegen_ssa::{
106+
CodegenResults, CompiledModule, ModuleCodegen, TargetConfig, target_features,
107+
};
106108
use rustc_data_structures::fx::FxIndexMap;
107109
use rustc_data_structures::sync::IntoDynSyncSend;
108110
use rustc_errors::DiagCtxtHandle;
@@ -486,40 +488,23 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
486488

487489
/// Returns the features that should be set in `cfg(target_feature)`.
488490
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);
491+
let (unstable_target_features, target_features) = target_features::cfg_target_feature(
492+
sess,
493+
/* FIXME: we ignore `-Ctarget-feature` */ "",
494+
|feature| {
495+
// TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
496+
if feature == "neon" {
497+
return false;
498+
}
499+
target_info.cpu_supports(feature)
500+
/*
501+
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
502+
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
503+
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
504+
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
505+
*/
506+
},
507+
);
523508

524509
TargetConfig {
525510
target_features,

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 7 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use std::sync::Once;
66
use std::{ptr, slice, str};
77

88
use libc::c_int;
9-
use rustc_codegen_ssa::TargetConfig;
109
use rustc_codegen_ssa::base::wants_wasm_eh;
1110
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
11+
use rustc_codegen_ssa::{TargetConfig, target_features};
1212
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1313
use rustc_data_structures::small_c_str::SmallCStr;
1414
use rustc_data_structures::unord::UnordSet;
@@ -17,9 +17,8 @@ use rustc_middle::bug;
1717
use rustc_session::Session;
1818
use rustc_session::config::{PrintKind, PrintRequest};
1919
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
20-
use rustc_span::Symbol;
2120
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
22-
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
21+
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
2322
use smallvec::{SmallVec, smallvec};
2423

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

436-
let target_features = f(false);
437-
let unstable_target_features = f(true);
438365
let mut cfg = TargetConfig {
439366
target_features,
440367
unstable_target_features,

compiler/rustc_codegen_ssa/src/target_features.rs

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_attr_data_structures::InstructionSetAttr;
2-
use rustc_data_structures::fx::FxIndexSet;
2+
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
33
use rustc_data_structures::unord::{UnordMap, UnordSet};
44
use rustc_errors::Applicability;
55
use rustc_hir as hir;
@@ -8,11 +8,12 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
88
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
99
use rustc_middle::query::Providers;
1010
use rustc_middle::ty::TyCtxt;
11+
use rustc_session::Session;
1112
use rustc_session::features::StabilityExt;
1213
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
1314
use rustc_session::parse::feature_err;
1415
use rustc_span::{Span, Symbol, sym};
15-
use rustc_target::target_features::{self, Stability};
16+
use rustc_target::target_features::{self, RUSTC_SPECIAL_FEATURES, Stability};
1617

1718
use crate::errors;
1819

@@ -156,6 +157,100 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId,
156157
}
157158
}
158159

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

0 commit comments

Comments
 (0)