Centralize all configuration into config.rs

This commit is contained in:
bjorn3 2021-04-07 11:52:11 +02:00
parent 1ee0aa9416
commit 53bfc6729a
10 changed files with 94 additions and 57 deletions

View File

@ -44,9 +44,10 @@ This will build your project with rustc_codegen_cranelift instead of the usual L
For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage.md](docs/usage.md).
## Env vars
## Configuration
See [env_vars.md](docs/env_vars.md) for all env vars used by rustc_codegen_cranelift.
See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all
configuration options.
## Not yet supported

View File

@ -1,15 +0,0 @@
# List of env vars recognized by cg_clif
<dl>
<dt>CG_CLIF_JIT_ARGS</dt>
<dd>When JIT mode is enable pass these arguments to the program.</dd>
<dt>CG_CLIF_INCR_CACHE_DISABLED</dt>
<dd>Don't cache object files in the incremental cache. Useful during development of cg_clif
to make it possible to use incremental mode for all analyses performed by rustc without caching
object files when their content should have been changed by a change to cg_clif.</dd>
<dt>CG_CLIF_DISPLAY_CG_TIME</dt>
<dd>If "1", display the time it took to perform codegen for a crate.</dd>
<dt>CG_CLIF_ENABLE_VERIFIER</dt>
<dd>Enable the Cranelift ir verifier for all compilation passes. If not set it will only run once
before passing the clif ir to Cranelift for compilation.</dt>
</dl>

View File

@ -5,7 +5,7 @@
set -e
export CG_CLIF_DISPLAY_CG_TIME=1
export CG_CLIF_INCR_CACHE_DISABLED=1
export CG_CLIF_DISABLE_INCR_CACHE=1
export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}

View File

