Skip to content

Commit 27ad89e

Browse files
authored
Unrolled build for #140920
Rollup merge of #140920 - RalfJung:target-feature-unification, r=nnethercote,WaffleLapkin Extract some shared code from codegen backend target feature handling There's a bunch of code duplication between the GCC and LLVM backends in target feature handling. This moves that into new shared helper functions in `rustc_codegen_ssa`. The first two commits should be purely refactoring. I am fairly sure the LLVM-side behavior stays the same; if the GCC side deliberately diverges from this then I may have missed that. I did account for one divergence, which I do not know is deliberate or not: GCC does not seem to use the `-Ctarget-feature` flag to populate `cfg(target_feature)`. That seems odd, since the `-Ctarget-feature` flag is used to populate the return value of `global_gcc_features` which controls the target features actually used by GCC. ``@GuillaumeGomez`` ``@antoyo`` is there a reason `target_config` ignores `-Ctarget-feature` but `global_gcc_features` does not? The second commit also cleans up a bunch of unneeded complexity added in #135927. The third commit extracts some shared logic out of the functions that populate `cfg(target_feature)` and the backend target feature set, respectively. This one actually has some slight functional changes: - Before, with `-Ctarget-feature=-feat`, if there is some other feature `x` that implies `feat` we would *not* add `-x` to the backend target feature set. Now, we do. This fixes #134792. - The logic that removes `x` from `cfg(target_feature)` in this case also changed a bit, avoiding a large number of calls to the (uncached) `sess.target.implied_target_features` (if there were a large number of positive features listed before a negative feature) but instead constructing a full inverse implication map when encountering the first negative feature. Ideally this would be done with queries but the backend target feature logic runs before `tcx` so we can't use that... - Previously, if feature "a" implied "b" and "b" was unstable, then using `-Ctarget-feature=+a` would also emit a warning about `b`. I had to remove this since when accounting for negative implications, this emits a ton of warnings in a bunch of existing tests... I assume this was unintentional anyway. The fourth commit increases consistency of the GCC backend with the LLVM backend. The last commit does some further cleanup: - Get rid of RUSTC_SPECIAL_FEATURES. It was only needed for s390x "backchain", but since LLVM 19 that is always a regular target feature so we don't need this hack any more. The hack also has various unintended side-effects so we don't want to keep it. Fixes #142412. - Move RUSTC_SPECIFIC_FEATURES handling into the shared parse_rust_feature_flag helper so all consumers of `-Ctarget-feature` that only care about actual target features (and not "crt-static") have it. Previously, we actually set `cfg(target_feature = "crt-static")` twice: once in the backend target feature logic, and once specifically for that one feature. IIUC, some targets are meant to ignore `-Ctarget-feature=+crt-static`, it seems like before this PR that flag still incorrectly enabled `cfg(target_feature = "crt-static")` (but I didn't test this). - Move fixed_x18 handling together with retpoline handling. - Forbid setting fixed_x18 as a regular target feature, even unstably. It must be set via the `-Z` flag. ``@bjorn3`` I did not touch the cranelift backend here, since AFAIK it doesn't really support target features. But if you ever do, please use the new helpers. :) Cc ``@workingjubilee``
2 parents 18491d5 + a50a3b8 commit 27ad89e

29 files changed

+534
-632
lines changed
Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
codegen_gcc_unknown_ctarget_feature_prefix =
2-
unknown feature specified for `-Ctarget-feature`: `{$feature}`
3-
.note = features must begin with a `+` to enable or `-` to disable it
4-
51
codegen_gcc_unwinding_inline_asm =
62
GCC backend does not support unwinding from inline asm
73
@@ -16,15 +12,3 @@ codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and st
1612
codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
1713
1814
codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err})
19-
20-
codegen_gcc_unknown_ctarget_feature =
21-
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
22-
.note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
23-
.possible_feature = you might have meant: `{$rust_feature}`
24-
.consider_filing_feature_request = consider filing a feature request
25-
26-
codegen_gcc_missing_features =
27-
add the missing features in a `target_feature` attribute
28-
29-
codegen_gcc_target_feature_disable_or_enable =
30-
the target features {$features} must all be either enabled or disabled together

compiler/rustc_codegen_gcc/src/errors.rs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,6 @@
1-
use rustc_macros::{Diagnostic, Subdiagnostic};
1+
use rustc_macros::Diagnostic;
22
use rustc_span::Span;
33

