1
Fork 0

Rollup merge of #116793 - WaffleLapkin:target_rules_the_backend, r=cjgillot

Allow targets to override default codegen backend

Implements https://github.com/rust-lang/compiler-team/issues/670.
This commit is contained in:
Jubilee 2024-03-11 09:29:32 -07:00 committed by GitHub
commit 86af4d25a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 117 additions and 59 deletions

View file

@ -37,7 +37,7 @@ use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType}; use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType};
use rustc_session::getopts::{self, Matches}; use rustc_session::getopts::{self, Matches};
use rustc_session::lint::{Lint, LintId}; use rustc_session::lint::{Lint, LintId};
use rustc_session::{config, EarlyDiagCtxt, Session}; use rustc_session::{config, filesearch, EarlyDiagCtxt, Session};
use rustc_span::def_id::LOCAL_CRATE; use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::source_map::FileLoader; use rustc_span::source_map::FileLoader;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
@ -887,7 +887,11 @@ pub fn version_at_macro_invocation(
let debug_flags = matches.opt_strs("Z"); let debug_flags = matches.opt_strs("Z");
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
get_codegen_backend(early_dcx, &None, backend_name).print_version(); let opts = config::Options::default();
let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone());
let target = config::build_target_config(early_dcx, &opts, None, &sysroot);
get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_version();
} }
} }
@ -1092,7 +1096,12 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) ->
if cg_flags.iter().any(|x| *x == "passes=list") { if cg_flags.iter().any(|x| *x == "passes=list") {
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
get_codegen_backend(early_dcx, &None, backend_name).print_passes();
let opts = config::Options::default();
let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone());
let target = config::build_target_config(early_dcx, &opts, None, &sysroot);
get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_passes();
return true; return true;
} }

View file