@ -5,13 +5,13 @@ use std::convert::{TryFrom, TryInto};
use rustc_data_structures::fx::FxHashMap;
use rustc_session::Session;
use cranelift_codegen::isa::TargetIsa;
use cranelift_module::FuncId;
use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
use object::write::*;
use object::{RelocationEncoding, SectionKind, SymbolFlags};
use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
use gimli::SectionId;
use crate::debuginfo::{DebugReloc, DebugRelocName};
@ -113,7 +113,7 @@ impl WriteDebugInfo for ObjectProduct {
}
pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
let triple = crate::build_isa(sess).triple().clone();
let triple = crate::target_triple(sess);
let binary_format = match triple.binary_format {
target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
@ -141,9 +141,9 @@ pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object
metadata_object.write().unwrap()
}
pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule {
pub(crate) fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
let mut builder = ObjectBuilder::new(
crate::build_isa(sess),
isa,
name + ".o",
cranelift_module::default_libcall_names(),
)

View File

@ -1,5 +1,10 @@
use std::env;
use std::str::FromStr;
fn bool_env_var(key: &str) -> bool {
env::var(key).as_ref().map(|val| &**val) == Ok("1")
}
#[derive(Copy, Clone, Debug)]
pub enum CodegenMode {
Aot,
@ -7,12 +12,6 @@ pub enum CodegenMode {
JitLazy,
}
impl Default for CodegenMode {
fn default() -> Self {
CodegenMode::Aot
}
}
impl FromStr for CodegenMode {
type Err = String;
@ -26,24 +25,77 @@ impl FromStr for CodegenMode {
}
}
#[derive(Copy, Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct BackendConfig {
/// Should the crate be AOT compiled or JIT executed.
///
/// Defaults to AOT compilation. Can be set using `-Cllvm-args=mode=...`.
pub codegen_mode: CodegenMode,
/// When JIT mode is enable pass these arguments to the program.
///
/// Defaults to the value of `CG_CLIF_JIT_ARGS`.
pub jit_args: Vec<String>,
/// Display the time it took to perform codegen for a crate.
///
/// Defaults to true when the `CG_CLIF_DISPLAY_CG_TIME` env var is set to 1 or false otherwise.
/// Can be set using `-Cllvm-args=display_cg_time=...`.
pub display_cg_time: bool,
/// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
/// once before passing the clif ir to Cranelift for compilation.
///
/// Defaults to true when the `CG_CLIF_ENABLE_VERIFIER` env var is set to 1 or when cg_clif is
/// compiled with debug assertions enabled or false otherwise. Can be set using
/// `-Cllvm-args=enable_verifier=...`.
pub enable_verifier: bool,
/// Don't cache object files in the incremental cache. Useful during development of cg_clif
/// to make it possible to use incremental mode for all analyses performed by rustc without
/// caching object files when their content should have been changed by a change to cg_clif.
///
/// Defaults to true when the `CG_CLIF_DISABLE_INCR_CACHE` env var is set to 1 or false
/// otherwise. Can be set using `-Cllvm-args=disable_incr_cache=...`.
pub disable_incr_cache: bool,
}
impl Default for BackendConfig {
fn default() -> Self {
BackendConfig {
codegen_mode: CodegenMode::Aot,
jit_args: {
let args = std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
args.split(' ').map(|arg| arg.to_string()).collect()
},
display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
}
}
}
impl BackendConfig {
pub fn from_opts(opts: &[String]) -> Result<Self, String> {
fn parse_bool(name: &str, value: &str) -> Result<bool, String> {
value.parse().map_err(|_| format!("failed to parse value `{}` for {}", value, name))
}
let mut config = BackendConfig::default();
for opt in opts {
if let Some((name, value)) = opt.split_once('=') {
match name {
"mode" => config.codegen_mode = value.parse()?,
"display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
"enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
"disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
_ => return Err(format!("Unknown option `{}`", name)),
}
} else {
return Err(format!("Invalid option `{}`", opt));
}
}
Ok(config)
}
}

View File

@ -16,12 +16,6 @@ use cranelift_object::ObjectModule;
use crate::{prelude::*, BackendConfig};
fn new_module(tcx: TyCtxt<'_>, name: String) -> ObjectModule {
let module = crate::backend::make_module(tcx.sess, name);
assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
module
}
struct ModuleCodegenResult(CompiledModule, Option<(WorkProductId, WorkProduct)>);
impl<HCX> HashStable<HCX> for ModuleCodegenResult {
@ -32,6 +26,7 @@ impl<HCX> HashStable<HCX> for ModuleCodegenResult {
fn emit_module(
tcx: TyCtxt<'_>,
backend_config: &BackendConfig,
name: String,
kind: ModuleKind,
module: ObjectModule,
@ -52,7 +47,7 @@ fn emit_module(
tcx.sess.fatal(&format!("error writing object file: {}", err));
}
let work_product = if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() {
let work_product = if backend_config.disable_incr_cache {
None
} else {
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
@ -110,11 +105,13 @@ fn module_codegen(
let cgu = tcx.codegen_unit(cgu_name);
let mono_items = cgu.items_in_deterministic_order(tcx);
let mut module = new_module(tcx, cgu_name.as_str().to_string());
let isa = crate::build_isa(tcx.sess, &backend_config);
let mut module = crate::backend::make_module(tcx.sess, isa, cgu_name.as_str().to_string());
assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
let mut cx = crate::CodegenCx::new(
tcx,
backend_config,
backend_config.clone(),
&mut module,
tcx.sess.opts.debuginfo != DebugInfo::None,
);
@ -144,6 +141,7 @@ fn module_codegen(
let codegen_result = emit_module(
tcx,
&backend_config,
cgu.name().as_str().to_string(),
ModuleKind::Regular,
module,
@ -193,14 +191,14 @@ pub(super) fn run_aot(
}
}
let modules = super::time(tcx, "codegen mono items", || {
let modules = super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
cgus.iter()
.map(|cgu| {
let cgu_reuse = determine_cgu_reuse(tcx, cgu);
tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
match cgu_reuse {
_ if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() => {}
_ if backend_config.disable_incr_cache => {}
CguReuse::No => {}
CguReuse::PreLto => {
return reuse_workproduct_for_cgu(tcx, &*cgu, &mut work_products);
@ -212,7 +210,7 @@ pub(super) fn run_aot(
let (ModuleCodegenResult(module, work_product), _) = tcx.dep_graph.with_task(
dep_node,
tcx,
(backend_config, cgu.name()),
(backend_config.clone(), cgu.name()),
module_codegen,
rustc_middle::dep_graph::hash_result,
);
@ -228,7 +226,9 @@ pub(super) fn run_aot(
tcx.sess.abort_if_errors();
let mut allocator_module = new_module(tcx, "allocator_shim".to_string());
let isa = crate::build_isa(tcx.sess, &backend_config);
let mut allocator_module = crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string());
assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type());
let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
let created_alloc_shim =
crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
@ -236,6 +236,7 @@ pub(super) fn run_aot(
let allocator_module = if created_alloc_shim {
let ModuleCodegenResult(module, work_product) = emit_module(
tcx,
&backend_config,
"allocator_shim".to_string(),
ModuleKind::Allocator,
allocator_module,

View File

@ -27,8 +27,8 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
let imported_symbols = load_imported_symbols_for_jit(tcx);
let mut jit_builder =
JITBuilder::with_isa(crate::build_isa(tcx.sess), cranelift_module::default_libcall_names());
let isa = crate::build_isa(tcx.sess, &backend_config);
let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
jit_builder.hotswap(matches!(backend_config.codegen_mode, CodegenMode::JitLazy));
crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
jit_builder.symbols(imported_symbols);
@ -44,9 +44,9 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
.into_iter()
.collect::<Vec<(_, (_, _))>>();
let mut cx = crate::CodegenCx::new(tcx, backend_config, &mut jit_module, false);
let mut cx = crate::CodegenCx::new(tcx, backend_config.clone(), &mut jit_module, false);
super::time(tcx, "codegen mono items", || {
super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
super::predefine_mono_items(&mut cx, &mono_items);
for (mono_item, _) in mono_items {
match mono_item {
@ -87,9 +87,8 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
"Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed"
);
let args = ::std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())
.chain(args.split(' '))
.chain(backend_config.jit_args.iter().map(|arg| &**arg))
.map(|arg| CString::new(arg).unwrap())
.collect::<Vec<_>>();
let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();

View File

@ -65,8 +65,8 @@ fn predefine_mono_items<'tcx>(
});
}
fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R {
if std::env::var("CG_CLIF_DISPLAY_CG_TIME").as_ref().map(|val| &**val) == Ok("1") {
fn time<R>(tcx: TyCtxt<'_>, display: bool, name: &'static str, f: impl FnOnce() -> R) -> R {
if display {
println!("[{:<30}: {}] start", tcx.crate_name(LOCAL_CRATE), name);
let before = std::time::Instant::now();
let res = tcx.sess.time(name, f);

View File

@ -193,7 +193,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
metadata: EncodedMetadata,
need_metadata_module: bool,
) -> Box<dyn Any> {
let config = if let Some(config) = self.config {
let config = if let Some(config) = self.config.clone() {
config
} else {
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
@ -237,7 +237,7 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple {
sess.target.llvm_target.parse().unwrap()
}
fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> {
use target_lexicon::BinaryFormat;
let target_triple = crate::target_triple(sess);
@ -245,9 +245,8 @@ fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
let mut flags_builder = settings::builder();
flags_builder.enable("is_pic").unwrap();
flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
let enable_verifier =
cfg!(debug_assertions) || std::env::var("CG_CLIF_ENABLE_VERIFIER").is_ok();
flags_builder.set("enable_verifier", if enable_verifier { "true" } else { "false" }).unwrap();
let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
flags_builder.set("enable_verifier", enable_verifier).unwrap();
let tls_model = match target_triple.binary_format {
BinaryFormat::Elf => "elf_gd",

View File

@ -248,7 +248,7 @@ pub(crate) fn write_clif_file<'tcx>(
&mut clif,
&context.func,
&DisplayFunctionAnnotations {
isa: Some(&*crate::build_isa(tcx.sess)),
isa,
value_ranges: value_ranges.as_ref(),
},
)