Skip to content

Add custom rustc driver that uses cg_clif #1089

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

Merged
merged 6 commits into from
Sep 29, 2020
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
21 changes: 19 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,24 @@ If you compiled cg_clif in debug mode (aka you didn't pass `--release` to `./tes
> You should prefer using the Cargo method.

```bash
$ rustc +$(cat $cg_clif_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$cg_clif_dir/target/release/librustc_codegen_cranelift.so --sysroot $cg_clif_dir/build_sysroot/sysroot my_crate.rs
$ $cg_clif_dir/target/release/cg_clif my_crate.rs
```

### Jit mode

In jit mode cg_clif will immediately execute your code without creating an executable file.

> This requires all dependencies to be available as dynamic library.
> The jit mode will probably need cargo integration to make this possible.

```bash
$ $cg_clif_dir/cargo.sh jit
```

or

```bash
$ $cg_clif_dir/target/release/cg_clif --jit my_crate.rs
```

### Shell
Expand All @@ -45,7 +62,7 @@ These are a few functions that allow you to easily run rust code from the shell

```bash
function jit_naked() {
echo "$@" | CG_CLIF_JIT=1 rustc -Zcodegen-backend=$cg_clif_dir/target/release/librustc_codegen_cranelift.so --sysroot $cg_clif_dir/build_sysroot/sysroot - -Cprefer-dynamic
echo "$@" | $cg_clif_dir/target/release/cg_clif - --jit
}

function jit() {
Expand Down
7 changes: 6 additions & 1 deletion build_sysroot/build_sysroot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ popd >/dev/null
rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true
rm -r sysroot/ 2>/dev/null || true

# Use rustc with cg_clif as hotpluggable backend instead of the custom cg_clif driver so that
# build scripts are still compiled using cg_llvm.
export RUSTC=rustc
export RUSTFLAGS=$RUSTFLAGS" -Ztrim-diagnostic-paths=no -Zcodegen-backend=$(pwd)/../target/"$CHANNEL"/librustc_codegen_cranelift."$dylib_ext" --sysroot $(pwd)/sysroot"

# Build libs
export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked"
export RUSTFLAGS="$RUSTFLAGS -Zforce-unstable-if-unmarked -Cpanic=abort"
if [[ "$1" == "--release" ]]; then
sysroot_channel='release'
# FIXME Enable incremental again once rust-lang/rust#74946 is fixed
Expand Down
9 changes: 4 additions & 5 deletions cargo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ TOOLCHAIN=$(cat rust-toolchain)

popd >/dev/null

if [[ $(rustc -V) != $(rustc +${TOOLCHAIN} -V) ]]; then
echo "rustc_codegen_cranelift is build for $(rustc +${TOOLCHAIN} -V) but the default rustc version is $(rustc -V)."
echo "Using $(rustc +${TOOLCHAIN} -V)."
fi

cmd=$1
shift

if [[ "$cmd" = "jit" ]]; then
cargo +${TOOLCHAIN} rustc $@ -- --jit
else
cargo +${TOOLCHAIN} $cmd $@
fi
2 changes: 0 additions & 2 deletions docs/env_vars.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# List of env vars recognized by cg_clif

<dl>
<dt>CG_CLIF_JIT</dt>
<dd>Enable JIT mode to immediately run a program instead of writing an executable file.</dd>
<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>
Expand Down
9 changes: 6 additions & 3 deletions scripts/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,18 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
fi
fi

export RUSTFLAGS=$linker' -Ztrim-diagnostic-paths=no -Cpanic=abort -Cdebuginfo=2 -Zpanic-abort-tests -Zcodegen-backend='$(pwd)'/target/'$CHANNEL'/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$(pwd)'/build_sysroot/sysroot'
export RUSTDOCFLAGS=$RUSTFLAGS
export RUSTC=$(pwd)/"target/"$CHANNEL"/cg_clif"
export RUSTFLAGS=$linker
export RUSTDOCFLAGS=$linker' -Ztrim-diagnostic-paths=no -Cpanic=abort -Zpanic-abort-tests '\
'-Zcodegen-backend='$(pwd)'/target/'$CHANNEL'/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$(pwd)'/build_sysroot/sysroot'

# FIXME remove once the atomic shim is gone
if [[ `uname` == 'Darwin' ]]; then
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
fi

export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib"
export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/"$TARGET_TRIPLE"/lib:\
$(pwd)/target/"$CHANNEL":$(rustc --print sysroot)/lib"
export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH

export CG_CLIF_DISPLAY_CG_TIME=1
2 changes: 1 addition & 1 deletion scripts/filter_profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ CHANNEL="release"
pushd $(dirname "$0")/../
source scripts/config.sh
popd
CG_CLIF_JIT=1 PROFILE=$1 OUTPUT=$2 exec rustc $RUSTFLAGS $0 --crate-type bin -Cprefer-dynamic
PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS --jit $0
#*/

//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse
Expand Down
12 changes: 8 additions & 4 deletions src/atomic_shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ use crate::prelude::*;
pub static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t =
libc::PTHREAD_MUTEX_INITIALIZER;

pub(crate) fn init_global_lock(module: &mut Module<impl Backend>, bcx: &mut FunctionBuilder<'_>) {
if std::env::var("CG_CLIF_JIT").is_ok() {
pub(crate) fn init_global_lock(
module: &mut Module<impl Backend>,
bcx: &mut FunctionBuilder<'_>,
use_jit: bool,
) {
if use_jit {
// When using JIT, dylibs won't find the __cg_clif_global_atomic_mutex data object defined here,
// so instead define it in the cg_clif dylib.
// so instead we define it in the cg_clif dylib.

return;
}
Expand Down Expand Up @@ -80,7 +84,7 @@ pub(crate) fn init_global_lock_constructor(
let block = bcx.create_block();
bcx.switch_to_block(block);

crate::atomic_shim::init_global_lock(module, &mut bcx);
crate::atomic_shim::init_global_lock(module, &mut bcx, false);

bcx.ins().return_(&[]);
bcx.seal_all_blocks();
Expand Down
94 changes: 94 additions & 0 deletions src/bin/cg_clif.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#![feature(rustc_private)]

extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate rustc_session;
extern crate rustc_target;

use rustc_data_structures::profiling::print_time_passes_entry;
use rustc_interface::interface;
use rustc_session::config::ErrorOutputType;
use rustc_session::early_error;
use rustc_target::spec::PanicStrategy;

#[derive(Default)]
pub struct TimePassesCallbacks {
time_passes: bool,
}

impl rustc_driver::Callbacks for TimePassesCallbacks {
fn config(&mut self, config: &mut interface::Config) {
// If a --prints=... option has been given, we don't print the "total"
// time because it will mess up the --prints output. See #64339.
self.time_passes = config.opts.prints.is_empty()
&& (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);

// FIXME workaround for an ICE
config.opts.debugging_opts.trim_diagnostic_paths = false;

config.opts.cg.panic = Some(PanicStrategy::Abort);
config.opts.debugging_opts.panic_abort_tests = true;
config.opts.maybe_sysroot = Some(
std::env::current_exe()
.unwrap()
.parent()
.unwrap()
.parent()
.unwrap()
.parent()
.unwrap()
.join("build_sysroot")
.join("sysroot"),
);
}
}

fn main() {
let start = std::time::Instant::now();
rustc_driver::init_rustc_env_logger();
let mut callbacks = TimePassesCallbacks::default();
rustc_driver::install_ice_hook();
let exit_code = rustc_driver::catch_with_exit_code(|| {
let mut use_jit = false;

let mut args = std::env::args_os()
.enumerate()
.map(|(i, arg)| {
arg.into_string().unwrap_or_else(|arg| {
early_error(
ErrorOutputType::default(),
&format!("Argument {} is not valid Unicode: {:?}", i, arg),
)
})
})
.filter(|arg| {
if arg == "--jit" {
use_jit = true;
false
} else {
true
}
})
.collect::<Vec<_>>();
if use_jit {
args.push("-Cprefer-dynamic".to_string());
}
rustc_driver::run_compiler(
&args,
&mut callbacks,
None,
None,
Some(Box::new(move |_| {
Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend {
config: rustc_codegen_cranelift::BackendConfig {
use_jit,
}
})
})),
)
});
// The extra `\t` is necessary to align this label with the others.
print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
std::process::exit(exit_code)
}
2 changes: 1 addition & 1 deletion src/driver/aot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodege
super::codegen_mono_items(&mut cx, mono_items);
let (mut module, global_asm, debug, mut unwind_context) =
tcx.sess.time("finalize CodegenCx", || cx.finalize());
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context);
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context, false);

let codegen_result = emit_module(
tcx,
Expand Down
36 changes: 19 additions & 17 deletions src/driver/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,23 @@ use crate::prelude::*;
pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};

// Rustc opens us without the RTLD_GLOBAL flag, so __cg_clif_global_atomic_mutex will not be
// exported. We fix this by opening ourself again as global.
// FIXME remove once atomic_shim is gone
let cg_dylib = std::ffi::OsString::from(
&tcx.sess
.opts
.debugging_opts
.codegen_backend
.as_ref()
.unwrap(),
);
std::mem::forget(
libloading::os::unix::Library::open(Some(cg_dylib), libc::RTLD_NOW | libc::RTLD_GLOBAL)
.unwrap(),
);
#[cfg(unix)]
unsafe {
// When not using our custom driver rustc will open us without the RTLD_GLOBAL flag, so
// __cg_clif_global_atomic_mutex will not be exported. We fix this by opening ourself again
// as global.
// FIXME remove once atomic_shim is gone

let mut dl_info: libc::Dl_info = std::mem::zeroed();
assert_ne!(
libc::dladdr(run_jit as *const libc::c_void, &mut dl_info),
0
);
assert_ne!(
libc::dlopen(dl_info.dli_fname, libc::RTLD_NOW | libc::RTLD_GLOBAL),
std::ptr::null_mut(),
);
}

let imported_symbols = load_imported_symbols_for_jit(tcx);

Expand Down Expand Up @@ -74,7 +76,7 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
if !global_asm.is_empty() {
tcx.sess.fatal("Global asm is not supported in JIT mode");
}
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, &mut unwind_context);
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, &mut unwind_context, true);
crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context);

jit_module.finalize_definitions();
Expand All @@ -85,7 +87,7 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {

let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);

println!("Rustc codegen cranelift will JIT run the executable, because the CG_CLIF_JIT env var is set");
println!("Rustc codegen cranelift will JIT run the executable, because --jit was passed");

let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
unsafe { ::std::mem::transmute(finalized_main) };
Expand Down
12 changes: 8 additions & 4 deletions src/driver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@ pub(crate) fn codegen_crate(
tcx: TyCtxt<'_>,
metadata: EncodedMetadata,
need_metadata_module: bool,
config: crate::BackendConfig,
) -> Box<dyn Any> {
tcx.sess.abort_if_errors();

if std::env::var("CG_CLIF_JIT").is_ok()
&& tcx
if config.use_jit {
let is_executable = tcx
.sess
.crate_types()
.contains(&rustc_session::config::CrateType::Executable)
{
.contains(&rustc_session::config::CrateType::Executable);
if !is_executable {
tcx.sess.fatal("can't jit non-executable crate");
}

#[cfg(feature = "jit")]
let _: ! = jit::run_jit(tcx);

Expand Down
17 changes: 14 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,14 @@ impl<'tcx, B: Backend + 'static> CodegenCx<'tcx, B> {
}
}

struct CraneliftCodegenBackend;
#[derive(Copy, Clone, Debug)]
pub struct BackendConfig {
pub use_jit: bool,
}

pub struct CraneliftCodegenBackend {
pub config: BackendConfig,
}

impl CodegenBackend for CraneliftCodegenBackend {
fn init(&self, sess: &Session) {
Expand Down Expand Up @@ -223,7 +230,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
metadata: EncodedMetadata,
need_metadata_module: bool,
) -> Box<dyn Any> {
let res = driver::codegen_crate(tcx, metadata, need_metadata_module);
let res = driver::codegen_crate(tcx, metadata, need_metadata_module, self.config);

rustc_symbol_mangling::test::report_symbol_names(tcx);

Expand Down Expand Up @@ -345,5 +352,9 @@ fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'stat
/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
Box::new(CraneliftCodegenBackend)
Box::new(CraneliftCodegenBackend {
config: BackendConfig {
use_jit: false,
}
})
}
5 changes: 4 additions & 1 deletion src/main_shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub(crate) fn maybe_create_entry_wrapper(
tcx: TyCtxt<'_>,
module: &mut Module<impl Backend + 'static>,
unwind_context: &mut UnwindContext<'_>,
use_jit: bool,
) {
let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
Some((def_id, entry_ty)) => (
Expand All @@ -32,6 +33,7 @@ pub(crate) fn maybe_create_entry_wrapper(
unwind_context,
main_def_id,
use_start_lang_item,
use_jit,
);

fn create_entry_fn(
Expand All @@ -40,6 +42,7 @@ pub(crate) fn maybe_create_entry_wrapper(
unwind_context: &mut UnwindContext<'_>,
rust_main_def_id: DefId,
use_start_lang_item: bool,
use_jit: bool,
) {
let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
// Given that `main()` has no arguments,
Expand Down Expand Up @@ -83,7 +86,7 @@ pub(crate) fn maybe_create_entry_wrapper(
let arg_argc = bcx.append_block_param(block, m.target_config().pointer_type());
let arg_argv = bcx.append_block_param(block, m.target_config().pointer_type());

crate::atomic_shim::init_global_lock(m, &mut bcx);
crate::atomic_shim::init_global_lock(m, &mut bcx, use_jit);

let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);

Expand Down
Loading