1
Fork 0

Auto merge of #77975 - bjorn3:cg_clif_subtree3, r=Mark-Simulacrum

Add cg_clif as optional codegen backend

Rustc_codegen_cranelift is an alternative codegen backend for rustc based on Cranelift. It has the potential to improve compilation times in debug mode. In my experience the compile time improvements over debug mode LLVM for a clean build are about 20-30% in most cases.

This PR adds cg_clif as optional codegen backend. By default it is only enabled for `./x.py check`. It can be enabled for `./x.py build` too by adding `cranelift` to the `rust.codegen-backends` array in `config.toml`.

MCP: https://github.com/rust-lang/compiler-team/issues/270

r? `@Mark-Simulacrum`
This commit is contained in:
bors 2020-10-26 16:31:38 +00:00
commit 35debd4c11
98 changed files with 17049 additions and 39 deletions

View file

@ -24,11 +24,13 @@ use rustc_span::source_map::FileLoader;
use rustc_span::symbol::{sym, Symbol};
use smallvec::SmallVec;
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::io::{self, Write};
use std::lazy::SyncOnceCell;
use std::mem;
use std::ops::DerefMut;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, Once};
#[cfg(not(parallel_compiler))]
use std::{panic, thread};
@ -238,7 +240,19 @@ pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> {
static mut LOAD: fn() -> Box<dyn CodegenBackend> = || unreachable!();
INIT.call_once(|| {
let codegen_name = sopts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm");
#[cfg(feature = "llvm")]
const DEFAULT_CODEGEN_BACKEND: &'static str = "llvm";
#[cfg(not(feature = "llvm"))]
const DEFAULT_CODEGEN_BACKEND: &'static str = "cranelift";
let codegen_name = sopts
.debugging_opts
.codegen_backend
.as_ref()
.map(|name| &name[..])
.unwrap_or(DEFAULT_CODEGEN_BACKEND);
let backend = match codegen_name {
filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
codegen_name => get_builtin_codegen_backend(codegen_name),
@ -367,15 +381,102 @@ fn sysroot_candidates() -> Vec<PathBuf> {
}
pub fn get_builtin_codegen_backend(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
#[cfg(feature = "llvm")]
{
if backend_name == "llvm" {
return rustc_codegen_llvm::LlvmCodegenBackend::new;
match backend_name {
#[cfg(feature = "llvm")]
"llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
_ => get_codegen_sysroot(backend_name),
}
}
pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
// For now we only allow this function to be called once as it'll dlopen a
// few things, which seems to work best if we only do that once. In
// general this assertion never trips due to the once guard in `get_codegen_backend`,
// but there's a few manual calls to this function in this file we protect
// against.
static LOADED: AtomicBool = AtomicBool::new(false);
assert!(
!LOADED.fetch_or(true, Ordering::SeqCst),
"cannot load the default codegen backend twice"
);
let target = session::config::host_triple();
let sysroot_candidates = sysroot_candidates();
let sysroot = sysroot_candidates
.iter()
.map(|sysroot| {
let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
sysroot.join(libdir).with_file_name("codegen-backends")
})
.filter(|f| {
info!("codegen backend candidate: {}", f.display());
f.exists()
})
.next();
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 \
in the sysroot candidates:\n* {}",
candidates
);
early_error(ErrorOutputType::default(), &err);
});
info!("probing {} for a codegen backend", sysroot.display());
let d = sysroot.read_dir().unwrap_or_else(|e| {
let err = format!(
"failed to load default codegen backend, couldn't \
read `{}`: {}",
sysroot.display(),
e
);
early_error(ErrorOutputType::default(), &err);
});
let mut file: Option<PathBuf> = None;
let expected_name =
format!("rustc_codegen_{}-{}", backend_name, release_str().expect("CFG_RELEASE"));
for entry in d.filter_map(|e| e.ok()) {
let path = entry.path();
let filename = match path.file_name().and_then(|s| s.to_str()) {
Some(s) => s,
None => continue,
};
if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) {
continue;
}
let name = &filename[DLL_PREFIX.len()..filename.len() - DLL_SUFFIX.len()];
if name != expected_name {
continue;
}
if let Some(ref prev) = file {
let err = format!(
"duplicate codegen backends found\n\
first: {}\n\
second: {}\n\
",
prev.display(),
path.display()
);
early_error(ErrorOutputType::default(), &err);
}
file = Some(path.clone());
}
let err = format!("unsupported builtin codegen backend `{}`", backend_name);
early_error(ErrorOutputType::default(), &err);
match file {
Some(ref s) => load_backend_from_dylib(s),
None => {
let err = format!("unsupported builtin codegen backend `{}`", backend_name);
early_error(ErrorOutputType::default(), &err);
}
}
}
pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
@ -782,3 +883,23 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
noop_visit_mac(mac, self)
}
}
/// Returns a version string such as "rustc 1.46.0 (04488afe3 2020-08-24)"
pub fn version_str() -> Option<&'static str> {
option_env!("CFG_VERSION")
}
/// Returns a version string such as "0.12.0-dev".
pub fn release_str() -> Option<&'static str> {
option_env!("CFG_RELEASE")
}
/// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
pub fn commit_hash_str() -> Option<&'static str> {
option_env!("CFG_VER_HASH")
}
/// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
pub fn commit_date_str() -> Option<&'static str> {
option_env!("CFG_VER_DATE")
}