Skip to content

Commit fedbccd

Browse files
committed
Use rust rather than LLVM target features in the target spec
This works better with non-LLVM codegen backends.
1 parent e22dab3 commit fedbccd

39 files changed

+120
-79
lines changed

compiler/rustc_codegen_gcc/src/gcc_util.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,7 @@ pub(crate) fn global_gcc_features(sess: &Session) -> Vec<String> {
3333
// should be taken in cases like these.
3434
let mut features = vec![];
3535

36-
// Features implied by an implicit or explicit `--target`.
37-
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
38-
39-
// -Ctarget-features
40-
target_features::flag_to_backend_features(sess, |feature, enable| {
36+
let mut extend_backend_features = |feature: &str, enable: bool| {
4137
// We run through `to_gcc_features` when
4238
// passing requests down to GCC. This means that all in-language
4339
// features also work on the command line instead of having two
@@ -48,7 +44,13 @@ pub(crate) fn global_gcc_features(sess: &Session) -> Vec<String> {
4844
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
4945
.map(|feature| if !enable { format!("-{}", feature) } else { feature.to_string() }),
5046
);
51-
});
47+
};
48+
49+
// Features implied by an implicit or explicit `--target`.
50+
target_features::target_spec_to_backend_features(sess, &mut extend_backend_features);
51+
52+
// -Ctarget-features
53+
target_features::flag_to_backend_features(sess, extend_backend_features);
5254

5355
gcc_features_by_flags(sess, &mut features);
5456

@@ -66,6 +68,7 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]>
6668
(&Arch::X86 | &Arch::X86_64, "rdrand") => smallvec!["rdrnd"],
6769
(&Arch::X86 | &Arch::X86_64, "bmi1") => smallvec!["bmi"],
6870
(&Arch::X86 | &Arch::X86_64, "cmpxchg16b") => smallvec!["cx16"],
71+
(&Arch::X86 | &Arch::X86_64, "lahfsahf") => smallvec!["sahf"],
6972
(&Arch::X86 | &Arch::X86_64, "avx512vaes") => smallvec!["vaes"],
7073
(&Arch::X86 | &Arch::X86_64, "avx512gfni") => smallvec!["gfni"],
7174
(&Arch::X86 | &Arch::X86_64, "avx512vpclmulqdq") => smallvec!["vpclmulqdq"],

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,10 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
626626

627627
/// The target features for compiler flags other than `-Ctarget-features`.
628628
fn llvm_features_by_flags(sess: &Session, features: &mut Vec<String>) {
629+
if wants_wasm_eh(sess) && sess.panic_strategy() == PanicStrategy::Unwind {
630+
features.push("+exception-handling".into());
631+
}
632+
629633
target_features::retpoline_features_by_flags(sess, features);
630634

631635
// -Zfixed-x18
@@ -691,36 +695,35 @@ pub(crate) fn global_llvm_features(sess: &Session, only_base_features: bool) ->
691695
Some(_) | None => {}
692696
};
693697

694-
// Features implied by an implicit or explicit `--target`.
695-
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
698+
let mut extend_backend_features = |feature: &str, enable: bool| {
699+
let enable_disable = if enable { '+' } else { '-' };
700+
// We run through `to_llvm_features` when
701+
// passing requests down to LLVM. This means that all in-language
702+
// features also work on the command line instead of having two
703+
// different names when the LLVM name and the Rust name differ.
704+
let Some(llvm_feature) = to_llvm_features(sess, feature) else { return };
705+
706+
features.extend(
707+
std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name)).chain(
708+
llvm_feature.dependencies.into_iter().filter_map(move |feat| {
709+
match (enable, feat) {
710+
(_, TargetFeatureFoldStrength::Both(f))
711+
| (true, TargetFeatureFoldStrength::EnableOnly(f)) => {
712+
Some(format!("{enable_disable}{f}"))
713+
}
714+
_ => None,
715+
}
716+
}),
717+
),
718+
);
719+
};
696720

697-
if wants_wasm_eh(sess) && sess.panic_strategy() == PanicStrategy::Unwind {
698-
features.push("+exception-handling".into());
699-
}
721+
// Features implied by an implicit or explicit `--target`.
722+
target_features::target_spec_to_backend_features(sess, &mut extend_backend_features);
700723

