Skip to content

Commit 0c065f9

Browse files
authored
Merge pull request #1089 from bjorn3/custom_driver
Add custom rustc driver that uses cg_clif
2 parents c046ad0 + 9a513be commit 0c065f9

File tree

14 files changed

+191
-50
lines changed

14 files changed

+191
-50
lines changed

Readme.md

+19-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,24 @@ If you compiled cg_clif in debug mode (aka you didn't pass `--release` to `./tes
3636
> You should prefer using the Cargo method.
3737
3838
```bash
39-
$ 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
39+
$ $cg_clif_dir/target/release/cg_clif my_crate.rs
40+
```
41+
42+
### Jit mode
43+
44+
In jit mode cg_clif will immediately execute your code without creating an executable file.
45+
46+
> This requires all dependencies to be available as dynamic library.
47+
> The jit mode will probably need cargo integration to make this possible.
48+
49+
```bash
50+
$ $cg_clif_dir/cargo.sh jit
51+
```
52+
53+
or
54+
55+
```bash
56+
$ $cg_clif_dir/target/release/cg_clif --jit my_crate.rs
4057
```
4158

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

4663
```bash
4764
function jit_naked() {
48-
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
65+
echo "$@" | $cg_clif_dir/target/release/cg_clif - --jit
4966
}
5067

5168
function jit() {

build_sysroot/build_sysroot.sh

+6-1
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@ popd >/dev/null
1414
rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true
1515
rm -r sysroot/ 2>/dev/null || true
1616

17+
# Use rustc with cg_clif as hotpluggable backend instead of the custom cg_clif driver so that
18+
# build scripts are still compiled using cg_llvm.
19+
export RUSTC=rustc
20+
export RUSTFLAGS=$RUSTFLAGS" -Ztrim-diagnostic-paths=no -Zcodegen-backend=$(pwd)/../target/"$CHANNEL"/librustc_codegen_cranelift."$dylib_ext" --sysroot $(pwd)/sysroot"
21+
1722
# Build libs
18-
export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked"
23+
export RUSTFLAGS="$RUSTFLAGS -Zforce-unstable-if-unmarked -Cpanic=abort"
1924
if [[ "$1" == "--release" ]]; then
2025
sysroot_channel='release'
2126
# FIXME Enable incremental again once rust-lang/rust#74946 is fixed

cargo.sh

+4-5
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ TOOLCHAIN=$(cat rust-toolchain)
1212

1313
popd >/dev/null
1414

15-
if [[ $(rustc -V) != $(rustc +${TOOLCHAIN} -V) ]]; then
16-
echo "rustc_codegen_cranelift is build for $(rustc +${TOOLCHAIN} -V) but the default rustc version is $(rustc -V)."
17-
echo "Using $(rustc +${TOOLCHAIN} -V)."
18-
fi
19-
2015
cmd=$1
2116
shift
2217

18+
if [[ "$cmd" = "jit" ]]; then
19+
cargo +${TOOLCHAIN} rustc $@ -- --jit
20+
else
2321
cargo +${TOOLCHAIN} $cmd $@
22+
fi

docs/env_vars.md

-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# List of env vars recognized by cg_clif
22

33
<dl>
4-
<dt>CG_CLIF_JIT</dt>
5-
<dd>Enable JIT mode to immediately run a program instead of writing an executable file.</dd>
64
<dt>CG_CLIF_JIT_ARGS</dt>
75
<dd>When JIT mode is enable pass these arguments to the program.</dd>
86
<dt>CG_CLIF_INCR_CACHE_DISABLED</dt>

scripts/config.sh

+6-3
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,18 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
3232
fi
3333
fi
3434

35-
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'
36-
export RUSTDOCFLAGS=$RUSTFLAGS
35+
export RUSTC=$(pwd)/"target/"$CHANNEL"/cg_clif"
36+
export RUSTFLAGS=$linker
37+
export RUSTDOCFLAGS=$linker' -Ztrim-diagnostic-paths=no -Cpanic=abort -Zpanic-abort-tests '\
38+
'-Zcodegen-backend='$(pwd)'/target/'$CHANNEL'/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$(pwd)'/build_sysroot/sysroot'
3739

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

43-
export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib"
45+
export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/"$TARGET_TRIPLE"/lib:\
46+
$(pwd)/target/"$CHANNEL":$(rustc --print sysroot)/lib"
4447
export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
4548

4649
export CG_CLIF_DISPLAY_CG_TIME=1

scripts/filter_profile.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ CHANNEL="release"
55
pushd $(dirname "$0")/../
66
source scripts/config.sh
77
popd
8-
CG_CLIF_JIT=1 PROFILE=$1 OUTPUT=$2 exec rustc $RUSTFLAGS $0 --crate-type bin -Cprefer-dynamic
8+
PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS --jit $0
99
#*/
1010

1111
//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse

src/atomic_shim.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@ use crate::prelude::*;
1010
pub static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t =
1111
libc::PTHREAD_MUTEX_INITIALIZER;
1212

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

1822
return;
1923
}
@@ -80,7 +84,7 @@ pub(crate) fn init_global_lock_constructor(
8084
let block = bcx.create_block();
8185
bcx.switch_to_block(block);
8286

83-
crate::atomic_shim::init_global_lock(module, &mut bcx);
87+
crate::atomic_shim::init_global_lock(module, &mut bcx, false);
8488

8589
bcx.ins().return_(&[]);
8690
bcx.seal_all_blocks();

src/bin/cg_clif.rs

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#![feature(rustc_private)]
2+
3+
extern crate rustc_data_structures;
4+
extern crate rustc_driver;
5+
extern crate rustc_interface;
6+
extern crate rustc_session;
7+
extern crate rustc_target;
8+
9+
use rustc_data_structures::profiling::print_time_passes_entry;
10+
use rustc_interface::interface;
11+
use rustc_session::config::ErrorOutputType;
12+
use rustc_session::early_error;
13+
use rustc_target::spec::PanicStrategy;
14+
15+
#[derive(Default)]
16+
pub struct TimePassesCallbacks {
17+
time_passes: bool,
18+
}
19+
20+
impl rustc_driver::Callbacks for TimePassesCallbacks {
21+
fn config(&mut self, config: &mut interface::Config) {
22+
// If a --prints=... option has been given, we don't print the "total"
23+
// time because it will mess up the --prints output. See #64339.
24+
self.time_passes = config.opts.prints.is_empty()
25+
&& (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);
26+
27+
// FIXME workaround for an ICE
28+
config.opts.debugging_opts.trim_diagnostic_paths = false;
29+
30+
config.opts.cg.panic = Some(PanicStrategy::Abort);
31+
config.opts.debugging_opts.panic_abort_tests = true;
32+
config.opts.maybe_sysroot = Some(
33+
std::env::current_exe()
34+
.unwrap()
35+
.parent()
36+
.unwrap()
37+
.parent()
38+
.unwrap()
39+
.parent()
40+
.unwrap()
41+
.join("build_sysroot")
42+
.join("sysroot"),
43+
);
44+
}
45+
}
46+
47+
fn main() {
48+
let start = std::time::Instant::now();
49+
rustc_driver::init_rustc_env_logger();
50+
let mut callbacks = TimePassesCallbacks::default();
51+
rustc_driver::install_ice_hook();
52+
let exit_code = rustc_driver::catch_with_exit_code(|| {
53+
let mut use_jit = false;
54+
55+
let mut args = std::env::args_os()
56+
.enumerate()
57+
.map(|(i, arg)| {
58+
arg.into_string().unwrap_or_else(|arg| {
59+
early_error(
60+
ErrorOutputType::default(),
61+
&format!("Argument {} is not valid Unicode: {:?}", i, arg),
62+
)
63+
})
64+
})
65+
.filter(|arg| {
66+
if arg == "--jit" {
67+
use_jit = true;
68+
false
69+
} else {
70+
true
71+
}
72+
})
73+
.collect::<Vec<_>>();
74+
if use_jit {
75+
args.push("-Cprefer-dynamic".to_string());
76+
}
77+
rustc_driver::run_compiler(
78+
&args,
79+
&mut callbacks,
80+
None,
81+
None,
82+
Some(Box::new(move |_| {
83+
Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend {
84+
config: rustc_codegen_cranelift::BackendConfig {
85+
use_jit,
86+
}
87+
})
88+
})),
89+
)
90+
});
91+
// The extra `\t` is necessary to align this label with the others.
92+
print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
93+
std::process::exit(exit_code)
94+
}

src/driver/aot.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodege
150150
super::codegen_mono_items(&mut cx, mono_items);
151151
let (mut module, global_asm, debug, mut unwind_context) =
152152
tcx.sess.time("finalize CodegenCx", || cx.finalize());
153-
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context);
153+
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context, false);
154154

155155
let codegen_result = emit_module(
156156
tcx,

src/driver/jit.rs

+19-17
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,23 @@ use crate::prelude::*;
1111
pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
1212
use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder};
1313

14-
// Rustc opens us without the RTLD_GLOBAL flag, so __cg_clif_global_atomic_mutex will not be
15-
// exported. We fix this by opening ourself again as global.
16-
// FIXME remove once atomic_shim is gone
17-
let cg_dylib = std::ffi::OsString::from(
18-
&tcx.sess
19-
.opts
20-
.debugging_opts
21-
.codegen_backend
22-
.as_ref()
23-
.unwrap(),
24-
);
25-
std::mem::forget(
26-
libloading::os::unix::Library::open(Some(cg_dylib), libc::RTLD_NOW | libc::RTLD_GLOBAL)
27-
.unwrap(),
28-
);
14+
#[cfg(unix)]
15+
unsafe {
16+
// When not using our custom driver rustc will open us without the RTLD_GLOBAL flag, so
17+
// __cg_clif_global_atomic_mutex will not be exported. We fix this by opening ourself again
18+
// as global.
19+
// FIXME remove once atomic_shim is gone
20+
21+
let mut dl_info: libc::Dl_info = std::mem::zeroed();
22+
assert_ne!(
23+
libc::dladdr(run_jit as *const libc::c_void, &mut dl_info),
24+
0
25+
);
26+
assert_ne!(
27+
libc::dlopen(dl_info.dli_fname, libc::RTLD_NOW | libc::RTLD_GLOBAL),
28+
std::ptr::null_mut(),
29+
);
30+
}
2931

3032
let imported_symbols = load_imported_symbols_for_jit(tcx);
3133

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

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

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

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

9092
let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
9193
unsafe { ::std::mem::transmute(finalized_main) };

src/driver/mod.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@ pub(crate) fn codegen_crate(
1616
tcx: TyCtxt<'_>,
1717
metadata: EncodedMetadata,
1818
need_metadata_module: bool,
19+
config: crate::BackendConfig,
1920
) -> Box<dyn Any> {
2021
tcx.sess.abort_if_errors();
2122

22-
if std::env::var("CG_CLIF_JIT").is_ok()
23-
&& tcx
23+
if config.use_jit {
24+
let is_executable = tcx
2425
.sess
2526
.crate_types()
26-
.contains(&rustc_session::config::CrateType::Executable)
27-
{
27+
.contains(&rustc_session::config::CrateType::Executable);
28+
if !is_executable {
29+
tcx.sess.fatal("can't jit non-executable crate");
30+
}
31+
2832
#[cfg(feature = "jit")]
2933
let _: ! = jit::run_jit(tcx);
3034

src/lib.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,14 @@ impl<'tcx, B: Backend + 'static> CodegenCx<'tcx, B> {
181181
}
182182
}
183183

184-
struct CraneliftCodegenBackend;
184+
#[derive(Copy, Clone, Debug)]
185+
pub struct BackendConfig {
186+
pub use_jit: bool,
187+
}
188+
189+
pub struct CraneliftCodegenBackend {
190+
pub config: BackendConfig,
191+
}
185192

186193
impl CodegenBackend for CraneliftCodegenBackend {
187194
fn init(&self, sess: &Session) {
@@ -223,7 +230,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
223230
metadata: EncodedMetadata,
224231
need_metadata_module: bool,
225232
) -> Box<dyn Any> {
226-
let res = driver::codegen_crate(tcx, metadata, need_metadata_module);
233+
let res = driver::codegen_crate(tcx, metadata, need_metadata_module, self.config);
227234

228235
rustc_symbol_mangling::test::report_symbol_names(tcx);
229236

@@ -345,5 +352,9 @@ fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'stat
345352
/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
346353
#[no_mangle]
347354
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
348-
Box::new(CraneliftCodegenBackend)
355+
Box::new(CraneliftCodegenBackend {
356+
config: BackendConfig {
357+
use_jit: false,
358+
}
359+
})
349360
}

src/main_shim.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub(crate) fn maybe_create_entry_wrapper(
99
tcx: TyCtxt<'_>,
1010
module: &mut Module<impl Backend + 'static>,
1111
unwind_context: &mut UnwindContext<'_>,
12+
use_jit: bool,
1213
) {
1314
let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
1415
Some((def_id, entry_ty)) => (
@@ -32,6 +33,7 @@ pub(crate) fn maybe_create_entry_wrapper(
3233
unwind_context,
3334
main_def_id,
3435
use_start_lang_item,
36+
use_jit,
3537
);
3638

3739
fn create_entry_fn(
@@ -40,6 +42,7 @@ pub(crate) fn maybe_create_entry_wrapper(
4042
unwind_context: &mut UnwindContext<'_>,
4143
rust_main_def_id: DefId,
4244
use_start_lang_item: bool,
45+
use_jit: bool,
4346
) {
4447
let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
4548
// Given that `main()` has no arguments,
@@ -83,7 +86,7 @@ pub(crate) fn maybe_create_entry_wrapper(
8386
let arg_argc = bcx.append_block_param(block, m.target_config().pointer_type());
8487
let arg_argv = bcx.append_block_param(block, m.target_config().pointer_type());
8588

86-
crate::atomic_shim::init_global_lock(m, &mut bcx);
89+
crate::atomic_shim::init_global_lock(m, &mut bcx, use_jit);
8790

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

0 commit comments

Comments
 (0)