4-
#[derive(Diagnostic)]
5-
#[diag(codegen_gcc_unknown_ctarget_feature_prefix)]
6-
#[note]
7-
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
8-
pub feature: &'a str,
9-
}
10-
11-
#[derive(Diagnostic)]
12-
#[diag(codegen_gcc_unknown_ctarget_feature)]
13-
#[note]
14-
pub(crate) struct UnknownCTargetFeature<'a> {
15-
pub feature: &'a str,
16-
#[subdiagnostic]
17-
pub rust_feature: PossibleFeature<'a>,
18-
}
19-
20-
#[derive(Subdiagnostic)]
21-
pub(crate) enum PossibleFeature<'a> {
22-
#[help(codegen_gcc_possible_feature)]
23-
Some { rust_feature: &'a str },
24-
#[help(codegen_gcc_consider_filing_feature_request)]
25-
None,
26-
}
27-
284
#[derive(Diagnostic)]
295
#[diag(codegen_gcc_unwinding_inline_asm)]
306
pub(crate) struct UnwindingInlineAsm {

compiler/rustc_codegen_gcc/src/gcc_util.rs

Lines changed: 23 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
11
#[cfg(feature = "master")]
22
use gccjit::Context;
3-
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
4-
use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
5-
use rustc_data_structures::fx::FxHashMap;
6-
use rustc_data_structures::unord::UnordSet;
3+
use rustc_codegen_ssa::target_features;
74
use rustc_session::Session;
8-
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
9-
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
105
use smallvec::{SmallVec, smallvec};
116

12-
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
13-
14-
fn gcc_features_by_flags(sess: &Session) -> Vec<&str> {
15-
let mut features: Vec<&str> = Vec::new();
16-
retpoline_features_by_flags(sess, &mut features);
17-
features
7+
fn gcc_features_by_flags(sess: &Session, features: &mut Vec<String>) {
8+
target_features::retpoline_features_by_flags(sess, features);
9+
// FIXME: LLVM also sets +reserve-x18 here under some conditions.
1810
}
1911

2012
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
@@ -44,98 +36,29 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
4436
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
4537

4638
// -Ctarget-features
47-
let known_features = sess.target.rust_target_features();
48-
let mut featsmap = FxHashMap::default();
49-
50-
// Compute implied features
51-
let mut all_rust_features = vec![];
52-
for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) {
53-
if let Some(feature) = feature.strip_prefix('+') {
54-
all_rust_features.extend(
55-
UnordSet::from(sess.target.implied_target_features(feature))
56-
.to_sorted_stable_ord()
57-
.iter()
58-
.map(|&&s| (true, s)),
59-
)
60-
} else if let Some(feature) = feature.strip_prefix('-') {
61-
// FIXME: Why do we not remove implied features on "-" here?
62-
// We do the equivalent above in `target_config`.
63-
// See <https://github.com/rust-lang/rust/issues/134792>.
64-
all_rust_features.push((false, feature));
65-
} else if !feature.is_empty() && diagnostics {
66-
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
67-
}
68-
}
69-
// Remove features that are meant for rustc, not codegen.
70-
all_rust_features.retain(|&(_, feature)| {
71-
// Retain if it is not a rustc feature
72-
!RUSTC_SPECIFIC_FEATURES.contains(&feature)
73-
});
74-
75-
// Check feature validity.
76-
if diagnostics {
77-
for &(enable, feature) in &all_rust_features {
78-
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
79-
match feature_state {
80-
None => {
81-
let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| {
82-
let gcc_features = to_gcc_features(sess, rust_feature);
83-
if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature)
84-
{
85-
Some(rust_feature)
86-
} else {
87-
None
88-
}
89-
});
90-
let unknown_feature = if let Some(rust_feature) = rust_feature {
91-
UnknownCTargetFeature {
92-
feature,
93-
rust_feature: PossibleFeature::Some { rust_feature },
94-
}
95-
} else {
96-
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
97-
};
98-
sess.dcx().emit_warn(unknown_feature);
99-
}
100-
Some(&(_, stability, _)) => {
101-
stability.verify_feature_enabled_by_flag(sess, enable, feature);
102-
}
103-
}
104-
105-
// FIXME(nagisa): figure out how to not allocate a full hashset here.
106-
featsmap.insert(feature, enable);
107-
}
108-
}
109-
110-
// Translate this into GCC features.
111-
let feats =
112-
all_rust_features.iter().flat_map(|&(enable, feature)| {
113-
let enable_disable = if enable { '+' } else { '-' };
39+
target_features::flag_to_backend_features(
40+
sess,
41+
diagnostics,
42+
|feature| to_gcc_features(sess, feature),
43+
|feature, enable| {
11444
// We run through `to_gcc_features` when
11545
// passing requests down to GCC. This means that all in-language
11646
// features also work on the command line instead of having two
11747
// different names when the GCC name and the Rust name differ.
118-
to_gcc_features(sess, feature)
119-
.iter()
120-
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
121-
.map(|feature| {
122-
if enable_disable == '-' {
123-
format!("-{}", feature)
124-
} else {
125-
feature.to_string()
126-
}
127-
})
128-
.collect::<Vec<_>>()
129-
});
130-
features.extend(feats);
131-
132-
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
133-
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
134-
features: f,
135-
span: None,
136-
missing_features: None,
137-
});
138-
}
48+
features.extend(
49+
to_gcc_features(sess, feature)
50+
.iter()
51+
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
52+
.map(
53+
|feature| {
54+
if !enable { format!("-{}", feature) } else { feature.to_string() }
55+
},
56+
),
57+
);
58+
},
59+
);
60+
61+
gcc_features_by_flags(sess, &mut features);
13962

