Skip to content
Merged
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
7 changes: 5 additions & 2 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,17 @@ fn write_output_file<'ll>(
result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output }))
}

/// If `for_cfg` is `true` then we are creating this machine for the purpose of populating
/// [`rustc_codegen_ssa::TargetConfig`] based on what LLVM actually enables in this configuration.
/// `-Ctarget-feature` should be ignored in that case since it is already processed separately.
pub(crate) fn create_informational_target_machine(
sess: &Session,
only_base_features: bool,
for_cfg: bool,
) -> OwnedTargetMachine {
let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None };
// Can't use query system here quite yet because this function is invoked before the query
// system/tcx is set up.
let features = llvm_util::global_llvm_features(sess, only_base_features);
let features = llvm_util::global_llvm_features(sess, for_cfg);
target_machine_factory(sess, config::OptLevel::No, &features)(sess.dcx(), config)
}

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_codegen_llvm/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,10 @@ pub(crate) struct IntrinsicWrongArch<'a> {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("ignoring feature with missing prefix in `-Zllvm-target-feature`: `{$feature}`")]
#[note("features must begin with a `+` to enable or `-` to disable it")]
pub(crate) struct UnknownLlvmTargetFeaturePrefix<'a> {
pub feature: &'a str,
}
29 changes: 26 additions & 3 deletions compiler/rustc_codegen_llvm/src/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,11 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec<String>) {

/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
pub(crate) fn global_llvm_features(sess: &Session, only_base_features: bool) -> Vec<String> {
///
/// If `for_cfg` is `true` then we are assembling the feature list for the purpose of populating
/// [`rustc_codegen_ssa::TargetConfig`] based on what LLVM actually enables in this configuration.
/// `-Ctarget-feature` should be ignored in that case since it is already processed separately.
pub(crate) fn global_llvm_features(sess: &Session, for_cfg: bool) -> Vec<String> {
// Features that come earlier are overridden by conflicting features later in the string.
// Typically we'll want more explicit settings to override the implicit ones, so:
//
Expand Down Expand Up @@ -725,14 +729,33 @@ pub(crate) fn global_llvm_features(sess: &Session, only_base_features: bool) ->
// Features implied by an implicit or explicit `--target`.
target_features::target_spec_to_backend_features(sess, &mut extend_backend_features);

// -Ctarget-features
if !only_base_features {
// -Ctarget-features. Skipped for `cfg` as there we parse -Ctarget-features directly instead of
// going via an LLVM target machine (which avoids accidentally picking up LLVM-level target
// feature implications that we do not want).
if !for_cfg {
target_features::flag_to_backend_features(sess, extend_backend_features);
}

// We add this in the "base target" so that these show up in `sess.unstable_target_features`.
llvm_features_by_flags(sess, &mut features);

// `-Zllvm-target-features`, all the way at the end to overwrite everything.
// Should be picked up by `cfg` (e.g. if someone enables AVX this way).
for feature in sess.opts.unstable_opts.llvm_target_feature.split(',') {
if feature.is_empty() {
continue;
}
if feature.starts_with('+') || feature.starts_with('-') {
features.push(feature.to_owned());
} else {
// LLVM seems to silently ignore entries without leading `+`/`-`. Let's emit a warning
// to avoid confusion. But only emit this warning once, under `for_cfg`.
if for_cfg {
sess.dcx().emit_warn(diagnostics::UnknownLlvmTargetFeaturePrefix { feature });
}
}
}

features
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1198,7 +1198,7 @@ pub(crate) struct XcrunSdkPathWarning {
pub(crate) struct Aarch64SoftfloatNeon;

#[derive(Diagnostic)]
#[diag("unknown feature specified for `-Ctarget-feature`: `{$feature}`")]
#[diag("ignoring feature with missing prefix in `-Ctarget-feature`: `{$feature}`")]
#[note("features must begin with a `+` to enable or `-` to disable it")]
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
pub feature: &'a str,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2582,6 +2582,10 @@ options! {
"a list of module flags to pass to LLVM (space separated)"),
llvm_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
"a list LLVM plugins to enable (space separated)"),
llvm_target_feature: String = (String::new(), parse_target_feature, [TRACKED] { TARGET_MODIFIER: LlvmTargetFeature },
"enable/disable LLVM-level target features. \
This feature is unsafe and can cause ABI issues and compiler crashes, \
because LLVM does not support all target feature combinations."),
llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
"generate JSON tracing data file from LLVM data (default: no)"),
llvm_writable: bool = (false, parse_bool, [TRACKED],
Expand Down
32 changes: 32 additions & 0 deletions tests/ui/target-feature/llvm-target-feature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//! Sometimes `-Ctarget-cpu` can *disable* target features that would by default be enabled on the
//! current target. Ensure that we catch the case where those target features are important for the
//! ABI.

//@ compile-flags: --crate-type=lib
//@ compile-flags: --target=x86_64-unknown-linux-gnu
//@ compile-flags: -Zllvm-target-feature=+avx2
//@ needs-llvm-components: x86

//@ build-pass
//@ ignore-backends: gcc
//@ add-minicore

#![feature(no_core, intrinsics, rustc_attrs)]
#![no_core]
#![allow(improper_ctypes_definitions)]

extern crate minicore;
use minicore::*;

// Also test the ABI checks by using `extern "C"`
#[no_mangle] // force codegen
pub extern "C" fn do_thing(x: simd::f32x8, y: simd::f32x8) -> simd::f32x8 {
#[rustc_intrinsic]
#[rustc_nounwind]
pub const unsafe fn simd_add<T>(x: T, y: T) -> T;

unsafe { simd_add(x, y) }
}

#[cfg(not(target_feature = "avx2"))]
compile_error!("the avx2 cfg did not get set");
2 changes: 1 addition & 1 deletion tests/ui/target-feature/missing-plusminus-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
#![feature(no_core)]
#![no_core]

//~? WARN unknown feature specified for `-Ctarget-feature`: `rdrand`
//~? WARN ignoring feature with missing prefix in `-Ctarget-feature`: `rdrand`
2 changes: 1 addition & 1 deletion tests/ui/target-feature/missing-plusminus-2.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
warning: unknown feature specified for `-Ctarget-feature`: `rdrand`
warning: ignoring feature with missing prefix in `-Ctarget-feature`: `rdrand`
|
= note: features must begin with a `+` to enable or `-` to disable it

Expand Down
13 changes: 13 additions & 0 deletions tests/ui/target-feature/missing-plusminus-llvm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//@ compile-flags: -Zllvm-target-feature=banana --crate-type=rlib
//@ build-pass

//@ ignore-backends: gcc
//@ add-minicore

#![feature(no_core, intrinsics, rustc_attrs)]
#![no_core]

extern crate minicore;
use minicore::*;

//~? WARN ignoring feature with missing prefix in `-Zllvm-target-feature`: `banana`
6 changes: 6 additions & 0 deletions tests/ui/target-feature/missing-plusminus-llvm.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
warning: ignoring feature with missing prefix in `-Zllvm-target-feature`: `banana`
|
= note: features must begin with a `+` to enable or `-` to disable it

warning: 1 warning emitted

2 changes: 1 addition & 1 deletion tests/ui/target-feature/missing-plusminus.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ compile-flags: -Ctarget-feature=banana --crate-type=rlib
//@ build-pass

//~? WARN unknown feature specified for `-Ctarget-feature`: `banana`
//~? WARN ignoring feature with missing prefix in `-Ctarget-feature`: `banana`
2 changes: 1 addition & 1 deletion tests/ui/target-feature/missing-plusminus.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
warning: unknown feature specified for `-Ctarget-feature`: `banana`
warning: ignoring feature with missing prefix in `-Ctarget-feature`: `banana`
|
= note: features must begin with a `+` to enable or `-` to disable it

Expand Down
Loading