From 8a0b95bc8bbca2b11c3dbfdc418f88cc96e62398 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Fri, 11 Mar 2016 21:27:54 -0600 Subject: [PATCH] Support structs and single-variant enums. --- src/interpreter.rs | 78 ++++++++++++++++++++++++++++++++-------------- src/memory.rs | 23 -------------- test/basic.rs | 7 +++++ 3 files changed, 61 insertions(+), 47 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index d4e2d949b5d6..2590cd656a4d 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -5,7 +5,7 @@ use rustc::mir::repr as mir; use std::error::Error; use std::fmt; -use memory::{Memory, Pointer, Repr}; +use memory::{FieldRepr, Memory, Pointer, Repr}; const TRACE_EXECUTION: bool = true; @@ -107,7 +107,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> { let mut locals = Vec::with_capacity(num_args + num_vars + num_temps); for (arg_decl, arg_operand) in mir.arg_decls.iter().zip(args) { - let repr = Repr::from_ty(arg_decl.ty); + let repr = self.ty_to_repr(arg_decl.ty); let dest = self.memory.allocate(repr.size()); let src = try!(self.operand_to_ptr(arg_operand)); try!(self.memory.copy(src, dest, repr.size())); @@ -117,7 +117,8 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> { let var_tys = mir.var_decls.iter().map(|v| v.ty); let temp_tys = mir.temp_decls.iter().map(|t| t.ty); locals.extend(var_tys.chain(temp_tys).map(|ty| { - self.memory.allocate(Repr::from_ty(ty).size()) + let repr = self.ty_to_repr(ty).size(); + self.memory.allocate(repr) })); self.stack.push(Frame { @@ -273,7 +274,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> { { let dest = try!(self.lvalue_to_ptr(lvalue)); let dest_ty = self.current_frame().mir.lvalue_ty(self.tcx, lvalue).to_ty(self.tcx); - let dest_repr = Repr::from_ty(dest_ty); + let dest_repr = self.ty_to_repr(dest_ty); use rustc::mir::repr::Rvalue::*; match *rvalue { @@ -297,7 +298,21 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> { self.memory.write_int(dest, n) } - Aggregate(mir::AggregateKind::Tuple, ref operands) => { + Aggregate(ref _kind, ref operands) => { + // TODO(tsion): Handle different `kind` variants. + + // let max_fields = adt_def.variants + // .iter() + // .map(|v| v.fields.len()) + // .max() + // .unwrap_or(0); + // let ptr = self.allocate_aggregate(max_fields); + // 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 } + match dest_repr { Repr::Aggregate { ref fields, .. } => { for (field, operand) in fields.iter().zip(operands) { @@ -316,24 +331,6 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> { // Value::Pointer(self.lvalue_to_ptr(lvalue)) // } - // 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); - - // 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 } - // } - ref r => panic!("can't handle rvalue: {:?}", r), } } @@ -433,6 +430,36 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> { } } + fn make_aggregate_repr(&self, iter: I) -> Repr where I: IntoIterator> { + let mut size = 0; + let fields = iter.into_iter().map(|ty| { + let repr = self.ty_to_repr(ty); + let old_size = size; + size += repr.size(); + FieldRepr { offset: old_size, repr: repr } + }).collect(); + Repr::Aggregate { size: size, fields: fields } + } + + // TODO(tsion): Cache these outputs. + fn ty_to_repr(&self, ty: ty::Ty<'tcx>) -> Repr { + match ty.sty { + ty::TyBool => Repr::Bool, + ty::TyInt(_) => Repr::Int, + ty::TyTuple(ref fields) => self.make_aggregate_repr(fields.iter().cloned()), + + ty::TyEnum(adt_def, ref subst) | ty::TyStruct(adt_def, ref subst) => { + // TODO(tsion): Support multi-variant enums. + assert!(adt_def.variants.len() == 1); + let field_tys = adt_def.variants[0].fields.iter().map(|f| f.ty(self.tcx, subst)); + self.make_aggregate_repr(field_tys) + } + + ref t => panic!("can't convert type to repr: {:?}", t), + } + } + + fn current_frame(&self) -> &Frame<'a, 'tcx> { self.stack.last().expect("no call frames exist") } @@ -449,7 +476,10 @@ pub fn interpret_start_points<'tcx>(tcx: &TyCtxt<'tcx>, mir_map: &MirMap<'tcx>) let mut miri = Interpreter::new(tcx, mir_map); let return_ptr = match mir.return_ty { - ty::FnConverging(ty) => Some(miri.memory.allocate(Repr::from_ty(ty).size())), + ty::FnConverging(ty) => { + let repr = miri.ty_to_repr(ty).size(); + Some(miri.memory.allocate(repr)) + } ty::FnDiverging => None, }; miri.call(mir, &[], return_ptr).unwrap(); diff --git a/src/memory.rs b/src/memory.rs index bb6cadd026a1..744424a1ffb3 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,5 +1,4 @@ use byteorder::{self, ByteOrder}; -use rustc::middle::ty; use std::collections::HashMap; use std::mem; use std::ptr; @@ -141,28 +140,6 @@ impl Pointer { } impl Repr { - // TODO(tsion): Cache these outputs. - pub fn from_ty(ty: ty::Ty) -> Self { - match ty.sty { - ty::TyBool => Repr::Bool, - - ty::TyInt(_) => Repr::Int, - - ty::TyTuple(ref fields) => { - let mut size = 0; - let fields = fields.iter().map(|ty| { - let repr = Repr::from_ty(ty); - let old_size = size; - size += repr.size(); - FieldRepr { offset: old_size, repr: repr } - }).collect(); - Repr::Aggregate { size: size, fields: fields } - }, - - ref t => panic!("can't convert type to repr: {:?}", t), - } - } - pub fn size(&self) -> usize { match *self { Repr::Bool => 1, diff --git a/test/basic.rs b/test/basic.rs index b3da0562fc51..795915a50411 100644 --- a/test/basic.rs +++ b/test/basic.rs @@ -61,6 +61,13 @@ fn if_true() -> i32 { if true { 1 } else { 0 } } +struct Pair { x: i64, y: i64 } + +#[miri_run] +fn pair() -> Pair { + Pair { x: 10, y: 20 } +} + // #[miri_run(expected = "Int(2)")] // fn call() -> i32 { // fn increment(x: i32) -> i32 {