Skip to content

Commit 7550062

Browse files
committed
codegen_ssa: consolidate tied feature checking
`rustc_codegen_llvm` and `rustc_codegen_gcc` duplicated logic for checking if tied target features were partially enabled. This commit consolidates these checks into `rustc_codegen_ssa` in the `codegen_fn_attrs` query, which also is run pre-monomorphisation for each function, which ensures that this check is run for unused functions, as would be expected.
1 parent 925af7a commit 7550062

File tree

13 files changed

+98
-163
lines changed

13 files changed

+98
-163
lines changed

compiler/rustc_codegen_gcc/messages.ftl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ codegen_gcc_invalid_minimum_alignment =
88
codegen_gcc_lto_not_supported =
99
LTO is not supported. You may get a linker error.
1010
11-
codegen_gcc_tied_target_features = the target features {$features} must all be either enabled or disabled together
12-
.help = add the missing features in a `target_feature` attribute
13-
1411
codegen_gcc_unwinding_inline_asm =
1512
GCC backend does not support unwinding from inline asm
1613

compiler/rustc_codegen_gcc/src/attributes.rs

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ use rustc_attr::InstructionSetAttr;
77
#[cfg(feature = "master")]
88
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
99
use rustc_middle::ty;
10-
use rustc_span::symbol::sym;
1110

1211
use crate::context::CodegenCx;
13-
use crate::errors::TiedTargetFeatures;
14-
use crate::gcc_util::{check_tied_features, to_gcc_features};
12+
use crate::gcc_util::to_gcc_features;
1513

1614
/// Get GCC attribute for the provided inline heuristic.
1715
#[cfg(feature = "master")]
@@ -72,26 +70,10 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
7270
}
7371
}
7472

75-
let function_features = codegen_fn_attrs
73+
let mut function_features = codegen_fn_attrs
7674
.target_features
7775
.iter()
7876
.map(|features| features.name.as_str())
79-
.collect::<Vec<&str>>();
80-
81-
if let Some(features) = check_tied_features(
82-
cx.tcx.sess,
83-
&function_features.iter().map(|features| (*features, true)).collect(),
84-
) {
85-
let span = cx
86-
.tcx
87-
.get_attr(instance.def_id(), sym::target_feature)
88-
.map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
89-
cx.tcx.dcx().create_err(TiedTargetFeatures { features: features.join(", "), span }).emit();
90-
return;
91-
}
92-
93-
let mut function_features = function_features
94-
.iter()
9577
.flat_map(|feat| to_gcc_features(cx.tcx.sess, feat).into_iter())
9678
.chain(codegen_fn_attrs.instruction_set.iter().map(|x| match *x {
9779
InstructionSetAttr::ArmA32 => "-thumb-mode", // TODO(antoyo): support removing feature.

compiler/rustc_codegen_gcc/src/errors.rs

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
21
use rustc_macros::{Diagnostic, Subdiagnostic};
32
use rustc_span::Span;
43

5-
use crate::fluent_generated as fluent;
6-
74
#[derive(Diagnostic)]
85
#[diag(codegen_gcc_unknown_ctarget_feature_prefix)]
96
#[note]
@@ -45,15 +42,6 @@ pub(crate) struct InvalidMinimumAlignment {
4542
pub err: String,
4643
}
4744

48-
#[derive(Diagnostic)]
49-
#[diag(codegen_gcc_tied_target_features)]
50-
#[help]
51-
pub(crate) struct TiedTargetFeatures {
52-
#[primary_span]
53-
pub span: Span,
54-
pub features: String,
55-
}
56-
5745
#[derive(Diagnostic)]
5846
#[diag(codegen_gcc_copy_bitcode)]
5947
pub(crate) struct CopyBitcode {
@@ -78,27 +66,3 @@ pub(crate) struct LtoDylib;
7866
pub(crate) struct LtoBitcodeFromRlib {
7967
pub gcc_err: String,
8068
}
81-
82-
pub(crate) struct TargetFeatureDisableOrEnable<'a> {
83-
pub features: &'a [&'a str],
84-
pub span: Option<Span>,
85-
pub missing_features: Option<MissingFeatures>,
86-
}
87-
88-
#[derive(Subdiagnostic)]
89-
#[help(codegen_gcc_missing_features)]
90-
pub(crate) struct MissingFeatures;
91-
92-
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
93-
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
94-
let mut diag = Diag::new(dcx, level, fluent::codegen_gcc_target_feature_disable_or_enable);
95-
if let Some(span) = self.span {
96-
diag.span(span);
97-
};
98-
if let Some(missing_features) = self.missing_features {
99-
diag.subdiagnostic(missing_features);
100-
}
101-
diag.arg("features", self.features.join(", "));
102-
diag
103-
}
104-
}

