Skip to content

Extract some shared code from codegen backend target feature handling #140920

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions compiler/rustc_codegen_gcc/messages.ftl
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
codegen_gcc_unknown_ctarget_feature_prefix =
unknown feature specified for `-Ctarget-feature`: `{$feature}`
.note = features must begin with a `+` to enable or `-` to disable it

codegen_gcc_invalid_minimum_alignment =
invalid minimum global alignment: {$err}

codegen_gcc_forbidden_ctarget_feature =
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}

codegen_gcc_unwinding_inline_asm =
GCC backend does not support unwinding from inline asm

Expand All @@ -22,19 +15,3 @@ codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and st
codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`

codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err})

codegen_gcc_unknown_ctarget_feature =
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
.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
.possible_feature = you might have meant: `{$rust_feature}`
.consider_filing_feature_request = consider filing a feature request

codegen_gcc_unstable_ctarget_feature =
unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = this feature is not stably supported; its behavior can change in the future

codegen_gcc_missing_features =
add the missing features in a `target_feature` attribute

codegen_gcc_target_feature_disable_or_enable =
the target features {$features} must all be either enabled or disabled together
41 changes: 1 addition & 40 deletions compiler/rustc_codegen_gcc/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,6 @@
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_macros::Diagnostic;
use rustc_span::Span;

#[derive(Diagnostic)]
#[diag(codegen_gcc_unknown_ctarget_feature_prefix)]
#[note]
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
pub feature: &'a str,
}

#[derive(Diagnostic)]
#[diag(codegen_gcc_unknown_ctarget_feature)]
#[note]
pub(crate) struct UnknownCTargetFeature<'a> {
pub feature: &'a str,
#[subdiagnostic]
pub rust_feature: PossibleFeature<'a>,
}

#[derive(Diagnostic)]
#[diag(codegen_gcc_unstable_ctarget_feature)]
#[note]
pub(crate) struct UnstableCTargetFeature<'a> {
pub feature: &'a str,
}

#[derive(Diagnostic)]
#[diag(codegen_gcc_forbidden_ctarget_feature)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}

#[derive(Subdiagnostic)]
pub(crate) enum PossibleFeature<'a> {
#[help(codegen_gcc_possible_feature)]
Some { rust_feature: &'a str },
#[help(codegen_gcc_consider_filing_feature_request)]
None,
}

#[derive(Diagnostic)]
#[diag(codegen_gcc_unwinding_inline_asm)]
pub(crate) struct UnwindingInlineAsm {
Expand Down
127 changes: 18 additions & 109 deletions compiler/rustc_codegen_gcc/src/gcc_util.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
#[cfg(feature = "master")]
use gccjit::Context;
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unord::UnordSet;
use rustc_middle::target_features;
use rustc_session::Session;
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
use smallvec::{SmallVec, smallvec};

use crate::errors::{
ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
UnstableCTargetFeature,
};

/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<String> {
Expand Down Expand Up @@ -40,109 +31,27 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));

// -Ctarget-features
let known_features = sess.target.rust_target_features();
let mut featsmap = FxHashMap::default();

// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',') {
if let Some(feature) = feature.strip_prefix('+') {
all_rust_features.extend(
UnordSet::from(sess.target.implied_target_features(feature))
.to_sorted_stable_ord()
.iter()
.map(|&&s| (true, s)),
)
} else if let Some(feature) = feature.strip_prefix('-') {
// FIXME: Why do we not remove implied features on "-" here?
// We do the equivalent above in `target_config`.
// See <https://github.com/rust-lang/rust/issues/134792>.
all_rust_features.push((false, feature));
} else if !feature.is_empty() && diagnostics {
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
}
}
// Remove features that are meant for rustc, not codegen.
all_rust_features.retain(|&(_, feature)| {
// Retain if it is not a rustc feature
!RUSTC_SPECIFIC_FEATURES.contains(&feature)
});

// Check feature validity.
if diagnostics {
for &(enable, feature) in &all_rust_features {
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
match feature_state {
None => {
let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| {
let gcc_features = to_gcc_features(sess, rust_feature);
if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature)
{
Some(rust_feature)
} else {
None
}
});
let unknown_feature = if let Some(rust_feature) = rust_feature {
UnknownCTargetFeature {
feature,
rust_feature: PossibleFeature::Some { rust_feature },
}
} else {
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
};
sess.dcx().emit_warn(unknown_feature);
}
Some(&(_, stability, _)) => {
if let Err(reason) = stability.toggle_allowed() {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: if enable { "enabled" } else { "disabled" },
reason,
});
} else if stability.requires_nightly().is_some() {
// An unstable feature. Warn about using it. (It makes little sense
// to hard-error here since we just warn about fully unknown
// features above).
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
}
}
}

// FIXME(nagisa): figure out how to not allocate a full hashset here.
featsmap.insert(feature, enable);
}
}

// Translate this into GCC features.
let feats =
all_rust_features.iter().flat_map(|&(enable, feature)| {
let enable_disable = if enable { '+' } else { '-' };
target_features::flag_to_backend_features(
sess,
diagnostics,
|feature| to_gcc_features(sess, feature),
|feature, enable| {
// We run through `to_gcc_features` when
// passing requests down to GCC. This means that all in-language
// features also work on the command line instead of having two
// different names when the GCC name and the Rust name differ.
to_gcc_features(sess, feature)
.iter()
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
.map(|feature| {
if enable_disable == '-' {
format!("-{}", feature)
} else {
feature.to_string()
}
})
.collect::<Vec<_>>()
});
features.extend(feats);

if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
features: f,
span: None,
missing_features: None,
});
}
features.extend(
to_gcc_features(sess, feature)
.iter()
.flat_map(|feat| to_gcc_features(sess, feat).into_iter())
.map(
|feature| {
if !enable { format!("-{}", feature) } else { feature.to_string() }
},
),
);
},
);

features
}
Expand Down
48 changes: 14 additions & 34 deletions compiler/rustc_codegen_gcc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ use rustc_data_structures::sync::IntoDynSyncSend;
use rustc_errors::DiagCtxtHandle;
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::target_features;
use rustc_middle::ty::TyCtxt;
use rustc_middle::util::Providers;
use rustc_session::Session;
Expand Down Expand Up @@ -486,40 +487,19 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {

/// Returns the features that should be set in `cfg(target_feature)`.
fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig {
// TODO(antoyo): use global_gcc_features.
let f = |allow_unstable| {
sess.target
.rust_target_features()
.iter()
.filter_map(|&(feature, gate, _)| {
if allow_unstable
|| (gate.in_cfg()
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
{
Some(feature)
} else {
None
}
})
.filter(|feature| {
// TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
if *feature == "neon" {
return false;
}
target_info.cpu_supports(feature)
/*
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
*/
})
.map(Symbol::intern)
.collect()
};

let target_features = f(false);
let unstable_target_features = f(true);
let (unstable_target_features, target_features) = target_features::cfg(sess, |feature| {
// TODO: we disable Neon for now since we don't support the LLVM intrinsics for it.
if feature == "neon" {
return false;
}
target_info.cpu_supports(feature)
/*
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
*/
});

TargetConfig {
target_features,
Expand Down
19 changes: 0 additions & 19 deletions compiler/rustc_codegen_llvm/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ codegen_llvm_dynamic_linking_with_lto =

codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture

codegen_llvm_forbidden_ctarget_feature =
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>

codegen_llvm_from_llvm_diag = {$message}

codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
Expand Down Expand Up @@ -70,22 +65,8 @@ codegen_llvm_symbol_already_defined =
codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}

codegen_llvm_unknown_ctarget_feature =
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
.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
.possible_feature = you might have meant: `{$rust_feature}`
.consider_filing_feature_request = consider filing a feature request

codegen_llvm_unknown_ctarget_feature_prefix =
unknown feature specified for `-Ctarget-feature`: `{$feature}`
.note = features must begin with a `+` to enable or `-` to disable it

codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo

codegen_llvm_unstable_ctarget_feature =
unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = this feature is not stably supported; its behavior can change in the future

codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}

codegen_llvm_write_ir = failed to write LLVM IR to {$path}
Expand Down
43 changes: 1 addition & 42 deletions compiler/rustc_codegen_llvm/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,11 @@ use std::path::Path;

use rustc_data_structures::small_c_str::SmallCStr;
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_macros::Diagnostic;
use rustc_span::Span;

use crate::fluent_generated as fluent;

#[derive(Diagnostic)]
#[diag(codegen_llvm_unknown_ctarget_feature_prefix)]
#[note]
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
pub feature: &'a str,
}

#[derive(Diagnostic)]
#[diag(codegen_llvm_unknown_ctarget_feature)]
#[note]
pub(crate) struct UnknownCTargetFeature<'a> {
pub feature: &'a str,
#[subdiagnostic]
pub rust_feature: PossibleFeature<'a>,
}

#[derive(Diagnostic)]
#[diag(codegen_llvm_unstable_ctarget_feature)]
#[note]
pub(crate) struct UnstableCTargetFeature<'a> {
pub feature: &'a str,
}

#[derive(Diagnostic)]
#[diag(codegen_llvm_forbidden_ctarget_feature)]
#[note]
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}

#[derive(Subdiagnostic)]
pub(crate) enum PossibleFeature<'a> {
#[help(codegen_llvm_possible_feature)]
Some { rust_feature: &'a str },
#[help(codegen_llvm_consider_filing_feature_request)]
None,
}

#[derive(Diagnostic)]
#[diag(codegen_llvm_symbol_already_defined)]
pub(crate) struct SymbolAlreadyDefined<'a> {
Expand Down
Loading
Loading