Skip to content

Commit 58250bf

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 82d72d0 commit 58250bf

2 files changed

Lines changed: 92 additions & 26 deletions

File tree

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

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ extern crate rustc_hir_analysis;
1616
extern crate rustc_interface;
1717
extern crate rustc_log;
1818
extern crate rustc_middle;
19+
extern crate rustc_query_system;
1920
extern crate rustc_session;
2021
extern crate rustc_span;
2122
extern crate rustc_target;
@@ -36,6 +37,8 @@ extern crate tikv_jemalloc_sys as _;
3637

3738
mod log;
3839

40+
use std::any::Any;
41+
use std::cell::RefCell;
3942
use std::env;
4043
use std::num::{NonZero, NonZeroI32};
4144
use std::ops::Range;
@@ -51,6 +54,8 @@ use miri::{
5154
};
5255
use rustc_abi::ExternAbi;
5356
use rustc_codegen_ssa::traits::CodegenBackend;
57+
use rustc_codegen_ssa::{CodegenResults, TargetConfig};
58+
use rustc_data_structures::fx::FxIndexMap;
5459
use rustc_data_structures::sync::{self, DynSync};
5560
use rustc_driver::Compilation;
5661
use rustc_hir::def_id::LOCAL_CRATE;
@@ -66,8 +71,9 @@ use rustc_middle::middle::exported_symbols::{
6671
use rustc_middle::query::LocalCrate;
6772
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
6873
use rustc_middle::ty::{self, Ty, TyCtxt};
69-
use rustc_session::EarlyDiagCtxt;
70-
use rustc_session::config::{CrateType, ErrorOutputType, OptLevel, Options};
74+
use rustc_query_system::dep_graph::{WorkProduct, WorkProductId};
75+
use rustc_session::config::{CrateType, ErrorOutputType, OptLevel, Options, OutputFilenames};
76+
use rustc_session::{EarlyDiagCtxt, Session};
7177
use rustc_span::def_id::DefId;
7278
use rustc_target::spec::Target;
7379

@@ -192,15 +198,64 @@ fn make_miri_codegen_backend(opts: &Options, target: &Target) -> Box<dyn Codegen
192198
}
193199

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

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

220275
// Obtain and complete the Miri configuration.
221-
let mut config = self.miri_config.take().expect("after_analysis must only be called once");
276+
let config = self.miri_config.take().expect("after_analysis must only be called once");
277+
222278
// Add filename to `miri` arguments.
223-
config.args.insert(0, tcx.sess.io.input.filestem().to_string());
279+
args.insert(0, tcx.sess.io.input.filestem().to_string());
224280

225281
// Adjust working directory for interpretation.
226282
if let Some(cwd) = env::var_os("MIRI_CWD") {
@@ -244,20 +300,27 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
244300

245301
// Invoke the interpreter.
246302
let res = if config.genmc_config.is_some() {
247-
assert!(self.many_seeds.is_none());
303+
assert!(self.many_seeds.borrow().is_none());
248304
run_genmc_mode(tcx, &config, |genmc_ctx: Rc<GenmcCtx>| {
249-
miri::eval_entry(tcx, entry_def_id, entry_type, &config, Some(genmc_ctx))
305+
miri::eval_entry(tcx, entry_def_id, entry_type, &args, &config, Some(genmc_ctx))
250306
})
251307
} else if let Some(many_seeds) = self.many_seeds.take() {
252308
assert!(config.seed.is_none());
253309
run_many_seeds(many_seeds, |seed| {
254310
let mut config = config.clone();
255311
config.seed = Some(seed);
256312
eprintln!("Trying seed: {seed}");
257-
miri::eval_entry(tcx, entry_def_id, entry_type, &config, /* genmc_ctx */ None)
313+
miri::eval_entry(
314+
tcx,
315+
entry_def_id,
316+
entry_type,
317+
&args,
318+
&config,
319+
/* genmc_ctx */ None,
320+
)
258321
})
259322
} else {
260-
miri::eval_entry(tcx, entry_def_id, entry_type, &config, None)
323+
miri::eval_entry(tcx, entry_def_id, entry_type, &args, &config, None)
261324
};
262325
// Process interpreter result.
263326
if let Err(return_code) = res {
@@ -487,6 +550,7 @@ fn main() -> ExitCode {
487550

488551
let mut rustc_args = vec![];
489552
let mut after_dashdash = false;
553+
let mut guest_args = vec![];
490554

491555
// Note that we require values to be given with `=`, not with a space.
492556
// This matches how rustc parses `-Z`.
@@ -499,7 +563,7 @@ fn main() -> ExitCode {
499563
rustc_args.extend(miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string));
500564
} else if after_dashdash {
501565
// Everything that comes after `--` is forwarded to the interpreted crate.
502-
miri_config.args.push(arg);
566+
guest_args.push(arg);
503567
} else if arg == "--" {
504568
after_dashdash = true;
505569
} else if arg == "-Zmiri-disable-validation" {
@@ -746,7 +810,6 @@ fn main() -> ExitCode {
746810
many_seeds.map(|seeds| ManySeedsConfig { seeds, keep_going: many_seeds_keep_going });
747811

748812
debug!("rustc arguments: {:?}", rustc_args);
749-
debug!("crate arguments: {:?}", miri_config.args);
750813
if !miri_config.native_lib.is_empty() && miri_config.native_lib_enable_tracing {
751814
// SAFETY: No other threads are running
752815
#[cfg(all(unix, feature = "native-lib"))]
@@ -757,5 +820,9 @@ fn main() -> ExitCode {
757820
);
758821
}
759822
}
823+
rustc_args.push("-Zjit-mode".to_owned());
824+
rustc_args.push("--".to_owned());
825+
rustc_args.extend(guest_args);
826+
760827
run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds))
761828
}

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)