compiler/rustc_codegen_gcc/src/gcc_util.rs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
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;
35
use rustc_data_structures::fx::FxHashMap;
46
use rustc_middle::bug;
57
use rustc_session::Session;
68
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
79
use smallvec::{smallvec, SmallVec};
810

9-
use crate::errors::{
10-
PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature,
11-
UnknownCTargetFeaturePrefix,
12-
};
11+
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
1312

1413
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
1514
/// `--target` and similar).
@@ -185,23 +184,6 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]>
185184
}
186185
}
187186

188-
// Given a map from target_features to whether they are enabled or disabled,
189-
// ensure only valid combinations are allowed.
190-
pub fn check_tied_features(
191-
sess: &Session,
192-
features: &FxHashMap<&str, bool>,
193-
) -> Option<&'static [&'static str]> {
194-
for tied in sess.target.tied_target_features() {
195-
// Tied features must be set to the same value, or not set at all
196-
let mut tied_iter = tied.iter();
197-
let enabled = features.get(tied_iter.next().unwrap());
198-
if tied_iter.any(|feature| enabled != features.get(feature)) {
199-
return Some(tied);
200-
}
201-
}
202-
None
203-
}
204-
205187
fn arch_to_gcc(name: &str) -> &str {
206188
match name {
207189
"M68020" => "68020",

compiler/rustc_codegen_llvm/messages.ftl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ codegen_llvm_lto_proc_macro = lto cannot be used for `proc-macro` crate type wit
3333
codegen_llvm_mismatch_data_layout =
3434
data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}`
3535
36-
codegen_llvm_missing_features =
37-
add the missing features in a `target_feature` attribute
38-
3936
codegen_llvm_multiple_source_dicompileunit = multiple source DICompileUnits found
4037
codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err}
4138
@@ -63,9 +60,6 @@ codegen_llvm_serialize_module_with_llvm_err = failed to serialize module {$name}
6360
codegen_llvm_symbol_already_defined =
6461
symbol `{$symbol_name}` is already defined
6562
66-
codegen_llvm_target_feature_disable_or_enable =
67-
the target features {$features} must all be either enabled or disabled together
68-
6963
codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
7064
codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
7165

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ use rustc_hir::def_id::DefId;
66
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
77
use rustc_middle::ty::{self, TyCtxt};
88
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
9-
use rustc_span::symbol::sym;
109
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
1110
use smallvec::SmallVec;
1211

1312
use crate::context::CodegenCx;
14-
use crate::errors::{MissingFeatures, SanitizerMemtagRequiresMte, TargetFeatureDisableOrEnable};
13+
use crate::errors::SanitizerMemtagRequiresMte;
1514
use crate::llvm::AttributePlace::Function;
1615
use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects};
1716
use crate::value::Value;
@@ -503,26 +502,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
503502
let function_features =
504503
codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
505504

506-
if let Some(f) = llvm_util::check_tied_features(
507-
cx.tcx.sess,
508-
&function_features.iter().map(|f| (*f, true)).collect(),
509-
) {
510-
let span = cx
511-
.tcx
512-
.get_attrs(instance.def_id(), sym::target_feature)
513-
.next()
514-
.map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
515-
cx.tcx
516-
.dcx()
517-
.create_err(TargetFeatureDisableOrEnable {
518-
features: f,
519-
span: Some(span),
520-
missing_features: Some(MissingFeatures),
521-
})
522-
.emit();
523-
return;
524-
}
525-
526505
let function_features = function_features
527506
.iter()
528507
// Convert to LLVMFeatures and filter out unavailable ones

compiler/rustc_codegen_llvm/src/errors.rs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -80,30 +80,6 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> {
8080
}
8181
}
8282

83-
pub(crate) struct TargetFeatureDisableOrEnable<'a> {
84-
pub features: &'a [&'a str],
85-
pub span: Option<Span>,
86-
pub missing_features: Option<MissingFeatures>,
87-
}
88-
89-
#[derive(Subdiagnostic)]
90-
#[help(codegen_llvm_missing_features)]
91-
pub(crate) struct MissingFeatures;
92-
93-
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> {
94-
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
95-
let mut diag = Diag::new(dcx, level, fluent::codegen_llvm_target_feature_disable_or_enable);
96-
if let Some(span) = self.span {
97-
diag.span(span);
98-
};
99-
if let Some(missing_features) = self.missing_features {
100-
diag.subdiagnostic(missing_features);
101-
}
102-
diag.arg("features", self.features.join(", "));
103-
diag
104-
}
105-
}
106-
10783
#[derive(Diagnostic)]
10884
#[diag(codegen_llvm_lto_disallowed)]
10985
pub(crate) struct LtoDisallowed;

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{ptr, slice, str};
66

77
use libc::c_int;
88
use rustc_codegen_ssa::base::wants_wasm_eh;
9+
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
910
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1011
use rustc_data_structures::small_c_str::SmallCStr;
1112
use rustc_data_structures::unord::UnordSet;
@@ -19,8 +20,8 @@ use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATU
1920

2021
use crate::back::write::create_informational_target_machine;
2122
use crate::errors::{
22-
FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable,
23-
UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
23+
FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, UnknownCTargetFeature,
24+
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
2425
};
2526
use crate::llvm;
2627

@@ -286,25 +287,6 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
286287
}
287288
}
288289

289-
/// Given a map from target_features to whether they are enabled or disabled,
290-
/// ensure only valid combinations are allowed.
291-
pub(crate) fn check_tied_features(
292-
sess: &Session,
293-
features: &FxHashMap<&str, bool>,
294-
) -> Option<&'static [&'static str]> {
295-
if !features.is_empty() {
296-
for tied in sess.target.tied_target_features() {
297-
// Tied features must be set to the same value, or not set at all
298-
let mut tied_iter = tied.iter();
299-
let enabled = features.get(tied_iter.next().unwrap());
300-
if tied_iter.any(|f| enabled != features.get(f)) {
301-
return Some(tied);
302-
}
303-
}
304-
}
305-
None
306-
}
307-
308290
/// Used to generate cfg variables and apply features
309291
/// Must express features in the way Rust understands them
310292
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
@@ -696,7 +678,7 @@ pub(crate) fn global_llvm_features(
696678
features.extend(feats);
697679

698680
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
699-
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
681+
sess.dcx().emit_err(rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable {
700682
features: f,
701683
span: None,
702684
missing_features: None,

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ codegen_ssa_metadata_object_file_write = error writing metadata object file: {$e
183183
184184
codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
185185
186+
codegen_ssa_missing_features = add the missing features in a `target_feature` attribute
187+
186188
codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
187189
188190
codegen_ssa_missing_query_depgraph =
@@ -238,6 +240,9 @@ codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` fa
238240
239241
codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
240242
243+
codegen_ssa_target_feature_disable_or_enable =
244+
the target features {$features} must all be either enabled or disabled together
245+
241246
codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method
242247
.label = cannot be applied to safe trait method
243248
.label_def = not an `unsafe` function

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem};
22
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
3+
use rustc_data_structures::fx::FxHashMap;
34
use rustc_errors::codes::*;
45
use rustc_errors::{struct_span_code_err, DiagMessage, SubdiagMessage};
56
use rustc_hir as hir;
@@ -13,13 +14,13 @@ use rustc_middle::middle::codegen_fn_attrs::{
1314
use rustc_middle::mir::mono::Linkage;
1415
use rustc_middle::query::Providers;
1516
use rustc_middle::ty::{self as ty, TyCtxt};
16-
use rustc_session::lint;
1717
use rustc_session::parse::feature_err;
18+
use rustc_session::{lint, Session};
1819
use rustc_span::symbol::Ident;
1920
use rustc_span::{sym, Span};
2021
use rustc_target::spec::{abi, SanitizerSet};
2122

22-
use crate::errors;
23+
use crate::errors::{self, MissingFeatures, TargetFeatureDisableOrEnable};
2324
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature};
2425

