Skip to content
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

Allow targets to override default codegen backend #116793

Merged
merged 3 commits into from
Mar 11, 2024
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
15 changes: 12 additions & 3 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType};
use rustc_session::getopts::{self, Matches};
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::source_map::FileLoader;
use rustc_span::symbol::sym;
Expand Down Expand Up @@ -887,7 +887,11 @@ 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(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();
}
}

Expand Down Expand Up @@ -1092,7 +1096,12 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, 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(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;
}

Expand Down
61 changes: 48 additions & 13 deletions compiler/rustc_interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt;
use rustc_query_system::query::print_query_stack;
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::{lint, CompilerIO, EarlyDiagCtxt, Session};
use rustc_span::source_map::FileLoader;
Expand Down Expand Up @@ -336,16 +336,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 codegen_backend = if let Some(make_codegen_backend) = config.make_codegen_backend {
make_codegen_backend(&config.opts)
} else {
util::get_codegen_backend(
&early_dcx,
&config.opts.maybe_sysroot,
config.opts.unstable_opts.codegen_backend.as_deref(),
)
let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone());

let (codegen_backend, target_override) = match config.make_codegen_backend {
None => {
// Build a target without override, so that it can override the backend if needed
let target =
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);
Comment on lines -339 to +355
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't really do the same thing as before, or rather it assumes custom codegen backends require config.make_codegen_backend, whereas config.opts.unstable_opts.codegen_backend is also possible.

The new version calls config::build_target_config once, without the override, which means the backend cannot add new targets, only at most slightly tweak existing ones.

To be clear, none of this really matters anymore due to:

(but I ran into it while trying to update Rust-GPU to nightly-2024-03-21, just before #122810, just so I can get everything else out of the way before tackling the target_override removal itself)


// 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 bundle = match rustc_errors::fluent_bundle(
Expand All @@ -364,9 +401,6 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
let mut locale_resources = Vec::from(config.locale_resources);
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(
early_dcx,
config.opts,
Expand All @@ -381,7 +415,8 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
locale_resources,
config.lint_caps,
config.file_loader,
target_override,
target_cfg,
sysroot,
util::rustc_version_str().unwrap_or("unknown"),
config.ice_file,
config.using_internal_features,
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_session::config::{
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
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::symbol::sym;
use rustc_span::{FileName, SourceFileHashAlgorithm};
Expand All @@ -37,6 +37,12 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
output_file: None,
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(
early_dcx,
sessopts,
Expand All @@ -46,7 +52,8 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
vec![],
Default::default(),
None,
None,
target_cfg,
sysroot,
"",
None,
Arc::default(),
Expand Down
47 changes: 26 additions & 21 deletions compiler/rustc_interface/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ use rustc_session::{filesearch, output, Session};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::symbol::{sym, Symbol};
use rustc_target::spec::Target;
use session::EarlyDiagCtxt;
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::mem;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::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 @@ -192,21 +193,25 @@ fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBacken
/// A name of `None` indicates that the default backend should be used.
pub fn get_codegen_backend(
early_dcx: &EarlyDiagCtxt,
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(early_dcx, filename.as_ref())
}
#[cfg(feature = "llvm")]
"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),
}
});

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

fn get_codegen_sysroot(
early_dcx: &EarlyDiagCtxt,
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 @@ -257,28 +262,28 @@ 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(<_>::as_ref))
.map(|sysroot| {
filesearch::make_target_lib_path(sysroot, target).with_file_name("codegen-backends")
})
.find(|f| {
info!("codegen backend candidate: {}", f.display());
f.exists()
});
let sysroot = sysroot.unwrap_or_else(|| {
let candidates = sysroot_candidates
.iter()
.map(|p| p.display().to_string())
.collect::<Vec<_>>()
.join("\n* ");
let err = format!(
"failed to find a `codegen-backends` folder \
})
.unwrap_or_else(|| {
let candidates = sysroot_candidates
.iter()
.map(|p| p.display().to_string())
.collect::<Vec<_>>()
.join("\n* ");
let err = format!(
"failed to find a `codegen-backends` folder \
in the sysroot candidates:\n* {candidates}"
);
early_dcx.early_fatal(err);
});
);
early_dcx.early_fatal(err);
});

info!("probing {} for a codegen backend", sysroot.display());

let d = sysroot.read_dir().unwrap_or_else(|e| {
Expand Down
18 changes: 5 additions & 13 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub use crate::options::*;
use crate::errors::FileWriteFail;
use crate::search_paths::SearchPath;
use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
use crate::{lint, HashStableContext};
use crate::{filesearch, lint, HashStableContext};
use crate::{EarlyDiagCtxt, Session};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
Expand Down Expand Up @@ -1558,7 +1558,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
user_cfg
}

pub(super) fn build_target_config(
pub fn build_target_config(
early_dcx: &EarlyDiagCtxt,
opts: &Options,
target_override: Option<Target>,
Expand Down Expand Up @@ -2856,16 +2856,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M

let logical_env = parse_logical_env(early_dcx, matches);

// Try to find a directory containing the Rust `src`, for more details see
// 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 sysroot = filesearch::materialize_sysroot(sysroot_opt);

let real_rust_source_base_dir = {
// This is the location used by the `rust-src` `rustup` component.
let mut candidate = sysroot.join("lib/rustlib/src/rust");
Expand Down Expand Up @@ -2909,7 +2901,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
describe_lints,
output_types,
search_paths,
maybe_sysroot: sysroot_opt,
maybe_sysroot: Some(sysroot),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This made it impossible for the config driver callback to determine whether the --sysroot flag was passed or not, which is a problem for drivers that want to overwrite the default sysroot but honor explicit --sysroot. I'm trying to fix this in #122993 but I don't really know what I am doing...

target_triple,
test,
incremental,
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_session/src/filesearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
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
/// is not found, finds sysroot from current rustc_driver dll.
pub fn get_or_default_sysroot() -> Result<PathBuf, String> {
Expand Down
9 changes: 2 additions & 7 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,8 @@ pub fn build_session(
fluent_resources: Vec<&'static str>,
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
target_override: Option<Target>,
target_cfg: Target,
sysroot: PathBuf,
cfg_version: &'static str,
ice_file: Option<PathBuf>,
using_internal_features: Arc<AtomicBool>,
Expand All @@ -1051,12 +1052,6 @@ pub fn build_session(
let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::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, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| {
early_dcx.early_fatal(format!("Error loading host specification: {e}"))
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 @@ -2044,6 +2044,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 @@ -2350,6 +2358,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
Loading