701724
// -Ctarget-features
702725
if !only_base_features {
703-
target_features::flag_to_backend_features(sess, |feature, enable| {
704-
let enable_disable = if enable { '+' } else { '-' };
705-
// We run through `to_llvm_features` when
706-
// passing requests down to LLVM. This means that all in-language
707-
// features also work on the command line instead of having two
708-
// different names when the LLVM name and the Rust name differ.
709-
let Some(llvm_feature) = to_llvm_features(sess, feature) else { return };
710-
711-
features.extend(
712-
std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name))
713-
.chain(llvm_feature.dependencies.into_iter().filter_map(move |feat| {
714-
match (enable, feat) {
715-
(_, TargetFeatureFoldStrength::Both(f))
716-
| (true, TargetFeatureFoldStrength::EnableOnly(f)) => {
717-
Some(format!("{enable_disable}{f}"))
718-
}
719-
_ => None,
720-
}
721-
})),
722-
)
723-
});
726+
target_features::flag_to_backend_features(sess, extend_backend_features);
724727
}
725728

726729
// We add this in the "base target" so that these show up in `sess.unstable_target_features`.

compiler/rustc_codegen_ssa/src/target_features.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,12 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId,
139139
}
140140
}
141141

142-
/// Parse the value of `-Ctarget-feature`, also expanding implied features,
143-
/// and call the closure for each (expanded) Rust feature. If the list contains
142+
/// Parse the value of the target spec `features` field or `-Ctarget-feature`, also expanding
143+
/// implied features, and call the closure for each (expanded) Rust feature. If the list contains
144144
/// a syntactically invalid item (not starting with `+`/`-`), the error callback is invoked.
145-
fn parse_rust_feature_flag<'a>(
145+
fn parse_rust_feature_list<'a>(
146146
sess: &'a Session,
147+
features: &'a str,
147148
err_callback: impl Fn(&'a str),
148149
mut callback: impl FnMut(
149150
/* base_feature */ &'a str,
@@ -154,7 +155,7 @@ fn parse_rust_feature_flag<'a>(
154155
// A cache for the backwards implication map.
155156
let mut inverse_implied_features: Option<FxHashMap<&str, FxHashSet<&str>>> = None;
156157

157-
for feature in sess.opts.cg.target_feature.split(',') {
158+
for feature in features.split(',') {
158159
if let Some(base_feature) = feature.strip_prefix('+') {
159160
// Skip features that are not target features, but rustc features.
160161
if RUSTC_SPECIFIC_FEATURES.contains(&base_feature) {
@@ -244,8 +245,9 @@ pub fn cfg_target_feature<'a, const N: usize>(
244245
let mut enabled_disabled_features = FxHashMap::default();
245246

246247
// Add enabled and remove disabled features.
247-
parse_rust_feature_flag(
248+
parse_rust_feature_list(
248249
sess,
250+
&sess.opts.cg.target_feature,
249251
/* err_callback */
250252
|feature| {
251253
sess.dcx().emit_warn(errors::UnknownCTargetFeaturePrefix { feature });
@@ -366,6 +368,37 @@ pub fn check_tied_features(
366368
None
367369
}
368370

371+
/// Translates the target spec `features` field into a backend target feature list.
372+
///
373+
/// `extend_backend_features` extends the set of backend features (assumed to be in mutable state
374+
/// accessible by that closure) to enable/disable the given Rust feature name.
375+
pub fn target_spec_to_backend_features<'a>(
376+
sess: &'a Session,
377+
mut extend_backend_features: impl FnMut(&'a str, /* enable */ bool),
378+
) {
379+
// Compute implied features
380+
let mut rust_features = vec![];
381+
parse_rust_feature_list(
382+
sess,
383+
&sess.target.features,
384+
/* err_callback */
385+
|feature| {
386+
panic!("Target spec contains invalid feature {feature}");
387+
},
388+
|_base_feature, new_features, enable| {
389+
// FIXME emit an error for unknown features like cfg_target_feature would for -Ctarget-feature
390+
rust_features.extend(
391+
UnordSet::from(new_features).to_sorted_stable_ord().iter().map(|&&s| (enable, s)),
392+
);
393+
},
394+
);
395+
396+
// Add this to the backend features.
397+
for (enable, feature) in rust_features {
398+
extend_backend_features(feature, enable);
399+
}
400+
}
401+
369402
/// Translates the `-Ctarget-feature` flag into a backend target feature list.
370403
///
371404
/// `extend_backend_features` extends the set of backend features (assumed to be in mutable state
@@ -376,8 +409,9 @@ pub fn flag_to_backend_features<'a>(
376409
) {
377410
// Compute implied features
378411
let mut rust_features = vec![];
379-
parse_rust_feature_flag(
412+
parse_rust_feature_list(
380413
sess,
414+
&sess.opts.cg.target_feature,
381415
/* err_callback */
382416
|_feature| {
383417
// Errors are already emitted in `cfg_target_feature`; avoid duplicates.

compiler/rustc_interface/src/util.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -364,15 +364,16 @@ impl CodegenBackend for DummyCodegenBackend {
364364
}
365365

366366
fn target_config(&self, sess: &Session) -> TargetConfig {
367+
let abi_required_features = sess.target.abi_required_features();
367368
let (target_features, unstable_target_features) = cfg_target_feature::<0>(
368369
sess,
369370
|_feature| Default::default(),
370371
|feature| {
371372
// This is a standin for the list of features a backend is expected to enable.
372373
// It would be better to parse target.features instead and handle implied features,
373-
// but target.features is a list of LLVM target features, not Rust target features.
374-
// The dummy backend doesn't know the mapping between LLVM and Rust target features.
375-
sess.target.abi_required_features().required.contains(&feature)
374+
// but target.features doesn't contain features that are enabled by default for an
375+
// architecture or target cpu.
376+
abi_required_features.required.contains(&feature)
376377
},
377378
);
378379

compiler/rustc_target/src/spec/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2246,10 +2246,10 @@ pub struct TargetOptions {
22462246
/// Whether a cpu needs to be explicitly set.
22472247
/// Set to true if there is no default cpu. Defaults to false.
22482248
pub need_explicit_cpu: bool,
2249-
/// Default target features to pass to LLVM. These features overwrite
2250-
/// `-Ctarget-cpu` but can be overwritten with `-Ctarget-features`.
2251-
/// Corresponds to `llc -mattr=$features`.
2252-
/// Note that these are LLVM feature names, not Rust feature names!
2249+
/// Default (Rust) target features to enable for this target. These features
2250+
/// overwrite `-Ctarget-cpu` but can be overwritten with `-Ctarget-features`.
2251+
/// Corresponds to `llc -mattr=$llvm_features` where `$llvm_features` is the
2252+
/// result of mapping the Rust features in this field to LLVM features.
22532253
///
22542254
/// Generally it is a bad idea to use negative target features because they often interact very
22552255
/// poorly with how `-Ctarget-cpu` works. Instead, try to use a lower "base CPU" and enable the

compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
1616
.into(),
1717
arch,
1818
options: TargetOptions {
19-
features: "+neon,+fp-armv8,+apple-a7".into(),
19+
features: "+neon,+apple-a7".into(),
2020
max_atomic_width: Some(128),
2121
supported_sanitizers: SanitizerSet::ADDRESS
2222
| SanitizerSet::THREAD

compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
1616
.into(),
1717
arch,
1818
options: TargetOptions {
19-
features: "+neon,+fp-armv8,+apple-a12".into(),
19+
features: "+neon,+apple-a12".into(),
2020
max_atomic_width: Some(128),
2121
supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD,
2222
..opts

compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
1616
.into(),
1717
arch,
1818
options: TargetOptions {
19-
features: "+neon,+fp-armv8,+apple-a7".into(),
19+
features: "+neon,+apple-a7".into(),
2020
max_atomic_width: Some(128),
2121
supported_sanitizers: SanitizerSet::ADDRESS
2222
| SanitizerSet::THREAD

compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
1616
.into(),
1717
arch,
1818
options: TargetOptions {
19-
features: "+neon,+fp-armv8,+apple-a7".into(),
19+
features: "+neon,+apple-a7".into(),
2020
max_atomic_width: Some(128),
2121
..opts
2222
},

compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
1616
.into(),
1717
arch,
1818
options: TargetOptions {
19-
features: "+neon,+fp-armv8,+apple-a7".into(),
19+
features: "+neon,+apple-a7".into(),
2020
max_atomic_width: Some(128),
2121
..opts
2222
},

0 commit comments

Comments
 (0)