2526
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
@@ -680,9 +681,47 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
680681
}
681682
}
682683

684+
if let Some(features) = check_tied_features(
685+
tcx.sess,
686+
&codegen_fn_attrs
687+
.target_features
688+
.iter()
689+
.map(|features| (features.name.as_str(), true))
690+
.collect(),
691+
) {
692+
let span =
693+
tcx.get_attr(did, sym::target_feature).map_or_else(|| tcx.def_span(did), |a| a.span);
694+
tcx.dcx()
695+
.create_err(TargetFeatureDisableOrEnable {
696+
features,
697+
span: Some(span),
698+
missing_features: Some(MissingFeatures),
699+
})
700+
.emit();
701+
}
702+
683703
codegen_fn_attrs
684704
}
685705

706+
/// Given a map from target_features to whether they are enabled or disabled, ensure only valid
707+
/// combinations are allowed.
708+
pub fn check_tied_features(
709+
sess: &Session,
710+
features: &FxHashMap<&str, bool>,
711+
) -> Option<&'static [&'static str]> {
712+
if !features.is_empty() {
713+
for tied in sess.target.tied_target_features() {
714+
// Tied features must be set to the same value, or not set at all
715+
let mut tied_iter = tied.iter();
716+
let enabled = features.get(tied_iter.next().unwrap());
717+
if tied_iter.any(|f| enabled != features.get(f)) {
718+
return Some(tied);
719+
}
720+
}
721+
}
722+
None
723+
}
724+
686725
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
687726
/// applied to the method prototype.
688727
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {

0 commit comments

Comments
 (0)