commit cf49d6b080bb685304c63379a3e101dc7df4ab14 Author: Scott Olson Date: Thu Nov 12 15:50:58 2015 -0600 Add the interpreter from my rustc branch and hook it up to CompileController. diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..ea8c4bf7f35 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000000..b86c754ccdf --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "miri" +version = "0.1.0" + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000000..8963f7a6ab8 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "miri" +version = "0.1.0" +authors = ["Scott Olson "] +description = "An experimental interpreter for Rust MIR." +repository = "https://github.com/tsion/miri" +license = "ISC" diff --git a/src/interpreter.rs b/src/interpreter.rs new file mode 100644 index 00000000000..2382a5d3077 --- /dev/null +++ b/src/interpreter.rs @@ -0,0 +1,109 @@ +use rustc::front; +use rustc::middle::ty; +use rustc_mir::repr::{self as mir, Mir}; +use rustc_mir::mir_map::MirMap; +use syntax::attr::AttrMetaMethods; + +#[derive(Clone, Debug)] +enum Value { + Uninit, + Int(i64), +} + +struct Interpreter<'tcx> { + mir: &'tcx Mir<'tcx>, + var_vals: Vec, + temp_vals: Vec, + result: Value, +} + +impl<'tcx> Interpreter<'tcx> { + fn new(mir: &'tcx Mir<'tcx>) -> Self { + Interpreter { + mir: mir, + var_vals: vec![Value::Uninit; mir.var_decls.len()], + temp_vals: vec![Value::Uninit; mir.temp_decls.len()], + result: Value::Uninit, + } + } + + fn run(&mut self) { + let start_block = self.mir.basic_block_data(mir::START_BLOCK); + + for stmt in &start_block.statements { + use rustc_mir::repr::Lvalue::*; + use rustc_mir::repr::StatementKind::*; + + println!(" {:?}", stmt); + match stmt.kind { + Assign(ref lv, ref rv) => { + let val = self.eval_rvalue(rv); + + let spot = match *lv { + Var(i) => &mut self.var_vals[i as usize], + Temp(i) => &mut self.temp_vals[i as usize], + ReturnPointer => &mut self.result, + _ => unimplemented!(), + }; + + *spot = val; + } + Drop(_kind, ref _lv) => { /* TODO */ }, + } + } + + println!(" {:?}", start_block.terminator); + println!("=> {:?}", self.result); + } + + fn eval_rvalue(&mut self, rv: &mir::Rvalue) -> Value { + use rustc_mir::repr::Rvalue::*; + + match *rv { + Use(ref op) => self.eval_operand(op), + BinaryOp(mir::BinOp::Add, ref left, ref right) => { + let left_val = self.eval_operand(left); + let right_val = self.eval_operand(right); + match (left_val, right_val) { + (Value::Int(l), Value::Int(r)) => Value::Int(l + r), + _ => unimplemented!(), + } + } + _ => unimplemented!(), + } + } + + fn eval_operand(&mut self, op: &mir::Operand) -> Value { + use rustc::middle::const_eval::ConstVal::*; + use rustc_mir::repr::Lvalue::*; + use rustc_mir::repr::Operand::*; + + match *op { + Consume(Var(i)) => self.var_vals[i as usize].clone(), + Consume(Temp(i)) => self.temp_vals[i as usize].clone(), + Constant(ref constant) => { + match constant.literal { + mir::Literal::Value { value: Int(n) } => Value::Int(n), + _ => unimplemented!(), + } + } + _ => unimplemented!(), + } + } +} + +pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx>) { + for (&id, mir) in mir_map { + for attr in tcx.map.attrs(id) { + if attr.check_name("miri_run") { + let item = match tcx.map.get(id) { + front::map::NodeItem(item) => item, + _ => panic!(), + }; + println!("Interpreting: {}", item.name); + let mut interpreter = Interpreter::new(mir); + interpreter.run(); + } + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 00000000000..808b43e9643 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,31 @@ +#![feature(rustc_private)] + +extern crate rustc; +extern crate rustc_driver; +extern crate rustc_mir; +extern crate syntax; + +mod interpreter; + +use rustc::session::Session; +use rustc_driver::{driver, CompilerCalls, Compilation}; + +struct MiriCompilerCalls; + +impl<'a> CompilerCalls<'a> for MiriCompilerCalls { + fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> { + let mut control = driver::CompileController::basic(); + control.after_analysis.stop = Compilation::Stop; + + control.after_analysis.callback = Box::new(|state| { + interpreter::interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap()); + }); + + control + } +} + +fn main() { + let args: Vec = std::env::args().collect(); + rustc_driver::run_compiler(&args, &mut MiriCompilerCalls); +} diff --git a/test/add.rs b/test/add.rs new file mode 100644 index 00000000000..33b3b533f55 --- /dev/null +++ b/test/add.rs @@ -0,0 +1,12 @@ +#![feature(custom_attribute, rustc_attrs)] +#![allow(dead_code, unused_attributes)] + +#[rustc_mir] +#[miri_run] +fn foo() -> i32 { + let x = 1; + let y = 2; + x + y +} + +fn main() {}