@ -16,7 +16,7 @@ use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt; use rustc_query_impl::QueryCtxt;
use rustc_query_system::query::print_query_stack; use rustc_query_system::query::print_query_stack;
use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName};
use rustc_session::filesearch::sysroot_candidates; use rustc_session::filesearch::{self, sysroot_candidates};
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_session::{lint, CompilerIO, EarlyDiagCtxt, Session}; use rustc_session::{lint, CompilerIO, EarlyDiagCtxt, Session};
use rustc_span::source_map::FileLoader; use rustc_span::source_map::FileLoader;
@ -339,16 +339,53 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
let early_dcx = EarlyDiagCtxt::new(config.opts.error_format); let early_dcx = EarlyDiagCtxt::new(config.opts.error_format);
let codegen_backend = if let Some(make_codegen_backend) = config.make_codegen_backend { let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone());
make_codegen_backend(&config.opts)
} else { let (codegen_backend, target_override) = match config.make_codegen_backend {
util::get_codegen_backend( None => {
&early_dcx, // Build a target without override, so that it can override the backend if needed
&config.opts.maybe_sysroot, let target =
config.opts.unstable_opts.codegen_backend.as_deref(), config::build_target_config(&early_dcx, &config.opts, None, &sysroot);
)
let backend = util::get_codegen_backend(
&early_dcx,
&sysroot,
config.opts.unstable_opts.codegen_backend.as_deref(),
&target,
);
// target_override is documented to be called before init(), so this is okay
let target_override = backend.target_override(&config.opts);
// Assert that we don't use target's override of the backend and
// backend's override of the target at the same time
if config.opts.unstable_opts.codegen_backend.is_none()
&& target.default_codegen_backend.is_some()
&& target_override.is_some()
{
rustc_middle::bug!(
"Codegen backend requested target override even though the target requested the backend"
);
}
(backend, target_override)
}
Some(make_codegen_backend) => {
// N.B. `make_codegen_backend` takes precedence over `target.default_codegen_backend`,
// which is ignored in this case.
let backend = make_codegen_backend(&config.opts);
// target_override is documented to be called before init(), so this is okay
let target_override = backend.target_override(&config.opts);
(backend, target_override)
}
}; };
// Re-build target with the (potential) override
let target_cfg =
config::build_target_config(&early_dcx, &config.opts, target_override, &sysroot);
let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
let bundle = match rustc_errors::fluent_bundle( let bundle = match rustc_errors::fluent_bundle(
@ -367,9 +404,6 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
let mut locale_resources = Vec::from(config.locale_resources); let mut locale_resources = Vec::from(config.locale_resources);
locale_resources.push(codegen_backend.locale_resource()); locale_resources.push(codegen_backend.locale_resource());
// target_override is documented to be called before init(), so this is okay
let target_override = codegen_backend.target_override(&config.opts);
let mut sess = rustc_session::build_session( let mut sess = rustc_session::build_session(
early_dcx, early_dcx,
config.opts, config.opts,
@ -384,7 +418,8 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
locale_resources, locale_resources,
config.lint_caps, config.lint_caps,
config.file_loader, config.file_loader,
target_override, target_cfg,
sysroot,
util::rustc_version_str().unwrap_or("unknown"), util::rustc_version_str().unwrap_or("unknown"),
config.ice_file, config.ice_file,
config.using_internal_features, config.using_internal_features,

View file

@ -13,7 +13,7 @@ use rustc_session::config::{
use rustc_session::lint::Level; use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath; use rustc_session::search_paths::SearchPath;
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
use rustc_session::{build_session, getopts, CompilerIO, EarlyDiagCtxt, Session}; use rustc_session::{build_session, filesearch, getopts, CompilerIO, EarlyDiagCtxt, Session};
use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::{FileName, SourceFileHashAlgorithm}; use rustc_span::{FileName, SourceFileHashAlgorithm};
@ -37,6 +37,12 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
output_file: None, output_file: None,
temps_dir, temps_dir,
}; };
let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone());
let target_cfg =
rustc_session::config::build_target_config(&early_dcx, &sessopts, None, &sysroot);
let sess = build_session( let sess = build_session(
early_dcx, early_dcx,
sessopts, sessopts,
@ -46,7 +52,8 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
vec![], vec![],
Default::default(), Default::default(),
None, None,
None, target_cfg,
sysroot,
"", "",
None, None,
Arc::default(), Arc::default(),

View file

@ -14,13 +14,14 @@ use rustc_session::{filesearch, output, Session};
use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::symbol::{sym, Symbol}; use rustc_span::symbol::{sym, Symbol};
use rustc_target::spec::Target;
use session::EarlyDiagCtxt; use session::EarlyDiagCtxt;
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::OnceLock; use std::sync::OnceLock;
use std::thread; use std::thread;
use std::{env, iter};
/// Function pointer type that constructs a new CodegenBackend. /// Function pointer type that constructs a new CodegenBackend.
pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>; pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
@ -195,21 +196,25 @@ fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBacken
/// A name of `None` indicates that the default backend should be used. /// A name of `None` indicates that the default backend should be used.
pub fn get_codegen_backend( pub fn get_codegen_backend(
early_dcx: &EarlyDiagCtxt, early_dcx: &EarlyDiagCtxt,
maybe_sysroot: &Option<PathBuf>, sysroot: &Path,
backend_name: Option<&str>, backend_name: Option<&str>,
target: &Target,
) -> Box<dyn CodegenBackend> { ) -> Box<dyn CodegenBackend> {
static LOAD: OnceLock<unsafe fn() -> Box<dyn CodegenBackend>> = OnceLock::new(); static LOAD: OnceLock<unsafe fn() -> Box<dyn CodegenBackend>> = OnceLock::new();
let load = LOAD.get_or_init(|| { let load = LOAD.get_or_init(|| {
let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm"); let backend = backend_name
.or(target.default_codegen_backend.as_deref())
.or(option_env!("CFG_DEFAULT_CODEGEN_BACKEND"))
.unwrap_or("llvm");
match backend_name.unwrap_or(default_codegen_backend) { match backend {
filename if filename.contains('.') => { filename if filename.contains('.') => {
load_backend_from_dylib(early_dcx, filename.as_ref()) load_backend_from_dylib(early_dcx, filename.as_ref())
} }
#[cfg(feature = "llvm")] #[cfg(feature = "llvm")]
"llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new, "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
backend_name => get_codegen_sysroot(early_dcx, maybe_sysroot, backend_name), backend_name => get_codegen_sysroot(early_dcx, sysroot, backend_name),
} }
}); });
@ -244,7 +249,7 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn get_codegen_sysroot( fn get_codegen_sysroot(
early_dcx: &EarlyDiagCtxt, early_dcx: &EarlyDiagCtxt,
maybe_sysroot: &Option<PathBuf>, sysroot: &Path,
backend_name: &str, backend_name: &str,
) -> MakeBackendFn { ) -> MakeBackendFn {
// For now we only allow this function to be called once as it'll dlopen a // For now we only allow this function to be called once as it'll dlopen a
@ -261,28 +266,28 @@ fn get_codegen_sysroot(
let target = session::config::host_triple(); let target = session::config::host_triple();
let sysroot_candidates = sysroot_candidates(); let sysroot_candidates = sysroot_candidates();
let sysroot = maybe_sysroot let sysroot = iter::once(sysroot)
.iter() .chain(sysroot_candidates.iter().map(<_>::as_ref))
.chain(sysroot_candidates.iter())
.map(|sysroot| { .map(|sysroot| {
filesearch::make_target_lib_path(sysroot, target).with_file_name("codegen-backends") filesearch::make_target_lib_path(sysroot, target).with_file_name("codegen-backends")
}) })
.find(|f| { .find(|f| {
info!("codegen backend candidate: {}", f.display()); info!("codegen backend candidate: {}", f.display());
f.exists() f.exists()
}); })
let sysroot = sysroot.unwrap_or_else(|| { .unwrap_or_else(|| {
let candidates = sysroot_candidates let candidates = sysroot_candidates
.iter() .iter()
.map(|p| p.display().to_string()) .map(|p| p.display().to_string())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n* "); .join("\n* ");
let err = format!( let err = format!(
"failed to find a `codegen-backends` folder \ "failed to find a `codegen-backends` folder \
in the sysroot candidates:\n* {candidates}" in the sysroot candidates:\n* {candidates}"
); );
early_dcx.early_fatal(err); early_dcx.early_fatal(err);
}); });
info!("probing {} for a codegen backend", sysroot.display()); info!("probing {} for a codegen backend", sysroot.display());
let d = sysroot.read_dir().unwrap_or_else(|e| { let d = sysroot.read_dir().unwrap_or_else(|e| {

View file

@ -8,7 +8,7 @@ pub use crate::options::*;
use crate::errors::FileWriteFail; use crate::errors::FileWriteFail;
use crate::search_paths::SearchPath; use crate::search_paths::SearchPath;
use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
use crate::{lint, HashStableContext}; use crate::{filesearch, lint, HashStableContext};
use crate::{EarlyDiagCtxt, Session}; use crate::{EarlyDiagCtxt, Session};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
@ -1564,7 +1564,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
user_cfg user_cfg
} }
pub(super) fn build_target_config( pub fn build_target_config(
early_dcx: &EarlyDiagCtxt, early_dcx: &EarlyDiagCtxt,
opts: &Options, opts: &Options,
target_override: Option<Target>, target_override: Option<Target>,
@ -2863,16 +2863,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
let logical_env = parse_logical_env(early_dcx, matches); let logical_env = parse_logical_env(early_dcx, matches);
// Try to find a directory containing the Rust `src`, for more details see let sysroot = filesearch::materialize_sysroot(sysroot_opt);
// the doc comment on the `real_rust_source_base_dir` field.
let tmp_buf;
let sysroot = match &sysroot_opt {
Some(s) => s,
None => {
tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
&tmp_buf
}
};
let real_rust_source_base_dir = { let real_rust_source_base_dir = {
// This is the location used by the `rust-src` `rustup` component. // This is the location used by the `rust-src` `rustup` component.
let mut candidate = sysroot.join("lib/rustlib/src/rust"); let mut candidate = sysroot.join("lib/rustlib/src/rust");
@ -2916,7 +2908,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
describe_lints, describe_lints,
output_types, output_types,
search_paths, search_paths,
maybe_sysroot: sysroot_opt, maybe_sysroot: Some(sysroot),
target_triple, target_triple,
test, test,
incremental, incremental,

View file

@ -193,6 +193,12 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
return sysroot_candidates; return sysroot_candidates;
} }
/// Returns the provided sysroot or calls [`get_or_default_sysroot`] if it's none.
/// Panics if [`get_or_default_sysroot`] returns an error.
pub fn materialize_sysroot(maybe_sysroot: Option<PathBuf>) -> PathBuf {
maybe_sysroot.unwrap_or_else(|| get_or_default_sysroot().expect("Failed finding sysroot"))
}
/// This function checks if sysroot is found using env::args().next(), and if it /// This function checks if sysroot is found using env::args().next(), and if it
/// is not found, finds sysroot from current rustc_driver dll. /// is not found, finds sysroot from current rustc_driver dll.
pub fn get_or_default_sysroot() -> Result<PathBuf, String> { pub fn get_or_default_sysroot() -> Result<PathBuf, String> {

View file

@ -1016,7 +1016,8 @@ pub fn build_session(
fluent_resources: Vec<&'static str>, fluent_resources: Vec<&'static str>,
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
target_override: Option<Target>, target_cfg: Target,
sysroot: PathBuf,
cfg_version: &'static str, cfg_version: &'static str,
ice_file: Option<PathBuf>, ice_file: Option<PathBuf>,
using_internal_features: Arc<AtomicBool>, using_internal_features: Arc<AtomicBool>,
@ -1033,12 +1034,6 @@ pub fn build_session(
let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::Allow); let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::Allow);
let can_emit_warnings = !(warnings_allow || cap_lints_allow); let can_emit_warnings = !(warnings_allow || cap_lints_allow);
let sysroot = match &sopts.maybe_sysroot {
Some(sysroot) => sysroot.clone(),
None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"),
};
let target_cfg = config::build_target_config(&early_dcx, &sopts, target_override, &sysroot);
let host_triple = TargetTriple::from_triple(config::host_triple()); let host_triple = TargetTriple::from_triple(config::host_triple());
let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| { let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| {
early_dcx.early_fatal(format!("Error loading host specification: {e}")) early_dcx.early_fatal(format!("Error loading host specification: {e}"))

View file

@ -2070,6 +2070,14 @@ pub struct TargetOptions {
/// Default number of codegen units to use in debug mode /// Default number of codegen units to use in debug mode
pub default_codegen_units: Option<u64>, pub default_codegen_units: Option<u64>,
/// Default codegen backend used for this target. Defaults to `None`.
///
/// If `None`, then `CFG_DEFAULT_CODEGEN_BACKEND` environmental variable captured when
/// compiling `rustc` will be used instead (or llvm if it is not set).
///
/// N.B. when *using* the compiler, backend can always be overriden with `-Zcodegen-backend`.
pub default_codegen_backend: Option<StaticCow<str>>,
/// Whether to generate trap instructions in places where optimization would /// Whether to generate trap instructions in places where optimization would
/// otherwise produce control flow that falls through into unrelated memory. /// otherwise produce control flow that falls through into unrelated memory.
pub trap_unreachable: bool, pub trap_unreachable: bool,
@ -2376,6 +2384,7 @@ impl Default for TargetOptions {
stack_probes: StackProbeType::None, stack_probes: StackProbeType::None,
min_global_align: None, min_global_align: None,
default_codegen_units: None, default_codegen_units: None,
default_codegen_backend: None,
trap_unreachable: true, trap_unreachable: true,
requires_lto: false, requires_lto: false,
singlethread: false, singlethread: false,