From 9d1d96ce07dabcbef38d4a0ddaa42d90919cba8e Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Mon, 14 Mar 2016 23:03:31 -0600 Subject: [PATCH] Add unsigned integers. --- src/interpreter.rs | 22 +++++++---- src/memory.rs | 95 ++++++++++++++++++++++++++++++++++++++-------- src/primval.rs | 44 +++++++++++---------- 3 files changed, 118 insertions(+), 43 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index 14e4323a5f1..17ab9a52bba 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -210,7 +210,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> { _ => panic!("attmpted to switch on non-sum type"), }; let discr_val = try!(self.memory.read_primval(adt_ptr, &discr_repr)); - TerminatorTarget::Block(targets[discr_val.to_int() as usize]) + TerminatorTarget::Block(targets[discr_val.to_usize()]) } Call { ref func, ref args, ref destination, .. } => { @@ -298,7 +298,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> { ty::AdtKind::Enum => match dest_repr { Repr::Sum { ref discr, ref variants, .. } => { if discr.size() > 0 { - let discr_val = PrimVal::from_int(variant_idx as i64, discr); + let discr_val = PrimVal::from_usize(variant_idx, discr); try!(self.memory.write_primval(dest, discr_val)); } self.assign_to_product( @@ -442,12 +442,18 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> { match ty.subst(self.tcx, self.current_substs()).sty { ty::TyBool => Repr::Bool, - ty::TyInt(IntTy::Is) => unimplemented!(), - ty::TyInt(IntTy::I8) => Repr::I8, + ty::TyInt(IntTy::Is) => Repr::isize(), + ty::TyInt(IntTy::I8) => Repr::I8, ty::TyInt(IntTy::I16) => Repr::I16, ty::TyInt(IntTy::I32) => Repr::I32, ty::TyInt(IntTy::I64) => Repr::I64, + ty::TyUint(UintTy::Us) => Repr::usize(), + ty::TyUint(UintTy::U8) => Repr::U8, + ty::TyUint(UintTy::U16) => Repr::U16, + ty::TyUint(UintTy::U32) => Repr::U32, + ty::TyUint(UintTy::U64) => Repr::U64, + ty::TyTuple(ref fields) => self.make_product_repr(fields.iter().cloned()), ty::TyEnum(adt_def, substs) => { @@ -456,13 +462,13 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> { let discr = if num_variants <= 1 { Repr::Product { size: 0, fields: vec![] } } else if num_variants <= 1 << 8 { - Repr::I8 + Repr::U8 } else if num_variants <= 1 << 16 { - Repr::I16 + Repr::U16 } else if num_variants <= 1 << 32 { - Repr::I32 + Repr::U32 } else { - Repr::I64 + Repr::U64 }; let variants: Vec = adt_def.variants.iter().map(|v| { diff --git a/src/memory.rs b/src/memory.rs index 3675476e2ee..5ab8872e85e 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,6 +1,7 @@ use byteorder::{self, ByteOrder}; use std::collections::{BTreeMap, HashMap}; use std::collections::Bound::{Included, Excluded}; +use std::mem; use std::ptr; use error::{EvalError, EvalResult}; @@ -38,10 +39,8 @@ pub struct FieldRepr { #[derive(Clone, Debug, PartialEq, Eq)] pub enum Repr { Bool, - I8, - I16, - I32, - I64, + I8, I16, I32, I64, + U8, U16, U32, U64, /// The representation for product types including tuples, structs, and the contents of enum /// variants. @@ -170,10 +169,14 @@ impl Memory { pub fn read_primval(&self, ptr: Pointer, repr: &Repr) -> EvalResult { match *repr { Repr::Bool => self.read_bool(ptr).map(PrimVal::Bool), - Repr::I8 => self.read_i8(ptr).map(PrimVal::I8), - Repr::I16 => self.read_i16(ptr).map(PrimVal::I16), - Repr::I32 => self.read_i32(ptr).map(PrimVal::I32), - Repr::I64 => self.read_i64(ptr).map(PrimVal::I64), + Repr::I8 => self.read_i8(ptr).map(PrimVal::I8), + Repr::I16 => self.read_i16(ptr).map(PrimVal::I16), + Repr::I32 => self.read_i32(ptr).map(PrimVal::I32), + Repr::I64 => self.read_i64(ptr).map(PrimVal::I64), + Repr::U8 => self.read_u8(ptr).map(PrimVal::U8), + Repr::U16 => self.read_u16(ptr).map(PrimVal::U16), + Repr::U32 => self.read_u32(ptr).map(PrimVal::U32), + Repr::U64 => self.read_u64(ptr).map(PrimVal::U64), _ => panic!("primitive read of non-primitive: {:?}", repr), } } @@ -181,10 +184,14 @@ impl Memory { pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<()> { match val { PrimVal::Bool(b) => self.write_bool(ptr, b), - PrimVal::I8(n) => self.write_i8(ptr, n), - PrimVal::I16(n) => self.write_i16(ptr, n), - PrimVal::I32(n) => self.write_i32(ptr, n), - PrimVal::I64(n) => self.write_i64(ptr, n), + PrimVal::I8(n) => self.write_i8(ptr, n), + PrimVal::I16(n) => self.write_i16(ptr, n), + PrimVal::I32(n) => self.write_i32(ptr, n), + PrimVal::I64(n) => self.write_i64(ptr, n), + PrimVal::U8(n) => self.write_u8(ptr, n), + PrimVal::U16(n) => self.write_u16(ptr, n), + PrimVal::U32(n) => self.write_u32(ptr, n), + PrimVal::U64(n) => self.write_u64(ptr, n), } } @@ -240,6 +247,44 @@ impl Memory { byteorder::NativeEndian::write_i64(bytes, n); Ok(()) } + + pub fn read_u8(&self, ptr: Pointer) -> EvalResult { + self.get_bytes(ptr, 1).map(|b| b[0] as u8) + } + + pub fn write_u8(&mut self, ptr: Pointer, n: u8) -> EvalResult<()> { + self.get_bytes_mut(ptr, 1).map(|b| b[0] = n as u8) + } + + pub fn read_u16(&self, ptr: Pointer) -> EvalResult { + self.get_bytes(ptr, 2).map(byteorder::NativeEndian::read_u16) + } + + pub fn write_u16(&mut self, ptr: Pointer, n: u16) -> EvalResult<()> { + let bytes = try!(self.get_bytes_mut(ptr, 2)); + byteorder::NativeEndian::write_u16(bytes, n); + Ok(()) + } + + pub fn read_u32(&self, ptr: Pointer) -> EvalResult { + self.get_bytes(ptr, 4).map(byteorder::NativeEndian::read_u32) + } + + pub fn write_u32(&mut self, ptr: Pointer, n: u32) -> EvalResult<()> { + let bytes = try!(self.get_bytes_mut(ptr, 4)); + byteorder::NativeEndian::write_u32(bytes, n); + Ok(()) + } + + pub fn read_u64(&self, ptr: Pointer) -> EvalResult { + self.get_bytes(ptr, 8).map(byteorder::NativeEndian::read_u64) + } + + pub fn write_u64(&mut self, ptr: Pointer, n: u64) -> EvalResult<()> { + let bytes = try!(self.get_bytes_mut(ptr, 8)); + byteorder::NativeEndian::write_u64(bytes, n); + Ok(()) + } } impl Allocation { @@ -287,13 +332,31 @@ impl Pointer { } impl Repr { + // TODO(tsion): Choice is based on host machine's type size. Should this be how miri works? + pub fn isize() -> Self { + match mem::size_of::() { + 4 => Repr::I32, + 8 => Repr::I64, + _ => unimplemented!(), + } + } + + // TODO(tsion): Choice is based on host machine's type size. Should this be how miri works? + pub fn usize() -> Self { + match mem::size_of::() { + 4 => Repr::U32, + 8 => Repr::U64, + _ => unimplemented!(), + } + } + pub fn size(&self) -> usize { match *self { Repr::Bool => 1, - Repr::I8 => 1, - Repr::I16 => 2, - Repr::I32 => 4, - Repr::I64 => 8, + Repr::I8 | Repr::U8 => 1, + Repr::I16 | Repr::U16 => 2, + Repr::I32 | Repr::U32 => 4, + Repr::I64 | Repr::U64 => 8, Repr::Product { size, .. } => size, Repr::Sum { ref discr, max_variant_size, .. } => discr.size() + max_variant_size, Repr::Pointer { .. } => POINTER_SIZE, diff --git a/src/primval.rs b/src/primval.rs index 63d5598ece0..88bd88b1746 100644 --- a/src/primval.rs +++ b/src/primval.rs @@ -5,31 +5,29 @@ use memory::Repr; #[derive(Clone, Copy, Debug, PartialEq)] pub enum PrimVal { Bool(bool), - I8(i8), - I16(i16), - I32(i32), - I64(i64), + I8(i8), I16(i16), I32(i32), I64(i64), + U8(u8), U16(u16), U32(u32), U64(u64), } impl PrimVal { - pub fn from_int(n: i64, repr: &Repr) -> Self { + pub fn from_usize(n: usize, repr: &Repr) -> Self { // TODO(tsion): Use checked casts. match *repr { - Repr::I8 => PrimVal::I8(n as i8), - Repr::I16 => PrimVal::I16(n as i16), - Repr::I32 => PrimVal::I32(n as i32), - Repr::I64 => PrimVal::I64(n), - _ => panic!("attempted to make integer primval from non-integer repr"), + Repr::U8 => PrimVal::U8(n as u8), + Repr::U16 => PrimVal::U16(n as u16), + Repr::U32 => PrimVal::U32(n as u32), + Repr::U64 => PrimVal::U64(n as u64), + _ => panic!("attempted to make usize primval from non-uint repr"), } } - pub fn to_int(self) -> i64 { + pub fn to_usize(self) -> usize { match self { - PrimVal::I8(n) => n as i64, - PrimVal::I16(n) => n as i64, - PrimVal::I32(n) => n as i64, - PrimVal::I64(n) => n, - _ => panic!("attempted to make integer from non-integer primval"), + PrimVal::U8(n) => n as usize, + PrimVal::U16(n) => n as usize, + PrimVal::U32(n) => n as usize, + PrimVal::U64(n) => n as usize, + _ => panic!("attempted to make usize from non-uint primval"), } } } @@ -65,10 +63,14 @@ pub fn binary_op(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> PrimVal { use self::PrimVal::*; match (left, right) { - (I8(l), I8(r)) => int_binops!(I8, l, r), + (I8(l), I8(r)) => int_binops!(I8, l, r), (I16(l), I16(r)) => int_binops!(I16, l, r), (I32(l), I32(r)) => int_binops!(I32, l, r), (I64(l), I64(r)) => int_binops!(I64, l, r), + (U8(l), U8(r)) => int_binops!(U8, l, r), + (U16(l), U16(r)) => int_binops!(U16, l, r), + (U32(l), U32(r)) => int_binops!(U32, l, r), + (U64(l), U64(r)) => int_binops!(U64, l, r), _ => unimplemented!(), } } @@ -78,14 +80,18 @@ pub fn unary_op(un_op: mir::UnOp, val: PrimVal) -> PrimVal { use self::PrimVal::*; match (un_op, val) { (Not, Bool(b)) => Bool(!b), - (Not, I8(n)) => I8(!n), - (Neg, I8(n)) => I8(-n), + (Not, I8(n)) => I8(!n), + (Neg, I8(n)) => I8(-n), (Not, I16(n)) => I16(!n), (Neg, I16(n)) => I16(-n), (Not, I32(n)) => I32(!n), (Neg, I32(n)) => I32(-n), (Not, I64(n)) => I64(!n), (Neg, I64(n)) => I64(-n), + (Not, U8(n)) => U8(!n), + (Not, U16(n)) => U16(!n), + (Not, U32(n)) => U32(!n), + (Not, U64(n)) => U64(!n), _ => unimplemented!(), } }