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
5 changes: 3 additions & 2 deletions compiler/rustc_interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use rustc_session::parse::ParseSess;
use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, lint};
use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs};
use rustc_span::{FileName, sym};
use rustc_target::spec::Target;
use tracing::trace;

use crate::util;
Expand Down Expand Up @@ -385,7 +386,7 @@ pub struct Config {
/// custom driver where the custom codegen backend has arbitrary data."
/// (See #102759.)
pub make_codegen_backend:
Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
Option<Box<dyn FnOnce(&config::Options, &Target) -> Box<dyn CodegenBackend> + Send>>,

/// Registry of diagnostics codes.
pub registry: Registry,
Expand Down Expand Up @@ -453,7 +454,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
Some(make_codegen_backend) => {
// N.B. `make_codegen_backend` takes precedence over
// `target.default_codegen_backend`, which is ignored in this case.
make_codegen_backend(&config.opts)
make_codegen_backend(&config.opts, &target)
}
};

Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_interface/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ pub fn get_codegen_backend(
filename if filename.contains('.') => {
load_backend_from_dylib(early_dcx, filename.as_ref())
}
"dummy" => || Box::new(DummyCodegenBackend),
"dummy" => || Box::new(DummyCodegenBackend { target_config_override: None }),
#[cfg(feature = "llvm")]
"llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
backend_name => get_codegen_sysroot(early_dcx, sysroot, backend_name),
Expand All @@ -352,7 +352,9 @@ pub fn get_codegen_backend(
unsafe { load() }
}

struct DummyCodegenBackend;
pub struct DummyCodegenBackend {
pub target_config_override: Option<Box<dyn Fn(&Session) -> TargetConfig>>,
}

impl CodegenBackend for DummyCodegenBackend {
fn locale_resource(&self) -> &'static str {
Expand All @@ -364,6 +366,10 @@ impl CodegenBackend for DummyCodegenBackend {
}

fn target_config(&self, sess: &Session) -> TargetConfig {
if let Some(target_config_override) = &self.target_config_override {
return target_config_override(sess);
}

let abi_required_features = sess.target.abi_required_features();
let (target_features, unstable_target_features) = cfg_target_feature::<0>(
sess,
Expand Down
160 changes: 98 additions & 62 deletions src/tools/miri/src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

// The rustc crates we need
extern crate rustc_abi;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_hir;
Expand All @@ -19,6 +20,7 @@ extern crate rustc_log;
extern crate rustc_middle;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;

/// See docs in https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc/src/main.rs
/// and https://github.com/rust-lang/rust/pull/146627 for why we need this.
Expand All @@ -36,19 +38,22 @@ use std::num::{NonZero, NonZeroI32};
use std::ops::Range;
use std::rc::Rc;
use std::str::FromStr;
use std::sync::Once;
use std::sync::atomic::{AtomicU32, Ordering};

use miri::{
BacktraceStyle, BorrowTrackerMethod, GenmcConfig, GenmcCtx, MiriConfig, MiriEntryFnType,
ProvenanceMode, TreeBorrowsParams, ValidationMode, run_genmc_mode,
};
use rustc_abi::ExternAbi;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::sync::{self, DynSync};
use rustc_driver::Compilation;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::{self as hir, Node};
use rustc_hir_analysis::check::check_function_signature;
use rustc_interface::interface::Config;
use rustc_interface::util::DummyCodegenBackend;
use rustc_log::tracing::debug;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::exported_symbols::{
Expand All @@ -58,8 +63,9 @@ use rustc_middle::query::LocalCrate;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::EarlyDiagCtxt;
use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
use rustc_session::config::{CrateType, ErrorOutputType, OptLevel, Options};
use rustc_span::def_id::DefId;
use rustc_target::spec::Target;

use crate::log::setup::{deinit_loggers, init_early_loggers, init_late_loggers};

Expand Down Expand Up @@ -161,7 +167,31 @@ fn run_many_seeds(
}
}

/// Generates the codegen backend for code that Miri will interpret: we basically
/// use the dummy backend, except that we put the LLVM backend in charge of
/// target features.
fn make_miri_codegen_backend(opts: &Options, target: &Target) -> Box<dyn CodegenBackend> {
let early_dcx = EarlyDiagCtxt::new(opts.error_format);

// Use the target_config method of the default codegen backend (eg LLVM) to ensure the
// calculated target features match said backend by respecting eg -Ctarget-cpu.
let target_config_backend =
rustc_interface::util::get_codegen_backend(&early_dcx, &opts.sysroot, None, &target);
let target_config_backend_init = Once::new();

Box::new(DummyCodegenBackend {
target_config_override: Some(Box::new(move |sess| {
target_config_backend_init.call_once(|| target_config_backend.init(sess));
target_config_backend.target_config(sess)
})),
})
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
fn config(&mut self, config: &mut rustc_interface::interface::Config) {
config.make_codegen_backend = Some(Box::new(make_miri_codegen_backend));
}

fn after_analysis<'tcx>(
&mut self,
_: &rustc_interface::interface::Compiler,
Expand Down Expand Up @@ -244,11 +274,20 @@ struct MiriBeRustCompilerCalls {
impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
#[allow(rustc::potential_query_instability)] // rustc_codegen_ssa (where this code is copied from) also allows this lint
fn config(&mut self, config: &mut Config) {
if config.opts.prints.is_empty() && self.target_crate {
if !self.target_crate {
// For a host crate, we fully behave like rustc.
return;
}
// For a target crate, we emit an rlib that Miri can later consume.
config.make_codegen_backend = Some(Box::new(make_miri_codegen_backend));

// Avoid warnings about unsupported crate types. However, only do that we we are *not* being
// queried by cargo about the supported crate types so that cargo still receives the
// warnings it expects.
if config.opts.prints.is_empty() {
#[allow(rustc::bad_opt_access)] // tcx does not exist yet
{
let any_crate_types = !config.opts.crate_types.is_empty();
// Avoid warnings about unsupported crate types.
config
.opts
.crate_types
Expand All @@ -259,66 +298,63 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
assert!(!config.opts.crate_types.is_empty());
}
}

// Queries overridden here affect the data stored in `rmeta` files of dependencies,
// which will be used later in non-`MIRI_BE_RUSTC` mode.
config.override_queries = Some(|_, local_providers| {
// We need to add #[used] symbols to exported_symbols for `lookup_link_section`.
// FIXME handle this somehow in rustc itself to avoid this hack.
local_providers.exported_non_generic_symbols = |tcx, LocalCrate| {
let reachable_set = tcx.with_stable_hashing_context(|hcx| {
tcx.reachable_set(()).to_sorted(&hcx, true)
});
tcx.arena.alloc_from_iter(
// This is based on:
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174
reachable_set.into_iter().filter_map(|&local_def_id| {
// Do the same filtering that rustc does:
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102
// Otherwise it may cause unexpected behaviours and ICEs
// (https://github.com/rust-lang/rust/issues/86261).
let is_reachable_non_generic = matches!(
tcx.hir_node_by_def_id(local_def_id),
Node::Item(&hir::Item {
kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn{ .. },
..
}) | Node::ImplItem(&hir::ImplItem {
kind: hir::ImplItemKind::Fn(..),
..
})
if !tcx.generics_of(local_def_id).requires_monomorphization(tcx)
);
if !is_reachable_non_generic {
return None;
}
let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id);
if codegen_fn_attrs.contains_extern_indicator()
|| codegen_fn_attrs
.flags
.contains(CodegenFnAttrFlags::USED_COMPILER)
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
{
Some((
ExportedSymbol::NonGeneric(local_def_id.to_def_id()),
// Some dummy `SymbolExportInfo` here. We only use
// `exported_symbols` in shims/foreign_items.rs and the export info
// is ignored.
SymbolExportInfo {
level: SymbolExportLevel::C,
kind: SymbolExportKind::Text,
used: false,
rustc_std_internal_symbol: false,
},
))
} else {
None
}
}),
)
}
});
}

// Queries overridden here affect the data stored in `rmeta` files of dependencies,
// which will be used later in non-`MIRI_BE_RUSTC` mode.
config.override_queries = Some(|_, local_providers| {
// We need to add #[used] symbols to exported_symbols for `lookup_link_section`.
// FIXME handle this somehow in rustc itself to avoid this hack.
local_providers.exported_non_generic_symbols = |tcx, LocalCrate| {
let reachable_set = tcx
.with_stable_hashing_context(|hcx| tcx.reachable_set(()).to_sorted(&hcx, true));
tcx.arena.alloc_from_iter(
// This is based on:
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174
reachable_set.into_iter().filter_map(|&local_def_id| {
// Do the same filtering that rustc does:
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102
// Otherwise it may cause unexpected behaviours and ICEs
// (https://github.com/rust-lang/rust/issues/86261).
let is_reachable_non_generic = matches!(
tcx.hir_node_by_def_id(local_def_id),
Node::Item(&hir::Item {
kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn{ .. },
..
}) | Node::ImplItem(&hir::ImplItem {
kind: hir::ImplItemKind::Fn(..),
..
})
if !tcx.generics_of(local_def_id).requires_monomorphization(tcx)
);
if !is_reachable_non_generic {
return None;
}
let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id);
if codegen_fn_attrs.contains_extern_indicator()
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
{
Some((
ExportedSymbol::NonGeneric(local_def_id.to_def_id()),
// Some dummy `SymbolExportInfo` here. We only use
// `exported_symbols` in shims/foreign_items.rs and the export info
// is ignored.
SymbolExportInfo {
level: SymbolExportLevel::C,
kind: SymbolExportKind::Text,
used: false,
rustc_std_internal_symbol: false,
},
))
} else {
None
}
}),
)
}
});
}

fn after_analysis<'tcx>(
Expand Down
1 change: 0 additions & 1 deletion src/tools/miri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ pub use crate::shims::unwind::{CatchUnwindData, EvalContextExt as _};
/// Also disable the MIR pass that inserts an alignment check on every pointer dereference. Miri
/// does that too, and with a better error message.
pub const MIRI_DEFAULT_ARGS: &[&str] = &[
"-Zcodegen-backend=dummy",
"--cfg=miri",
"-Zalways-encode-mir",
"-Zextra-const-ub-checks",
Expand Down
16 changes: 16 additions & 0 deletions src/tools/miri/tests/pass/target-cpu-implies-target-feature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Test that target-cpu implies the correct target features
//@only-target: x86_64
//@compile-flags: -C target-cpu=x86-64-v4

fn main() {
assert!(cfg!(target_feature = "avx2"));
assert!(cfg!(target_feature = "avx512bw"));
assert!(cfg!(target_feature = "avx512cd"));
assert!(cfg!(target_feature = "avx512dq"));
assert!(cfg!(target_feature = "avx512f"));
assert!(cfg!(target_feature = "avx512vl"));
assert!(is_x86_feature_detected!("avx512bw"));

assert!(cfg!(not(target_feature = "avx512vpopcntdq")));
assert!(!is_x86_feature_detected!("avx512vpopcntdq"));
}
Loading