Skip to content

Commit 037f86f

Browse files
committed
Use -Zjit-mode in miri
If cargo gets native support for -Zjit-mode, this should allow simplifying cargo-miri a fair bit.
1 parent 53a7ce3 commit 037f86f

2 files changed

Lines changed: 93 additions & 26 deletions

File tree

src/tools/miri/src/bin/miri.rs

Lines changed: 85 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extern crate rustc_hir_analysis;
1818
extern crate rustc_interface;
1919
extern crate rustc_log;
2020
extern crate rustc_middle;
21+
extern crate rustc_query_system;
2122
extern crate rustc_session;
2223
extern crate rustc_span;
2324
extern crate rustc_target;
@@ -38,9 +39,12 @@ extern crate tikv_jemalloc_sys as _;
3839

3940
mod log;
4041

42+
use std::any::Any;
43+
use std::cell::RefCell;
4144
use std::env;
4245
use std::num::{NonZero, NonZeroI32};
4346
use std::ops::Range;
47+
use std::process::ExitCode;
4448
use std::rc::Rc;
4549
use std::str::FromStr;
4650
use std::sync::Once;
@@ -52,6 +56,8 @@ use miri::{
5256
};
5357
use rustc_abi::ExternAbi;
5458
use rustc_codegen_ssa::traits::CodegenBackend;
59+
use rustc_codegen_ssa::{CodegenResults, TargetConfig};
60+
use rustc_data_structures::fx::FxIndexMap;
5561
use rustc_data_structures::sync::{self, DynSync};
5662
use rustc_driver::Compilation;
5763
use rustc_hir::def_id::LOCAL_CRATE;
@@ -67,8 +73,9 @@ use rustc_middle::middle::exported_symbols::{
6773
use rustc_middle::query::LocalCrate;
6874
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
6975
use rustc_middle::ty::{self, Ty, TyCtxt};
70-
use rustc_session::EarlyDiagCtxt;
71-
use rustc_session::config::{CrateType, ErrorOutputType, OptLevel, Options};
76+
use rustc_query_system::dep_graph::{WorkProduct, WorkProductId};
77+
use rustc_session::config::{CrateType, ErrorOutputType, OptLevel, Options, OutputFilenames};
78+
use rustc_session::{EarlyDiagCtxt, Session};
7279
use rustc_span::def_id::DefId;
7380
use rustc_target::spec::Target;
7481

@@ -193,15 +200,64 @@ fn make_miri_codegen_backend(opts: &Options, target: &Target) -> Box<dyn Codegen
193200
}
194201

