Skip to content

Commit

Permalink
Allow targets to override default codegen backend
Browse files Browse the repository at this point in the history
  • Loading branch information
WaffleLapkin committed Nov 14, 2023
1 parent d9bde93 commit eedd680
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 21 deletions.
18 changes: 15 additions & 3 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType, Tri
use rustc_session::cstore::MetadataLoader;
use rustc_session::getopts::{self, Matches};
use rustc_session::lint::{Lint, LintId};
use rustc_session::{config, EarlyErrorHandler, Session};
use rustc_session::{config, filesearch, EarlyErrorHandler, Session};
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
use rustc_target::json::ToJson;
Expand Down Expand Up @@ -943,7 +943,13 @@ pub fn version_at_macro_invocation(

let debug_flags = matches.opt_strs("Z");
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
get_codegen_backend(handler, &None, backend_name).print_version();
let sopts = config::Options::default();
let sysroot = sopts.maybe_sysroot.clone().unwrap_or_else(|| {
filesearch::get_or_default_sysroot().expect("Failed finding sysroot")
});
let target = config::build_target_config(handler, &sopts, None, &sysroot);

get_codegen_backend(handler, &sysroot, backend_name, &target).print_version();
}
}

Expand Down Expand Up @@ -1147,7 +1153,13 @@ pub fn describe_flag_categories(handler: &EarlyErrorHandler, matches: &Matches)

if cg_flags.iter().any(|x| *x == "passes=list") {
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
get_codegen_backend(handler, &None, backend_name).print_passes();
let sopts = config::Options::default();
let sysroot = sopts.maybe_sysroot.clone().unwrap_or_else(|| {
filesearch::get_or_default_sysroot().expect("Failed finding sysroot")
});
let target = config::build_target_config(handler, &sopts, None, &sysroot);

get_codegen_backend(handler, &sysroot, backend_name, &target).print_passes();
return true;
}

Expand Down
58 changes: 40 additions & 18 deletions compiler/rustc_interface/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::source_map::FileLoader;
use rustc_span::symbol::{sym, Symbol};
use rustc_target::spec::Target;
use session::{CompilerIO, EarlyErrorHandler};
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::mem;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, OnceLock};
use std::thread;
use std::{env, iter};

/// Function pointer type that constructs a new CodegenBackend.
pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
Expand Down Expand Up @@ -75,24 +77,41 @@ pub fn create_session(
};

let (codegen_backend, target_cfg) = match make_codegen_backend {
Some(make_codegen_backend) => {
let backend = make_codegen_backend(&sopts);
None => {
// Build a target without override, so that it can override the backend if needed
let target = config::build_target_config(handler, &sopts, None, &sysroot);

let backend = get_codegen_backend(
handler,
&sysroot,
sopts.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(&sopts);

// Assert that we don't use target's override of the backend and
// backend's override of the target at the same time
if sopts.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"
);
}

// Re-build target with the (potential) override
let target = config::build_target_config(handler, &sopts, target_override, &sysroot);

(backend, target)
}
None => {
let _target = config::build_target_config(handler, &sopts, None, &sysroot);
Some(make_codegen_backend) => {
// N.B. `make_codegen_backend` takes precedence over `target.default_codegen_backend`,
// which is ignored in this case.

let backend = get_codegen_backend(
handler,
&sopts.maybe_sysroot,
sopts.unstable_opts.codegen_backend.as_deref(),
);
let backend = make_codegen_backend(&sopts);

// target_override is documented to be called before init(), so this is okay
let target_override = backend.target_override(&sopts);
Expand Down Expand Up @@ -292,21 +311,25 @@ fn load_backend_from_dylib(handler: &EarlyErrorHandler, path: &Path) -> MakeBack
/// A name of `None` indicates that the default backend should be used.
pub fn get_codegen_backend(
handler: &EarlyErrorHandler,
maybe_sysroot: &Option<PathBuf>,
sysroot: &Path,
backend_name: Option<&str>,
target: &Target,
) -> Box<dyn CodegenBackend> {
static LOAD: OnceLock<unsafe fn() -> Box<dyn CodegenBackend>> = OnceLock::new();

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('.') => {
load_backend_from_dylib(handler, filename.as_ref())
}
#[cfg(feature = "llvm")]
"llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
backend_name => get_codegen_sysroot(handler, maybe_sysroot, backend_name),
backend_name => get_codegen_sysroot(handler, sysroot, backend_name),
}
});

Expand Down Expand Up @@ -340,7 +363,7 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {

fn get_codegen_sysroot(
handler: &EarlyErrorHandler,
maybe_sysroot: &Option<PathBuf>,
sysroot: &Path,
backend_name: &str,
) -> MakeBackendFn {
// For now we only allow this function to be called once as it'll dlopen a
Expand All @@ -357,9 +380,8 @@ fn get_codegen_sysroot(
let target = session::config::host_triple();
let sysroot_candidates = sysroot_candidates();

let sysroot = maybe_sysroot
.iter()
.chain(sysroot_candidates.iter())
let sysroot = iter::once(sysroot)
.chain(sysroot_candidates.iter().map(<_>::deref))
.map(|sysroot| {
filesearch::make_target_lib_path(sysroot, target).with_file_name("codegen-backends")
})
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2110,6 +2110,14 @@ pub struct TargetOptions {
/// Default number of codegen units to use in debug mode
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
/// otherwise produce control flow that falls through into unrelated memory.
pub trap_unreachable: bool,
Expand Down Expand Up @@ -2418,6 +2426,7 @@ impl Default for TargetOptions {
stack_probes: StackProbeType::None,
min_global_align: None,
default_codegen_units: None,
default_codegen_backend: None,
trap_unreachable: true,
requires_lto: false,
singlethread: false,
Expand Down

0 comments on commit eedd680

Please sign in to comment.