Skip to content

Commit 82d72d0

Browse files
committed
Add -Zjit-mode flag and use it in cg_clif
This flag tells the codegen backend to immediately execute the code it builds. This is exactly what miri needs as it is unable to produce real executables. Adding a builtin flag would allow cargo to add native support for this without miri needing to do a bunch of hacks in its cargo wrapper. Furthermore cg_clif also has a jit mode that benefits from it.
1 parent d2218f5 commit 82d72d0

14 files changed

Lines changed: 172 additions & 130 deletions

File tree

compiler/rustc_codegen_cranelift/docs/usage.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ $ $cg_clif_dir/dist/cargo-clif jit
3838
or
3939

4040
```bash
41-
$ $cg_clif_dir/dist/rustc-clif -Cllvm-args=jit-mode -Cprefer-dynamic my_crate.rs
41+
$ $cg_clif_dir/dist/rustc-clif -Zjit-mode -Cprefer-dynamic my_crate.rs
4242
```
4343

4444
## Shell
@@ -47,7 +47,7 @@ These are a few functions that allow you to easily run rust code from the shell
4747

4848
```bash
4949
function jit_naked() {
50-
echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Cllvm-args=jit-mode -Cprefer-dynamic
50+
echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-options -Zjit-mode -Cprefer-dynamic
5151
}
5252

5353
function jit() {

compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,7 @@ fn main() {
5151
args.remove(0);
5252
IntoIterator::into_iter(["rustc".to_string()])
5353
.chain(args)
54-
.chain([
55-
"--".to_string(),
56-
"-Zunstable-options".to_string(),
57-
"-Cllvm-args=jit-mode".to_string(),
58-
])
54+
.chain(["--".to_string(), "-Zjit-mode".to_string()])
5955
.collect()
6056
}
6157
_ => args,

compiler/rustc_codegen_cranelift/scripts/filter_profile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
pushd $(dirname "$0")/../
55
RUSTC="$(pwd)/dist/rustc-clif"
66
popd
7-
PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=jit-mode -Cprefer-dynamic $0
7+
PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zjit-mode -Cprefer-dynamic $0
88
#*/
99

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

compiler/rustc_codegen_cranelift/src/config.rs

Lines changed: 0 additions & 43 deletions
This file was deleted.

compiler/rustc_codegen_cranelift/src/driver/jit.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
use std::ffi::CString;
55
use std::os::raw::{c_char, c_int};
6+
use std::process::ExitCode;
67

78
use cranelift_jit::{JITBuilder, JITModule};
89
use rustc_codegen_ssa::CrateInfo;
@@ -18,12 +19,12 @@ use crate::unwind_module::UnwindModule;
1819

1920
fn create_jit_module(
2021
tcx: TyCtxt<'_>,
21-
crate_info: &CrateInfo,
22+
crate_info: CrateInfo,
2223
) -> (UnwindModule<JITModule>, Option<DebugContext>) {
2324
let isa = crate::build_isa(tcx.sess, true);
2425
let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
2526
crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
26-
jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info.clone()));
27+
jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info));
2728
let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false);
2829

2930
let cx = DebugContext::new(tcx, jit_module.isa(), false, "dummy_cgu_name");
@@ -33,13 +34,10 @@ fn create_jit_module(
3334
(jit_module, cx)
3435
}
3536

36-
pub(crate) fn run_jit(tcx: TyCtxt<'_>, crate_info: &CrateInfo, jit_args: Vec<String>) -> ! {
37-
if !tcx.crate_types().contains(&rustc_session::config::CrateType::Executable) {
38-
tcx.dcx().fatal("can't jit non-executable crate");
39-
}
40-
37+
pub(crate) fn run_jit(tcx: TyCtxt<'_>, target_cpu: String, jit_args: Vec<String>) -> ExitCode {
4138
let output_filenames = tcx.output_filenames(());
4239
let should_write_ir = crate::pretty_clif::should_write_ir(tcx.sess);
40+
let crate_info = CrateInfo::new(tcx, target_cpu);
4341
let (mut jit_module, mut debug_context) = create_jit_module(tcx, crate_info);
4442
let mut cached_context = Context::new();
4543

@@ -114,7 +112,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, crate_info: &CrateInfo, jit_args: Vec<Str
114112
argv.push(std::ptr::null());
115113

116114
let ret = f(args.len() as c_int, argv.as_ptr());
117-
std::process::exit(ret);
115+
ExitCode::from(ret as u8)
118116
}
119117

120118
fn codegen_and_compile_fn<'tcx>(

compiler/rustc_codegen_cranelift/src/lib.rs

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ extern crate rustc_target;
3333
extern crate rustc_driver;
3434

3535
use std::any::Any;
36-
use std::cell::OnceCell;
3736
use std::env;
37+
use std::process::ExitCode;
3838
use std::sync::Arc;
3939

4040
use cranelift_codegen::isa::TargetIsa;
@@ -48,7 +48,6 @@ use rustc_session::config::OutputFilenames;
4848
use rustc_span::{Symbol, sym};
4949
use rustc_target::spec::{Abi, Arch, Env, Os};
5050

51-
pub use crate::config::*;
5251
use crate::prelude::*;
5352

5453
mod abi;
@@ -61,7 +60,6 @@ mod codegen_i128;
6160
mod common;
6261
mod compiler_builtins;
6362
mod concurrency_limiter;
64-
mod config;
6563
mod constant;
6664
mod debuginfo;
6765
mod discriminant;
@@ -119,9 +117,7 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
119117
}
120118
}
121119

122-
pub struct CraneliftCodegenBackend {
123-
pub config: OnceCell<BackendConfig>,
124-
}
120+
pub struct CraneliftCodegenBackend;
125121

126122
impl CodegenBackend for CraneliftCodegenBackend {
127123
fn name(&self) -> &'static str {
@@ -141,15 +137,6 @@ impl CodegenBackend for CraneliftCodegenBackend {
141137
sess.dcx()
142138
.fatal("`-Cinstrument-coverage` is LLVM specific and not supported by Cranelift");
143139
}
144-
145-
let config = self.config.get_or_init(|| {
146-
BackendConfig::from_opts(&sess.opts.cg.llvm_args)
147-
.unwrap_or_else(|err| sess.dcx().fatal(err))
148-
});
149-
150-
if config.jit_mode && !sess.opts.output_types.should_codegen() {
151-
sess.dcx().fatal("JIT mode doesn't work with `cargo check`");
152-
}
153140
}
154141

155142
fn target_config(&self, sess: &Session) -> TargetConfig {
@@ -211,16 +198,17 @@ impl CodegenBackend for CraneliftCodegenBackend {
211198

212199
fn codegen_crate(&self, tcx: TyCtxt<'_>, _crate_info: &CrateInfo) -> Box<dyn Any> {
213200
info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE));
214-
let config = self.config.get().unwrap();
215-
if config.jit_mode {
216-
#[cfg(feature = "jit")]
217-
driver::jit::run_jit(tcx, _crate_info, config.jit_args.clone());
218201

219-
#[cfg(not(feature = "jit"))]
220-
tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift");
221-
} else {
222-
driver::aot::run_aot(tcx)
202+
for opt in &tcx.sess.opts.cg.llvm_args {
203+
if opt.starts_with("-import-instr-limit") {
204+
// Silently ignore -import-instr-limit. It is set by rust's build system even when
205+
// testing cg_clif.
206+
continue;
207+
}
208+
tcx.sess.dcx().fatal(format!("Unknown option `{}`", opt));
223209
}
210+
211+
driver::aot::run_aot(tcx)
224212
}
225213

226214
fn join_codegen(
@@ -231,6 +219,29 @@ impl CodegenBackend for CraneliftCodegenBackend {
231219
) -> (CompiledModules, FxIndexMap<WorkProductId, WorkProduct>) {
232220
ongoing_codegen.downcast::<driver::aot::OngoingCodegen>().unwrap().join(sess, outputs)
233221
}
222+
223+
fn jit_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, args: Vec<String>) -> ExitCode {
224+
info!("jit crate {}", tcx.crate_name(LOCAL_CRATE));
225+
226+
for opt in &tcx.sess.opts.cg.llvm_args {
227+
if opt.starts_with("-import-instr-limit") {
228+
// Silently ignore -import-instr-limit. It is set by rust's build system even when
229+
// testing cg_clif.
230+
continue;
231+
}
232+
tcx.sess.dcx().fatal(format!("Unknown option `{}`", opt));
233+
}
234+
235+
#[cfg(feature = "jit")]
236+
#[allow(unreachable_code)]
237+
return driver::jit::run_jit(tcx, self.target_cpu(&tcx.sess), args);
238+
239+
#[cfg(not(feature = "jit"))]
240+
{
241+
let _ = args;
242+
tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift");
243+
}
244+
}
234245
}
235246

236247
/// Determine if the Cranelift ir verifier should run.
@@ -360,5 +371,5 @@ fn build_isa(sess: &Session, jit: bool) -> Arc<dyn TargetIsa + 'static> {
360371
/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
361372
#[unsafe(no_mangle)]
362373
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
363-
Box::new(CraneliftCodegenBackend { config: OnceCell::new() })
374+
Box::new(CraneliftCodegenBackend)
364375
}

compiler/rustc_codegen_ssa/src/traits/backend.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::any::Any;
22
use std::hash::Hash;
3+
use std::process::ExitCode;
34

45
use rustc_ast::expand::allocator::AllocatorMethod;
56
use rustc_data_structures::fx::FxIndexMap;
@@ -138,6 +139,12 @@ pub trait CodegenBackend {
138139
self.name(),
139140
);
140141
}
142+
143+
/// Used in place of [`codegen_crate`](Self::codegen_crate) when `-Zjit-mode` is passed.
144+
fn jit_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, args: Vec<String>) -> ExitCode {
145+
let _ = args;
146+
tcx.sess.dcx().fatal("-Zjit-mode not supported by the active codegen backend")
147+
}
141148
}
142149

143150
pub trait ExtraBackendMethods:

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,15 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
180180
// the compiler with @empty_file as argv[0] and no more arguments.
181181
let at_args = at_args.get(1..).unwrap_or_default();
182182

183-
let args = args::arg_expand_all(&default_early_dcx, at_args);
183+
let mut args = args::arg_expand_all(&default_early_dcx, at_args);
184+
185+
let (args, jit_args) = if let Some(idx) = args.iter().position(|arg| arg == "--") {
186+
let mut jit_args = args.split_off(idx);
187+
jit_args.remove(0);
188+
(args, jit_args)
189+
} else {
190+
(args, vec![])
191+
};
184192

185193
let (matches, help_only) = match handle_options(&default_early_dcx, &args) {
186194
HandledOptions::None => return,
@@ -201,6 +209,10 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
201209
let has_input = input.is_some();
202210
let (odir, ofile) = make_output(&matches);
203211

212+
if !jit_args.is_empty() && !sopts.unstable_opts.jit_mode {
213+
default_early_dcx.early_fatal("passing arguments after -- requires -Zjit-mode");
214+
}
215+
204216
drop(default_early_dcx);
205217

206218
let mut config = interface::Config {
@@ -338,15 +350,15 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
338350
}
339351
}
340352

341-
Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend))
353+
Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend, jit_args))
342354
});
343355

344356
// Linking is done outside the `compiler.enter()` so that the
345357
// `GlobalCtxt` within `Queries` can be freed as early as possible.
346358
if let Some(linker) = linker {
347359
linker.link(sess, codegen_backend);
348360
}
349-
})
361+
});
350362
}
351363

352364
fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) {

compiler/rustc_interface/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// tidy-alphabetical-start
22
#![feature(decl_macro)]
3+
#![feature(exitcode_exit_method)]
34
#![feature(file_buffered)]
45
#![feature(iter_intersperse)]
56
#![feature(try_blocks)]

compiler/rustc_interface/src/passes.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::any::Any;
22
use std::ffi::{OsStr, OsString};
33
use std::io::{self, BufWriter, Write};
44
use std::path::{Path, PathBuf};
5+
use std::process::ExitCode;
56
use std::sync::{Arc, LazyLock, OnceLock};
67
use std::{env, fs, iter};
78

@@ -1189,14 +1190,8 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
11891190
}
11901191
}
11911192

1192-
/// Runs the codegen backend, after which the AST and analysis can
1193-
/// be discarded.
1194-
pub(crate) fn start_codegen<'tcx>(
1195-
codegen_backend: &dyn CodegenBackend,
1196-
tcx: TyCtxt<'tcx>,
1197-
) -> (Box<dyn Any>, CrateInfo, EncodedMetadata) {
1198-
tcx.sess.timings.start_section(tcx.sess.dcx(), TimingSection::Codegen);
1199-
1193+
/// A couple of checks that need to run before we run codegen.
1194+
fn pre_codegen_checks(tcx: TyCtxt<'_>) {
12001195
// Hook for tests.
12011196
if let Some((def_id, _)) = tcx.entry_fn(())
12021197
&& find_attr!(tcx, def_id, RustcDelayedBugFromInsideQuery)
@@ -1216,6 +1211,17 @@ pub(crate) fn start_codegen<'tcx>(
12161211
if let Some(guar) = tcx.sess.dcx().has_errors_or_delayed_bugs() {
12171212
guar.raise_fatal();
12181213
}
1214+
}
1215+
1216+
/// Runs the codegen backend, after which the AST and analysis can
1217+
/// be discarded.
1218+
pub(crate) fn start_codegen<'tcx>(
1219+
codegen_backend: &dyn CodegenBackend,
1220+
tcx: TyCtxt<'tcx>,
1221+
) -> (Box<dyn Any>, CrateInfo, EncodedMetadata) {
1222+
tcx.sess.timings.start_section(tcx.sess.dcx(), TimingSection::Codegen);
1223+
1224+
pre_codegen_checks(tcx);
12191225

12201226
info!("Pre-codegen\n{:?}", tcx.debug_stats());
12211227

@@ -1246,6 +1252,16 @@ pub(crate) fn start_codegen<'tcx>(
12461252
(codegen, crate_info, metadata)
12471253
}
12481254

1255+
pub fn jit_crate<'tcx>(
1256+
codegen_backend: &dyn CodegenBackend,
1257+
tcx: TyCtxt<'tcx>,
1258+
args: Vec<String>,
1259+
) -> ExitCode {
1260+
pre_codegen_checks(tcx);
1261+
1262+
tcx.sess.time("jit_crate", move || codegen_backend.jit_crate(tcx, args))
1263+
}
1264+
12491265
/// Compute and validate the crate name.
12501266
pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol {
12511267
// We validate *all* occurrences of `#![crate_name]`, pick the first find and

0 commit comments

Comments
 (0)