195202
impl rustc_driver::Callbacks for MiriCompilerCalls {
196-
fn config(&mut self, config: &mut rustc_interface::interface::Config) {
197-
config.make_codegen_backend = Some(Box::new(make_miri_codegen_backend));
203+
fn config(&mut self, config: &mut Config) {
204+
let mut miri_config = self.miri_config.take();
205+
let mut many_seeds = self.many_seeds.take();
206+
207+
config.make_codegen_backend = Some(Box::new(move |opts, target| {
208+
let early_dcx = EarlyDiagCtxt::new(opts.error_format);
209+
210+
// Use the target_config method of the default codegen backend (eg LLVM) to ensure the
211+
// calculated target features match said backend by respecting eg -Ctarget-cpu.
212+
let target_config_backend =
213+
rustc_interface::util::get_codegen_backend(&early_dcx, &opts.sysroot, None, target);
214+
let target_config_backend_init = Once::new();
215+
216+
Box::new(MiriCodegenBackend {
217+
miri_config: RefCell::new(miri_config.take()),
218+
many_seeds: RefCell::new(many_seeds.take()),
219+
target_config_override: Box::new(move |sess| {
220+
target_config_backend_init.call_once(|| target_config_backend.init(sess));
221+
target_config_backend.target_config(sess)
222+
}),
223+
})
224+
}));
198225
}
226+
}
199227

200-
fn after_analysis<'tcx>(
201-
&mut self,
202-
_: &rustc_interface::interface::Compiler,
203-
tcx: TyCtxt<'tcx>,
204-
) -> Compilation {
228+
struct MiriCodegenBackend {
229+
miri_config: RefCell<Option<MiriConfig>>,
230+
many_seeds: RefCell<Option<ManySeedsConfig>>,
231+
target_config_override: Box<dyn Fn(&Session) -> TargetConfig>,
232+
}
233+
234+
impl CodegenBackend for MiriCodegenBackend {
235+
fn name(&self) -> &'static str {
236+
"miri"
237+
}
238+
239+
fn locale_resource(&self) -> &'static str {
240+
""
241+
}
242+
243+
fn target_config(&self, sess: &Session) -> TargetConfig {
244+
(self.target_config_override)(sess)
245+
}
246+
247+
fn codegen_crate<'tcx>(&self, _tcx: TyCtxt<'tcx>) -> Box<dyn Any> {
248+
unreachable!()
249+
}
250+
251+
fn join_codegen(
252+
&self,
253+
_ongoing_codegen: Box<dyn Any>,
254+
_sess: &Session,
255+
_outputs: &OutputFilenames,
256+
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
257+
unreachable!()
258+
}
259+
260+
fn jit_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, mut args: Vec<String>) -> ExitCode {
205261
// Compilation is done, interpretation is starting. Deal with diagnostics from the
206262
// compilation part. We cannot call `sess.finish_diagnostics()` as then "aborting due to
207263
// previous errors" gets printed twice.
@@ -219,9 +275,10 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
219275
let (entry_def_id, entry_type) = entry_fn(tcx);
220276

221277
// Obtain and complete the Miri configuration.
222-
let mut config = self.miri_config.take().expect("after_analysis must only be called once");
278+
let config = self.miri_config.take().expect("after_analysis must only be called once");
279+
223280
// Add filename to `miri` arguments.
224-
config.args.insert(0, tcx.sess.io.input.filestem().to_string());
281+
args.insert(0, tcx.sess.io.input.filestem().to_string());
225282

226283
// Adjust working directory for interpretation.
227284
if let Some(cwd) = env::var_os("MIRI_CWD") {
@@ -245,20 +302,27 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
245302

246303
// Invoke the interpreter.
247304
let res = if config.genmc_config.is_some() {
248-
assert!(self.many_seeds.is_none());
305+
assert!(self.many_seeds.borrow().is_none());
249306
run_genmc_mode(tcx, &config, |genmc_ctx: Rc<GenmcCtx>| {
250-
miri::eval_entry(tcx, entry_def_id, entry_type, &config, Some(genmc_ctx))
307+
miri::eval_entry(tcx, entry_def_id, entry_type, &args, &config, Some(genmc_ctx))
251308
})
252309
} else if let Some(many_seeds) = self.many_seeds.take() {
253310
assert!(config.seed.is_none());
254311
run_many_seeds(many_seeds, |seed| {
255312
let mut config = config.clone();
256313
config.seed = Some(seed);
257314
eprintln!("Trying seed: {seed}");
258-
miri::eval_entry(tcx, entry_def_id, entry_type, &config, /* genmc_ctx */ None)
315+
miri::eval_entry(
316+
tcx,
317+
entry_def_id,
318+
entry_type,
319+
&args,
320+
&config,
321+
/* genmc_ctx */ None,
322+
)
259323
})
260324
} else {
261-
miri::eval_entry(tcx, entry_def_id, entry_type, &config, None)
325+
miri::eval_entry(tcx, entry_def_id, entry_type, &args, &config, None)
262326
};
263327
// Process interpreter result.
264328
if let Err(return_code) = res {
@@ -486,6 +550,7 @@ fn main() {
486550

487551
let mut rustc_args = vec![];
488552
let mut after_dashdash = false;
553+
let mut guest_args = vec![];
489554

490555
// Note that we require values to be given with `=`, not with a space.
491556
// This matches how rustc parses `-Z`.
@@ -498,7 +563,7 @@ fn main() {
498563
rustc_args.extend(miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string));
499564
} else if after_dashdash {
500565
// Everything that comes after `--` is forwarded to the interpreted crate.
501-
miri_config.args.push(arg);
566+
guest_args.push(arg);
502567
} else if arg == "--" {
503568
after_dashdash = true;
504569
} else if arg == "-Zmiri-disable-validation" {
@@ -745,7 +810,6 @@ fn main() {
745810
many_seeds.map(|seeds| ManySeedsConfig { seeds, keep_going: many_seeds_keep_going });
746811

747812
debug!("rustc arguments: {:?}", rustc_args);
748-
debug!("crate arguments: {:?}", miri_config.args);
749813
if !miri_config.native_lib.is_empty() && miri_config.native_lib_enable_tracing {
750814
// SAFETY: No other threads are running
751815
#[cfg(all(unix, feature = "native-lib"))]
@@ -756,5 +820,9 @@ fn main() {
756820
);
757821
}
758822
}
823+
rustc_args.push("-Zjit-mode".to_owned());
824+
rustc_args.push("--".to_owned());
825+
rustc_args.extend(guest_args);
826+
759827
run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds))
760828
}

src/tools/miri/src/eval.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ pub struct MiriConfig {
5454
pub forwarded_env_vars: Vec<String>,
5555
/// Additional environment variables that should be set in the interpreted program.
5656
pub set_env_vars: FxHashMap<String, String>,
57-
/// Command-line arguments passed to the interpreted program.
58-
pub args: Vec<String>,
5957
/// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
6058
pub seed: Option<u64>,
6159
/// The stacked borrows pointer ids to report about.
@@ -130,7 +128,6 @@ impl Default for MiriConfig {
130128
ignore_leaks: false,
131129
forwarded_env_vars: vec![],
132130
set_env_vars: FxHashMap::default(),
133-
args: vec![],
134131
seed: None,
135132
tracked_pointer_tags: FxHashSet::default(),
136133
tracked_alloc_ids: FxHashSet::default(),
@@ -276,6 +273,7 @@ pub fn create_ecx<'tcx>(
276273
tcx: TyCtxt<'tcx>,
277274
entry_id: DefId,
278275
entry_type: MiriEntryFnType,
276+
args: &[String],
279277
config: &MiriConfig,
280278
genmc_ctx: Option<Rc<GenmcCtx>>,
281279
) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> {
@@ -299,12 +297,11 @@ pub fn create_ecx<'tcx>(
299297
}
300298

301299
// Compute argc and argv from `config.args`.
302-
let argc =
303-
ImmTy::from_int(i64::try_from(config.args.len()).unwrap(), ecx.machine.layouts.isize);
300+
let argc = ImmTy::from_int(i64::try_from(args.len()).unwrap(), ecx.machine.layouts.isize);
304301
let argv = {
305302
// Put each argument in memory, collect pointers.
306-
let mut argvs = Vec::<Immediate<Provenance>>::with_capacity(config.args.len());
307-
for arg in config.args.iter() {
303+
let mut argvs = Vec::<Immediate<Provenance>>::with_capacity(args.len());
304+
for arg in args.iter() {
308305
// Make space for `0` terminator.
309306
let size = u64::try_from(arg.len()).unwrap().strict_add(1);
310307
let arg_type = Ty::new_array(tcx, tcx.types.u8, size);
@@ -342,7 +339,7 @@ pub fn create_ecx<'tcx>(
342339
// Store command line as UTF-16 for Windows `GetCommandLineW`.
343340
if tcx.sess.target.os == Os::Windows {
344341
// Construct a command string with all the arguments.
345-
let cmd_utf16: Vec<u16> = args_to_utf16_command_string(config.args.iter());
342+
let cmd_utf16: Vec<u16> = args_to_utf16_command_string(args.iter());
346343

347344
let cmd_type =
348345
Ty::new_array(tcx, tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap());
@@ -458,13 +455,15 @@ pub fn eval_entry<'tcx>(
458455
tcx: TyCtxt<'tcx>,
459456
entry_id: DefId,
460457
entry_type: MiriEntryFnType,
458+
args: &[String],
461459
config: &MiriConfig,
462460
genmc_ctx: Option<Rc<GenmcCtx>>,
463461
) -> Result<(), NonZeroI32> {
464462
// Copy setting before we move `config`.
465463
let ignore_leaks = config.ignore_leaks;
466464

467-
let mut ecx = match create_ecx(tcx, entry_id, entry_type, config, genmc_ctx).report_err() {
465+
let mut ecx = match create_ecx(tcx, entry_id, entry_type, args, config, genmc_ctx).report_err()
466+
{
468467
Ok(v) => v,
469468
Err(err) => {
470469
let (kind, backtrace) = err.into_parts();

0 commit comments

Comments
 (0)