]> git.lizzy.rs Git - rust.git/commitdiff
WIP: Switching to a new byte-based value representation.
authorScott Olson <scott@solson.me>
Sun, 28 Feb 2016 01:20:25 +0000 (19:20 -0600)
committerScott Olson <scott@solson.me>
Sun, 28 Feb 2016 01:20:25 +0000 (19:20 -0600)
Cargo.lock
Cargo.toml
src/interpreter.rs
src/lib.rs
test/new_values.rs [new file with mode: 0644]

index b86c754ccdf18806f892efd3dab22e6bfc78f46e..8fc715429970f1bc843dcce39866cdd04dd4245b 100644 (file)
@@ -1,4 +1,12 @@
 [root]
 name = "miri"
 version = "0.1.0"
+dependencies = [
+ "byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "byteorder"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 
index 9396477cd3ccf7022b633f1ed3d8496fae15ddd1..a369f6070c86b4afed6ac8f322479e36bfe59c6f 100644 (file)
@@ -1,11 +1,14 @@
 [package]
-name = "miri"
-version = "0.1.0"
 authors = ["Scott Olson <scott@solson.me>"]
 description = "An experimental interpreter for Rust MIR."
-repository = "https://github.com/tsion/miri"
 license = "ISC"
+name = "miri"
+repository = "https://github.com/tsion/miri"
+version = "0.1.0"
 
 [[bin]]
-name = "miri"
 doc = false
+name = "miri"
+
+[dependencies]
+byteorder = "0.4.2"
index ce923f2b34eb997c281b0351f9bb8d5b5ecdc6a8..01db533661ed3179669dcda901eb72aea0532afd 100644 (file)
+// TODO(tsion): Remove this.
+#![allow(unused_imports, dead_code, unused_variables)]
+
+use byteorder;
+use byteorder::ByteOrder;
 use rustc::middle::{const_eval, def_id, ty};
 use rustc::middle::cstore::CrateStore;
 use rustc::mir::repr::{self as mir, Mir};
 use rustc::mir::mir_map::MirMap;
+use std::collections::HashMap;
 use syntax::ast::Attribute;
 use syntax::attr::AttrMetaMethods;
 
 use std::iter;
 
-const TRACE_EXECUTION: bool = false;
+const TRACE_EXECUTION: bool = true;
 
-#[derive(Clone, Debug, PartialEq)]
-enum Value {
-    Uninit,
-    Bool(bool),
-    Int(i64), // FIXME(tsion): Should be bit-width aware.
-    Pointer(Pointer),
-    Adt { variant: usize, data_ptr: Pointer },
-    Func(def_id::DefId),
-}
+mod memory {
+    use byteorder;
+    use byteorder::ByteOrder;
+    use rustc::middle::ty;
+    use std::collections::HashMap;
+    use std::mem;
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-enum Pointer {
-    Stack(usize),
-    // TODO(tsion): Heap
-}
+    pub struct Memory {
+        next_id: u64,
+        alloc_map: HashMap<u64, Value>,
+    }
+
+    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
+    pub struct AllocId(u64);
+
+    // TODO(tsion): Remove this hack.
+    pub fn alloc_id_hack(i: u64) -> AllocId {
+        AllocId(i)
+    }
+
+    // TODO(tsion): Shouldn't clone values.
+    #[derive(Clone, Debug)]
+    pub struct Value {
+        pub bytes: Vec<u8>,
+        // TODO(tsion): relocations
+        // TODO(tsion): undef mask
+    }
+
+    #[derive(Clone, Debug, PartialEq, Eq)]
+    pub struct Pointer {
+        pub alloc_id: AllocId,
+        pub offset: usize,
+        pub repr: Repr,
+    }
+
+    #[derive(Clone, Debug, PartialEq, Eq)]
+    pub enum Repr {
+        Int,
+
+        StackFrame {
+            locals: Vec<Repr>,
+        }
+    }
+
+    impl Memory {
+        pub fn new() -> Self {
+            Memory { next_id: 0, alloc_map: HashMap::new() }
+        }
+
+        pub fn allocate(&mut self, size: usize) -> AllocId {
+            let id = AllocId(self.next_id);
+            let val = Value { bytes: vec![0; size] };
+            self.alloc_map.insert(self.next_id, val);
+            self.next_id += 1;
+            id
+        }
+
+        pub fn allocate_int(&mut self, n: i64) -> AllocId {
+            let id = self.allocate(mem::size_of::<i64>());
+            byteorder::NativeEndian::write_i64(&mut self.value_mut(id).unwrap().bytes, n);
+            id
+        }
+
+        pub fn value(&self, id: AllocId) -> Option<&Value> {
+            self.alloc_map.get(&id.0)
+        }
+
+        pub fn value_mut(&mut self, id: AllocId) -> Option<&mut Value> {
+            self.alloc_map.get_mut(&id.0)
+        }
+    }
+
+    impl Pointer {
+        pub fn offset(self, i: usize) -> Self {
+            Pointer { offset: self.offset + i, ..self }
+        }
+    }
+
+    impl Repr {
+        // TODO(tsion): Cache these outputs.
+        pub fn from_ty(ty: ty::Ty) -> Self {
+            match ty.sty {
+                ty::TyInt(_) => Repr::Int,
+                _ => unimplemented!(),
+            }
+        }
 
-impl Pointer {
-    fn offset(self, i: usize) -> Self {
-        match self {
-            Pointer::Stack(p) => Pointer::Stack(p + i),
+        pub fn size(&self) -> usize {
+            match *self {
+                Repr::Int => 8,
+                Repr::StackFrame { ref locals } =>
+                    locals.iter().map(Repr::size).fold(0, |a, b| a + b)
+            }
         }
     }
 }
+use self::memory::{Pointer, Repr, Value};
+
+// #[derive(Clone, Debug, PartialEq)]
+// enum Value {
+//     Uninit,
+//     Bool(bool),
+//     Int(i64), // FIXME(tsion): Should be bit-width aware.
+//     Pointer(Pointer),
+//     Adt { variant: usize, data_ptr: Pointer },
+//     Func(def_id::DefId),
+// }
 
 /// A stack frame:
 ///
@@ -55,42 +145,43 @@ fn offset(self, i: usize) -> Self {
 /// | Aggregates            | aggregates
 /// +-----------------------+
 /// ```
-#[derive(Debug)]
-struct Frame {
-    /// A pointer to a stack cell to write the return value of the current call, if it's not a
-    /// divering call.
-    return_ptr: Option<Pointer>,
-
-    offset: usize,
-    num_args: usize,
-    num_vars: usize,
-    num_temps: usize,
-    num_aggregate_fields: usize,
-}
-
-impl Frame {
-    fn size(&self) -> usize {
-        self.num_args + self.num_vars + self.num_temps + self.num_aggregate_fields
-    }
-
-    fn arg_offset(&self, i: usize) -> usize {
-        self.offset + i
-    }
-
-    fn var_offset(&self, i: usize) -> usize {
-        self.offset + self.num_args + i
-    }
-
-    fn temp_offset(&self, i: usize) -> usize {
-        self.offset + self.num_args + self.num_vars + i
-    }
-}
+// #[derive(Debug)]
+// struct Frame {
+//     /// A pointer to a stack cell to write the return value of the current call, if it's not a
+//     /// divering call.
+//     return_ptr: Option<Pointer>,
+
+//     offset: usize,
+//     num_args: usize,
+//     num_vars: usize,
+//     num_temps: usize,
+//     num_aggregate_fields: usize,
+// }
+
+// impl Frame {
+//     fn size(&self) -> usize {
+//         self.num_args + self.num_vars + self.num_temps + self.num_aggregate_fields
+//     }
+
+//     fn arg_offset(&self, i: usize) -> usize {
+//         self.offset + i
+//     }
+
+//     fn var_offset(&self, i: usize) -> usize {
+//         self.offset + self.num_args + i
+//     }
+
+//     fn temp_offset(&self, i: usize) -> usize {
+//         self.offset + self.num_args + self.num_vars + i
+//     }
+// }
 
 struct Interpreter<'a, 'tcx: 'a> {
     tcx: &'a ty::ctxt<'tcx>,
     mir_map: &'a MirMap<'tcx>,
-    value_stack: Vec<Value>,
-    call_stack: Vec<Frame>,
+    // value_stack: Vec<Value>,
+    // call_stack: Vec<Frame>,
+    memory: memory::Memory,
 }
 
 impl<'a, 'tcx> Interpreter<'a, 'tcx> {
@@ -98,47 +189,47 @@ fn new(tcx: &'a ty::ctxt<'tcx>, mir_map: &'a MirMap<'tcx>) -> Self {
         Interpreter {
             tcx: tcx,
             mir_map: mir_map,
-            value_stack: vec![Value::Uninit], // Allocate a spot for the top-level return value.
-            call_stack: Vec::new(),
+            // value_stack: vec![Value::Uninit], // Allocate a spot for the top-level return value.
+            // call_stack: Vec::new(),
+            memory: memory::Memory::new(),
         }
     }
 
-    fn push_stack_frame(&mut self, mir: &Mir, args: &[Value], return_ptr: Option<Pointer>) {
-        let frame = Frame {
-            return_ptr: return_ptr,
-            offset: self.value_stack.len(),
-            num_args: mir.arg_decls.len(),
-            num_vars: mir.var_decls.len(),
-            num_temps: mir.temp_decls.len(),
-            num_aggregate_fields: 0,
-        };
+    // fn push_stack_frame(&mut self, mir: &Mir, args: &[Value], return_ptr: Option<Pointer>) {
+    //     let frame = Frame {
+    //         return_ptr: return_ptr,
+    //         offset: self.value_stack.len(),
+    //         num_args: mir.arg_decls.len(),
+    //         num_vars: mir.var_decls.len(),
+    //         num_temps: mir.temp_decls.len(),
+    //         num_aggregate_fields: 0,
+    //     };
 
-        self.value_stack.extend(iter::repeat(Value::Uninit).take(frame.size()));
-
-        for (i, arg) in args.iter().enumerate() {
-            self.value_stack[frame.arg_offset(i)] = arg.clone();
-        }
+    //     self.value_stack.extend(iter::repeat(Value::Uninit).take(frame.size()));
 
-        self.call_stack.push(frame);
+    //     for (i, arg) in args.iter().enumerate() {
+    //         self.value_stack[frame.arg_offset(i)] = arg.clone();
+    //     }
 
-    }
+    //     self.call_stack.push(frame);
+    // }
 
-    fn pop_stack_frame(&mut self) {
-        let frame = self.call_stack.pop().expect("tried to pop stack frame, but there were none");
-        self.value_stack.truncate(frame.offset);
-    }
+    // fn pop_stack_frame(&mut self) {
+    //     let frame = self.call_stack.pop().expect("tried to pop stack frame, but there were none");
+    //     self.value_stack.truncate(frame.offset);
+    // }
 
-    fn allocate_aggregate(&mut self, size: usize) -> Pointer {
-        let frame = self.call_stack.last_mut().expect("missing call frame");
-        frame.num_aggregate_fields += size;
+    // fn allocate_aggregate(&mut self, size: usize) -> Pointer {
+    //     let frame = self.call_stack.last_mut().expect("missing call frame");
+    //     frame.num_aggregate_fields += size;
 
-        let ptr = Pointer::Stack(self.value_stack.len());
-        self.value_stack.extend(iter::repeat(Value::Uninit).take(size));
-        ptr
-    }
+    //     let ptr = Pointer::Stack(self.value_stack.len());
+    //     self.value_stack.extend(iter::repeat(Value::Uninit).take(size));
+    //     ptr
+    // }
 
     fn call(&mut self, mir: &Mir, args: &[Value], return_ptr: Option<Pointer>) {
-        self.push_stack_frame(mir, args, return_ptr);
+        // self.push_stack_frame(mir, args, return_ptr);
         let mut block = mir::START_BLOCK;
 
         loop {
@@ -150,9 +241,8 @@ fn call(&mut self, mir: &Mir, args: &[Value], return_ptr: Option<Pointer>) {
 
                 match stmt.kind {
                     mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
-                        let ptr = self.eval_lvalue(lvalue);
-                        let value = self.eval_rvalue(rvalue);
-                        self.write_pointer(ptr, value);
+                        let ptr = self.lvalue_to_ptr(lvalue);
+                        self.eval_rvalue_into(rvalue, ptr);
                     }
                 }
             }
@@ -163,60 +253,60 @@ fn call(&mut self, mir: &Mir, args: &[Value], return_ptr: Option<Pointer>) {
                 mir::Terminator::Return => break,
                 mir::Terminator::Goto { target } => block = target,
 
-                mir::Terminator::Call { ref func, ref args, ref destination, .. } => {
-                    let ptr = destination.as_ref().map(|&(ref lv, _)| self.eval_lvalue(lv));
-                    let func_val = self.eval_operand(func);
-
-                    if let Value::Func(def_id) = func_val {
-                        let mir_data;
-                        let mir = match self.tcx.map.as_local_node_id(def_id) {
-                            Some(node_id) => self.mir_map.map.get(&node_id).unwrap(),
-                            None => {
-                                let cstore = &self.tcx.sess.cstore;
-                                mir_data = cstore.maybe_get_item_mir(self.tcx, def_id).unwrap();
-                                &mir_data
-                            }
-                        };
-
-                        let arg_vals: Vec<Value> =
-                            args.iter().map(|arg| self.eval_operand(arg)).collect();
-
-                        self.call(mir, &arg_vals, ptr);
-
-                        if let Some((_, target)) = *destination {
-                            block = target;
-                        }
-                    } else {
-                        panic!("tried to call a non-function value: {:?}", func_val);
-                    }
-                }
-
-                mir::Terminator::If { ref cond, targets: (then_target, else_target) } => {
-                    match self.eval_operand(cond) {
-                        Value::Bool(true) => block = then_target,
-                        Value::Bool(false) => block = else_target,
-                        cond_val => panic!("Non-boolean `if` condition value: {:?}", cond_val),
-                    }
-                }
-
-                mir::Terminator::SwitchInt { ref discr, ref values, ref targets, .. } => {
-                    let discr_val = self.read_lvalue(discr);
-
-                    let index = values.iter().position(|v| discr_val == self.eval_constant(v))
-                        .expect("discriminant matched no values");
-
-                    block = targets[index];
-                }
-
-                mir::Terminator::Switch { ref discr, ref targets, .. } => {
-                    let discr_val = self.read_lvalue(discr);
-
-                    if let Value::Adt { variant, .. } = discr_val {
-                        block = targets[variant];
-                    } else {
-                        panic!("Switch on non-Adt value: {:?}", discr_val);
-                    }
-                }
+                // mir::Terminator::Call { ref func, ref args, ref destination, .. } => {
+                //     let ptr = destination.as_ref().map(|&(ref lv, _)| self.lvalue_to_ptr(lv));
+                //     let func_val = self.operand_to_ptr(func);
+
+                //     if let Value::Func(def_id) = func_val {
+                //         let mir_data;
+                //         let mir = match self.tcx.map.as_local_node_id(def_id) {
+                //             Some(node_id) => self.mir_map.map.get(&node_id).unwrap(),
+                //             None => {
+                //                 let cstore = &self.tcx.sess.cstore;
+                //                 mir_data = cstore.maybe_get_item_mir(self.tcx, def_id).unwrap();
+                //                 &mir_data
+                //             }
+                //         };
+
+                //         let arg_vals: Vec<Value> =
+                //             args.iter().map(|arg| self.operand_to_ptr(arg)).collect();
+
+                //         self.call(mir, &arg_vals, ptr);
+
+                //         if let Some((_, target)) = *destination {
+                //             block = target;
+                //         }
+                //     } else {
+                //         panic!("tried to call a non-function value: {:?}", func_val);
+                //     }
+                // }
+
+                // mir::Terminator::If { ref cond, targets: (then_target, else_target) } => {
+                //     match self.operand_to_ptr(cond) {
+                //         Value::Bool(true) => block = then_target,
+                //         Value::Bool(false) => block = else_target,
+                //         cond_val => panic!("Non-boolean `if` condition value: {:?}", cond_val),
+                //     }
+                // }
+
+                // mir::Terminator::SwitchInt { ref discr, ref values, ref targets, .. } => {
+                //     let discr_val = self.read_lvalue(discr);
+
+                //     let index = values.iter().position(|v| discr_val == self.eval_constant(v))
+                //         .expect("discriminant matched no values");
+
+                //     block = targets[index];
+                // }
+
+                // mir::Terminator::Switch { ref discr, ref targets, .. } => {
+                //     let discr_val = self.read_lvalue(discr);
+
+                //     if let Value::Adt { variant, .. } = discr_val {
+                //         block = targets[variant];
+                //     } else {
+                //         panic!("Switch on non-Adt value: {:?}", discr_val);
+                //     }
+                // }
 
                 mir::Terminator::Drop { target, .. } => {
                     // TODO: Handle destructors and dynamic drop.
@@ -224,139 +314,159 @@ fn call(&mut self, mir: &Mir, args: &[Value], return_ptr: Option<Pointer>) {
                 }
 
                 mir::Terminator::Resume => unimplemented!(),
+                _ => unimplemented!(),
             }
         }
 
-        self.pop_stack_frame();
+        // self.pop_stack_frame();
     }
 
-    fn eval_lvalue(&self, lvalue: &mir::Lvalue) -> Pointer {
-        let frame = self.call_stack.last().expect("missing call frame");
-
+    fn lvalue_to_ptr(&self, lvalue: &mir::Lvalue) -> Pointer {
         match *lvalue {
-            mir::Lvalue::ReturnPointer =>
-                frame.return_ptr.expect("ReturnPointer used in a function with no return value"),
-            mir::Lvalue::Arg(i)  => Pointer::Stack(frame.arg_offset(i as usize)),
-            mir::Lvalue::Var(i)  => Pointer::Stack(frame.var_offset(i as usize)),
-            mir::Lvalue::Temp(i) => Pointer::Stack(frame.temp_offset(i as usize)),
-
-            mir::Lvalue::Projection(ref proj) => {
-                let base_ptr = self.eval_lvalue(&proj.base);
-
-                match proj.elem {
-                    mir::ProjectionElem::Field(field, _) => {
-                        base_ptr.offset(field.index())
-                    }
-
-                    mir::ProjectionElem::Downcast(_, variant) => {
-                        let adt_val = self.read_pointer(base_ptr);
-                        if let Value::Adt { variant: actual_variant, data_ptr } = adt_val {
-                            debug_assert_eq!(variant, actual_variant);
-                            data_ptr
-                        } else {
-                            panic!("Downcast attempted on non-ADT: {:?}", adt_val)
-                        }
-                    }
-
-                    mir::ProjectionElem::Deref => {
-                        let ptr_val = self.read_pointer(base_ptr);
-                        if let Value::Pointer(ptr) = ptr_val {
-                            ptr
-                        } else {
-                            panic!("Deref attempted on non-pointer: {:?}", ptr_val)
-                        }
-                    }
-
-                    mir::ProjectionElem::Index(ref _operand) => unimplemented!(),
-                    mir::ProjectionElem::ConstantIndex { .. } => unimplemented!(),
-                }
-            }
+            mir::Lvalue::ReturnPointer => Pointer {
+                alloc_id: self::memory::alloc_id_hack(0),
+                offset: 0,
+                repr: Repr::Int,
+            },
 
             _ => unimplemented!(),
         }
+
+        // let frame = self.call_stack.last().expect("missing call frame");
+
+        // match *lvalue {
+        //     mir::Lvalue::ReturnPointer =>
+        //         frame.return_ptr.expect("ReturnPointer used in a function with no return value"),
+        //     mir::Lvalue::Arg(i)  => Pointer::Stack(frame.arg_offset(i as usize)),
+        //     mir::Lvalue::Var(i)  => Pointer::Stack(frame.var_offset(i as usize)),
+        //     mir::Lvalue::Temp(i) => Pointer::Stack(frame.temp_offset(i as usize)),
+
+        //     mir::Lvalue::Projection(ref proj) => {
+        //         let base_ptr = self.lvalue_to_ptr(&proj.base);
+
+        //         match proj.elem {
+        //             mir::ProjectionElem::Field(field, _) => {
+        //                 base_ptr.offset(field.index())
+        //             }
+
+        //             mir::ProjectionElem::Downcast(_, variant) => {
+        //                 let adt_val = self.read_pointer(base_ptr);
+        //                 if let Value::Adt { variant: actual_variant, data_ptr } = adt_val {
+        //                     debug_assert_eq!(variant, actual_variant);
+        //                     data_ptr
+        //                 } else {
+        //                     panic!("Downcast attempted on non-ADT: {:?}", adt_val)
+        //                 }
+        //             }
+
+        //             mir::ProjectionElem::Deref => {
+        //                 let ptr_val = self.read_pointer(base_ptr);
+        //                 if let Value::Pointer(ptr) = ptr_val {
+        //                     ptr
+        //                 } else {
+        //                     panic!("Deref attempted on non-pointer: {:?}", ptr_val)
+        //                 }
+        //             }
+
+        //             mir::ProjectionElem::Index(ref _operand) => unimplemented!(),
+        //             mir::ProjectionElem::ConstantIndex { .. } => unimplemented!(),
+        //         }
+        //     }
+
+        //     _ => unimplemented!(),
+        // }
     }
 
-    fn eval_binary_op(&mut self, bin_op: mir::BinOp, left: Value, right: Value) -> Value {
-        match (left, right) {
-            (Value::Int(l), Value::Int(r)) => {
-                match bin_op {
-                    mir::BinOp::Add    => Value::Int(l + r),
-                    mir::BinOp::Sub    => Value::Int(l - r),
-                    mir::BinOp::Mul    => Value::Int(l * r),
-                    mir::BinOp::Div    => Value::Int(l / r),
-                    mir::BinOp::Rem    => Value::Int(l % r),
-                    mir::BinOp::BitXor => Value::Int(l ^ r),
-                    mir::BinOp::BitAnd => Value::Int(l & r),
-                    mir::BinOp::BitOr  => Value::Int(l | r),
-                    mir::BinOp::Shl    => Value::Int(l << r),
-                    mir::BinOp::Shr    => Value::Int(l >> r),
-                    mir::BinOp::Eq     => Value::Bool(l == r),
-                    mir::BinOp::Lt     => Value::Bool(l < r),
-                    mir::BinOp::Le     => Value::Bool(l <= r),
-                    mir::BinOp::Ne     => Value::Bool(l != r),
-                    mir::BinOp::Ge     => Value::Bool(l >= r),
-                    mir::BinOp::Gt     => Value::Bool(l > r),
-                }
+    fn eval_binary_op(&mut self, bin_op: mir::BinOp, left: Pointer, right: Pointer, out: Pointer) {
+        match (left.repr, right.repr, out.repr) {
+            (Repr::Int, Repr::Int, Repr::Int) => {
+                let l = byteorder::NativeEndian::read_i64(&self.memory.value(left.alloc_id).unwrap().bytes);
+                let r = byteorder::NativeEndian::read_i64(&self.memory.value(right.alloc_id).unwrap().bytes);
+                let n = match bin_op {
+                    mir::BinOp::Add    => l + r,
+                    mir::BinOp::Sub    => l - r,
+                    mir::BinOp::Mul    => l * r,
+                    mir::BinOp::Div    => l / r,
+                    mir::BinOp::Rem    => l % r,
+                    mir::BinOp::BitXor => l ^ r,
+                    mir::BinOp::BitAnd => l & r,
+                    mir::BinOp::BitOr  => l | r,
+                    mir::BinOp::Shl    => l << r,
+                    mir::BinOp::Shr    => l >> r,
+                    _                  => unimplemented!(),
+                    // mir::BinOp::Eq     => Value::Bool(l == r),
+                    // mir::BinOp::Lt     => Value::Bool(l < r),
+                    // mir::BinOp::Le     => Value::Bool(l <= r),
+                    // mir::BinOp::Ne     => Value::Bool(l != r),
+                    // mir::BinOp::Ge     => Value::Bool(l >= r),
+                    // mir::BinOp::Gt     => Value::Bool(l > r),
+                };
+                byteorder::NativeEndian::write_i64(&mut self.memory.value_mut(out.alloc_id).unwrap().bytes, n);
             }
 
             _ => unimplemented!(),
         }
     }
 
-    fn eval_rvalue(&mut self, rvalue: &mir::Rvalue) -> Value {
+    fn eval_rvalue_into(&mut self, rvalue: &mir::Rvalue, out: Pointer) {
         match *rvalue {
-            mir::Rvalue::Use(ref operand) => self.eval_operand(operand),
+            mir::Rvalue::Use(ref operand) => {
+                let ptr = self.operand_to_ptr(operand);
+                let val = self.read_pointer(ptr);
+                self.write_pointer(out, val);
+            }
 
             mir::Rvalue::BinaryOp(bin_op, ref left, ref right) => {
-                let left_val = self.eval_operand(left);
-                let right_val = self.eval_operand(right);
-                self.eval_binary_op(bin_op, left_val, right_val)
+                let left_ptr = self.operand_to_ptr(left);
+                let right_ptr = self.operand_to_ptr(right);
+                self.eval_binary_op(bin_op, left_ptr, right_ptr, out)
             }
 
             mir::Rvalue::UnaryOp(un_op, ref operand) => {
-                match (un_op, self.eval_operand(operand)) {
-                    (mir::UnOp::Not, Value::Int(n)) => Value::Int(!n),
-                    (mir::UnOp::Neg, Value::Int(n)) => Value::Int(-n),
-                    _ => unimplemented!(),
-                }
+                unimplemented!()
+                // match (un_op, self.operand_to_ptr(operand)) {
+                //     (mir::UnOp::Not, Value::Int(n)) => Value::Int(!n),
+                //     (mir::UnOp::Neg, Value::Int(n)) => Value::Int(-n),
+                //     _ => unimplemented!(),
+                // }
             }
 
-            mir::Rvalue::Ref(_region, _kind, ref lvalue) => {
-                Value::Pointer(self.eval_lvalue(lvalue))
-            }
+            // mir::Rvalue::Ref(_region, _kind, ref lvalue) => {
+            //     Value::Pointer(self.lvalue_to_ptr(lvalue))
+            // }
 
-            mir::Rvalue::Aggregate(mir::AggregateKind::Adt(ref adt_def, variant, _substs),
-                                   ref operands) => {
-                let max_fields = adt_def.variants
-                    .iter()
-                    .map(|v| v.fields.len())
-                    .max()
-                    .unwrap_or(0);
+            // mir::Rvalue::Aggregate(mir::AggregateKind::Adt(ref adt_def, variant, _substs),
+            //                        ref operands) => {
+            //     let max_fields = adt_def.variants
+            //         .iter()
+            //         .map(|v| v.fields.len())
+            //         .max()
+            //         .unwrap_or(0);
 
-                let ptr = self.allocate_aggregate(max_fields);
+            //     let ptr = self.allocate_aggregate(max_fields);
 
-                for (i, operand) in operands.iter().enumerate() {
-                    let val = self.eval_operand(operand);
-                    self.write_pointer(ptr.offset(i), val);
-                }
+            //     for (i, operand) in operands.iter().enumerate() {
+            //         let val = self.operand_to_ptr(operand);
+            //         self.write_pointer(ptr.offset(i), val);
+            //     }
 
-                Value::Adt { variant: variant, data_ptr: ptr }
-            }
+            //     Value::Adt { variant: variant, data_ptr: ptr }
+            // }
 
             ref r => panic!("can't handle rvalue: {:?}", r),
         }
     }
 
-    fn eval_operand(&mut self, op: &mir::Operand) -> Value {
+    fn operand_to_ptr(&mut self, op: &mir::Operand) -> Pointer {
         match *op {
-            mir::Operand::Consume(ref lvalue) => self.read_lvalue(lvalue),
+            mir::Operand::Consume(ref lvalue) => self.lvalue_to_ptr(lvalue),
 
             mir::Operand::Constant(ref constant) => {
                 match constant.literal {
                     mir::Literal::Value { ref value } => self.eval_constant(value),
 
                     mir::Literal::Item { def_id, kind, .. } => match kind {
-                        mir::ItemKind::Function | mir::ItemKind::Method => Value::Func(def_id),
+                        // mir::ItemKind::Function | mir::ItemKind::Method => Value::Func(def_id),
                         _ => panic!("can't handle item literal: {:?}", constant.literal),
                     },
                 }
@@ -364,14 +474,19 @@ fn eval_operand(&mut self, op: &mir::Operand) -> Value {
         }
     }
 
-    fn eval_constant(&self, const_val: &const_eval::ConstVal) -> Value {
+    fn eval_constant(&mut self, const_val: &const_eval::ConstVal) -> Pointer {
         match *const_val {
             const_eval::ConstVal::Float(_f)         => unimplemented!(),
-            const_eval::ConstVal::Int(i)            => Value::Int(i),
+            // const_eval::ConstVal::Int(i)            => Value::new_int(i),
+            const_eval::ConstVal::Int(i)            => Pointer {
+                alloc_id: self.memory.allocate_int(i),
+                offset: 0,
+                repr: Repr::Int,
+            },
             const_eval::ConstVal::Uint(_u)          => unimplemented!(),
             const_eval::ConstVal::Str(ref _s)       => unimplemented!(),
             const_eval::ConstVal::ByteStr(ref _bs)  => unimplemented!(),
-            const_eval::ConstVal::Bool(b)           => Value::Bool(b),
+            const_eval::ConstVal::Bool(b)           => unimplemented!(),
             const_eval::ConstVal::Struct(_node_id)  => unimplemented!(),
             const_eval::ConstVal::Tuple(_node_id)   => unimplemented!(),
             const_eval::ConstVal::Function(_def_id) => unimplemented!(),
@@ -380,19 +495,19 @@ fn eval_constant(&self, const_val: &const_eval::ConstVal) -> Value {
         }
     }
 
-    fn read_lvalue(&self, lvalue: &mir::Lvalue) -> Value {
-        self.read_pointer(self.eval_lvalue(lvalue))
-    }
+    // fn read_lvalue(&self, lvalue: &mir::Lvalue) -> Value {
+    //     self.read_pointer(self.lvalue_to_ptr(lvalue))
+    // }
 
     fn read_pointer(&self, p: Pointer) -> Value {
-        match p {
-            Pointer::Stack(offset) => self.value_stack[offset].clone(),
-        }
+        self.memory.value(p.alloc_id).unwrap().clone()
     }
 
     fn write_pointer(&mut self, p: Pointer, val: Value) {
-        match p {
-            Pointer::Stack(offset) => self.value_stack[offset] = val,
+        // TODO(tsion): Remove panics.
+        let alloc = self.memory.value_mut(p.alloc_id).unwrap();
+        for (i, byte) in val.bytes.into_iter().enumerate() {
+            alloc.bytes[p.offset + i] = byte;
         }
     }
 }
@@ -406,10 +521,20 @@ pub fn interpret_start_points<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &MirMap<'tcx>
                 println!("Interpreting: {}", item.name);
 
                 let mut interpreter = Interpreter::new(tcx, mir_map);
-                let return_ptr = Pointer::Stack(0);
-                interpreter.call(mir, &[], Some(return_ptr));
+                let return_ptr = match mir.return_ty {
+                    ty::FnOutput::FnConverging(ty) => {
+                        let repr = Repr::from_ty(ty);
+                        Some(Pointer {
+                            alloc_id: interpreter.memory.allocate(repr.size()),
+                            offset: 0,
+                            repr: repr,
+                        })
+                    }
+                    ty::FnOutput::FnDiverging => None,
+                };
+                interpreter.call(mir, &[], return_ptr.clone());
 
-                let val_str = format!("{:?}", interpreter.read_pointer(return_ptr));
+                let val_str = format!("{:?}", interpreter.read_pointer(return_ptr.unwrap()));
                 if !check_expected(&val_str, attr) {
                     println!("=> {}\n", val_str);
                 }
index da83e7db925acc4497dabbdf7c5bebd791de4249..c7be3a0340cb9eb6a960b49ff8191bd5fae1a007 100644 (file)
@@ -1,5 +1,6 @@
 #![feature(rustc_private)]
 
+extern crate byteorder;
 extern crate rustc;
 extern crate rustc_mir;
 extern crate syntax;
diff --git a/test/new_values.rs b/test/new_values.rs
new file mode 100644 (file)
index 0000000..228aec8
--- /dev/null
@@ -0,0 +1,176 @@
+#![feature(custom_attribute)]
+#![allow(dead_code, unused_attributes)]
+
+#[miri_run(expected = "Int(1)")]
+fn ret() -> i32 {
+    1
+}
+
+// #[miri_run(expected = "Int(-1)")]
+// fn neg() -> i32 {
+//     -1
+// }
+
+#[miri_run(expected = "Int(3)")]
+fn add() -> i32 {
+    1 + 2
+}
+
+// #[miri_run(expected = "Int(3)")]
+// fn indirect_add() -> i32 {
+//     let x = 1;
+//     let y = 2;
+//     x + y
+// }
+
+// #[miri_run(expected = "Int(25)")]
+// fn arith() -> i32 {
+//     3*3 + 4*4
+// }
+
+// #[miri_run(expected = "Int(0)")]
+// fn if_false() -> i32 {
+//     if false { 1 } else { 0 }
+// }
+
+// #[miri_run(expected = "Int(1)")]
+// fn if_true() -> i32 {
+//     if true { 1 } else { 0 }
+// }
+
+// #[miri_run(expected = "Int(2)")]
+// fn call() -> i32 {
+//     fn increment(x: i32) -> i32 {
+//         x + 1
+//     }
+
+//     increment(1)
+// }
+
+// // #[miri_run(expected = "Int(3628800)")]
+// // fn factorial_loop() -> i32 {
+// //     let mut product = 1;
+// //     let mut i = 1;
+
+// //     while i <= 10 {
+// //         product *= i;
+// //         i += 1;
+// //     }
+
+// //     product
+// // }
+
+// #[miri_run(expected = "Int(3628800)")]
+// fn factorial_recursive() -> i32 {
+//     fn fact(n: i32) -> i32 {
+//         if n == 0 {
+//             1
+//         } else {
+//             n * fact(n - 1)
+//         }
+//     }
+
+//     fact(10)
+// }
+
+// #[miri_run(expected = "Int(1)")]
+// fn match_bool() -> i32 {
+//     let b = true;
+//     match b {
+//         true => 1,
+//         false => 0,
+//     }
+// }
+
+// #[miri_run(expected = "Int(20)")]
+// fn match_int() -> i32 {
+//     let n = 2;
+//     match n {
+//         0 => 0,
+//         1 => 10,
+//         2 => 20,
+//         3 => 30,
+//         _ => 100,
+//     }
+// }
+
+// #[miri_run(expected = "Int(1)")]
+// fn one_line_ref() -> i32 {
+//     *&1
+// }
+
+// #[miri_run(expected = "Int(1)")]
+// fn basic_ref() -> i32 {
+//     let x = &1;
+//     *x
+// }
+
+// #[miri_run(expected = "Int(3)")]
+// fn basic_ref_mut() -> i32 {
+//     let x = &mut 1;
+//     *x += 2;
+//     *x
+// }
+
+// // #[miri_run(expected = "Int(3)")]
+// // fn basic_ref_mut_var() -> i32 {
+// //     let mut a = 1;
+// //     {
+// //         let x = &mut a;
+// //         *x += 2;
+// //     }
+// //     a
+// // }
+
+// #[miri_run(expected = "Int(4)")]
+// fn match_int_range() -> i32 {
+//     let n = 42;
+//     match n {
+//         0...9 => 0,
+//         10...19 => 1,
+//         20...29 => 2,
+//         30...39 => 3,
+//         40...49 => 4,
+//         _ => 5,
+//     }
+// }
+
+// enum MyOption<T> {
+//     Some { data: T },
+//     None,
+// }
+
+// #[miri_run(expected = "Int(13)")]
+// fn match_my_opt_some() -> i32 {
+//     let x = MyOption::Some { data: 13 };
+//     match x {
+//         MyOption::Some { data } => data,
+//         MyOption::None => 42,
+//     }
+// }
+
+// #[miri_run(expected = "Int(42)")]
+// fn match_my_opt_none() -> i32 {
+//     let x = MyOption::None;
+//     match x {
+//         MyOption::Some { data } => data,
+//         MyOption::None => 42,
+//     }
+// }
+
+// #[miri_run(expected = "Int(13)")]
+// fn match_opt_some() -> i32 {
+//     let x = Some(13);
+//     match x {
+//         Some(data)  => data,
+//         None => 42,
+//     }
+// }
+
+// /// Test calling a very simple function from the standard library.
+// #[miri_run(expected = "Int(1)")]
+// fn cross_crate_fn_call() -> i32 {
+//     if 1i32.is_positive() { 1 } else { 0 }
+// }
+
+// fn main() {}