14063
features
14164
}

compiler/rustc_codegen_gcc/src/lib.rs

Lines changed: 16 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ use rustc_codegen_ssa::back::write::{
102102
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn,
103103
};
104104
use rustc_codegen_ssa::base::codegen_crate;
105+
use rustc_codegen_ssa::target_features::cfg_target_feature;
105106
use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};
106107
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig};
107108
use rustc_data_structures::fx::FxIndexMap;
@@ -476,42 +477,21 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
476477

477478
/// Returns the features that should be set in `cfg(target_feature)`.
478479
fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig {
479-
// TODO(antoyo): use global_gcc_features.
480-
let f = |allow_unstable| {
481-
sess.target
482-
.rust_target_features()
483-
.iter()
484-
.filter_map(|&(feature, gate, _)| {
485-
if allow_unstable
486-
|| (gate.in_cfg()
487-
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
488-
{
489-
Some(feature)
490-
} else {
491-
None
492-
}
493-
})
494-
.filter(|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-
// cSpell:disable
501-
/*
502-
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
503-
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
504-
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
505-
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
506-
*/
507-
// cSpell:enable
508-
})
509-
.map(Symbol::intern)
510-
.collect()
511-
};
512-
513-
let target_features = f(false);
514-
let unstable_target_features = f(true);
480+
let (unstable_target_features, target_features) = cfg_target_feature(sess, |feature| {
481+
// TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
482+
if feature == "neon" {
483+
return false;
484+
}
485+
target_info.cpu_supports(feature)
486+
// cSpell:disable
487+
/*
488+
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
489+
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
490+
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
491+
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
492+
*/
493+
// cSpell:enable
494+
});
515495

516496
let has_reliable_f16 = target_info.supports_target_dependent_type(CType::Float16);
517497
let has_reliable_f128 = target_info.supports_target_dependent_type(CType::Float128);

compiler/rustc_codegen_llvm/messages.ftl

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,6 @@ codegen_llvm_symbol_already_defined =
5959
codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
6060
codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
6161
62-
codegen_llvm_unknown_ctarget_feature =
63-
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
64-
.note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
65-
.possible_feature = you might have meant: `{$rust_feature}`
66-
.consider_filing_feature_request = consider filing a feature request
67-
68-
codegen_llvm_unknown_ctarget_feature_prefix =
69-
unknown feature specified for `-Ctarget-feature`: `{$feature}`
70-
.note = features must begin with a `+` to enable or `-` to disable it
71-
7262
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
7363
7464
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}

compiler/rustc_codegen_llvm/src/errors.rs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,11 @@ use std::path::Path;
33

44
use rustc_data_structures::small_c_str::SmallCStr;
55
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
6-
use rustc_macros::{Diagnostic, Subdiagnostic};
6+
use rustc_macros::Diagnostic;
77
use rustc_span::Span;
88

99
use crate::fluent_generated as fluent;
1010

11-
#[derive(Diagnostic)]
12-
#[diag(codegen_llvm_unknown_ctarget_feature_prefix)]
13-
#[note]
14-
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
15-
pub feature: &'a str,
16-
}
17-
18-
#[derive(Diagnostic)]
19-
#[diag(codegen_llvm_unknown_ctarget_feature)]
20-
#[note]
21-
pub(crate) struct UnknownCTargetFeature<'a> {
22-
pub feature: &'a str,
23-
#[subdiagnostic]
24-
pub rust_feature: PossibleFeature<'a>,
25-
}
26-
27-
#[derive(Subdiagnostic)]
28-
pub(crate) enum PossibleFeature<'a> {
29-
#[help(codegen_llvm_possible_feature)]
30-
Some { rust_feature: &'a str },
31-
#[help(codegen_llvm_consider_filing_feature_request)]
32-
None,
33-
}
34-
3511
#[derive(Diagnostic)]
3612
#[diag(codegen_llvm_symbol_already_defined)]
3713
pub(crate) struct SymbolAlreadyDefined<'a> {

0 commit comments

Comments
 (0)