1
Fork 0

Add unsigned integers.

This commit is contained in:
Scott Olson 2016-03-14 23:03:31 -06:00
parent 9e1bb9841e
commit 9d1d96ce07
3 changed files with 118 additions and 43 deletions

View file

@ -210,7 +210,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
_ => panic!("attmpted to switch on non-sum type"), _ => panic!("attmpted to switch on non-sum type"),
}; };
let discr_val = try!(self.memory.read_primval(adt_ptr, &discr_repr)); 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, .. } => { Call { ref func, ref args, ref destination, .. } => {
@ -298,7 +298,7 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
ty::AdtKind::Enum => match dest_repr { ty::AdtKind::Enum => match dest_repr {
Repr::Sum { ref discr, ref variants, .. } => { Repr::Sum { ref discr, ref variants, .. } => {
if discr.size() > 0 { 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)); try!(self.memory.write_primval(dest, discr_val));
} }
self.assign_to_product( self.assign_to_product(
@ -442,12 +442,18 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
match ty.subst(self.tcx, self.current_substs()).sty { match ty.subst(self.tcx, self.current_substs()).sty {
ty::TyBool => Repr::Bool, ty::TyBool => Repr::Bool,
ty::TyInt(IntTy::Is) => unimplemented!(), ty::TyInt(IntTy::Is) => Repr::isize(),
ty::TyInt(IntTy::I8) => Repr::I8, ty::TyInt(IntTy::I8) => Repr::I8,
ty::TyInt(IntTy::I16) => Repr::I16, ty::TyInt(IntTy::I16) => Repr::I16,
ty::TyInt(IntTy::I32) => Repr::I32, ty::TyInt(IntTy::I32) => Repr::I32,
ty::TyInt(IntTy::I64) => Repr::I64, 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::TyTuple(ref fields) => self.make_product_repr(fields.iter().cloned()),
ty::TyEnum(adt_def, substs) => { ty::TyEnum(adt_def, substs) => {
@ -456,13 +462,13 @@ impl<'a, 'tcx: 'a> Interpreter<'a, 'tcx> {
let discr = if num_variants <= 1 { let discr = if num_variants <= 1 {
Repr::Product { size: 0, fields: vec![] } Repr::Product { size: 0, fields: vec![] }
} else if num_variants <= 1 << 8 { } else if num_variants <= 1 << 8 {
Repr::I8 Repr::U8
} else if num_variants <= 1 << 16 { } else if num_variants <= 1 << 16 {
Repr::I16 Repr::U16
} else if num_variants <= 1 << 32 { } else if num_variants <= 1 << 32 {
Repr::I32 Repr::U32
} else { } else {
Repr::I64 Repr::U64
}; };
let variants: Vec<Repr> = adt_def.variants.iter().map(|v| { let variants: Vec<Repr> = adt_def.variants.iter().map(|v| {

View file

@ -1,6 +1,7 @@
use byteorder::{self, ByteOrder}; use byteorder::{self, ByteOrder};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::collections::Bound::{Included, Excluded}; use std::collections::Bound::{Included, Excluded};
use std::mem;
use std::ptr; use std::ptr;
use error::{EvalError, EvalResult}; use error::{EvalError, EvalResult};
@ -38,10 +39,8 @@ pub struct FieldRepr {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum Repr { pub enum Repr {
Bool, Bool,
I8, I8, I16, I32, I64,
I16, U8, U16, U32, U64,
I32,
I64,
/// The representation for product types including tuples, structs, and the contents of enum /// The representation for product types including tuples, structs, and the contents of enum
/// variants. /// variants.
@ -170,10 +169,14 @@ impl Memory {
pub fn read_primval(&self, ptr: Pointer, repr: &Repr) -> EvalResult<PrimVal> { pub fn read_primval(&self, ptr: Pointer, repr: &Repr) -> EvalResult<PrimVal> {
match *repr { match *repr {
Repr::Bool => self.read_bool(ptr).map(PrimVal::Bool), Repr::Bool => self.read_bool(ptr).map(PrimVal::Bool),
Repr::I8 => self.read_i8(ptr).map(PrimVal::I8), Repr::I8 => self.read_i8(ptr).map(PrimVal::I8),
Repr::I16 => self.read_i16(ptr).map(PrimVal::I16), Repr::I16 => self.read_i16(ptr).map(PrimVal::I16),
Repr::I32 => self.read_i32(ptr).map(PrimVal::I32), Repr::I32 => self.read_i32(ptr).map(PrimVal::I32),
Repr::I64 => self.read_i64(ptr).map(PrimVal::I64), 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), _ => panic!("primitive read of non-primitive: {:?}", repr),
} }
} }
@ -181,10 +184,14 @@ impl Memory {
pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<()> { pub fn write_primval(&mut self, ptr: Pointer, val: PrimVal) -> EvalResult<()> {
match val { match val {
PrimVal::Bool(b) => self.write_bool(ptr, b), PrimVal::Bool(b) => self.write_bool(ptr, b),
PrimVal::I8(n) => self.write_i8(ptr, n), PrimVal::I8(n) => self.write_i8(ptr, n),
PrimVal::I16(n) => self.write_i16(ptr, n), PrimVal::I16(n) => self.write_i16(ptr, n),
PrimVal::I32(n) => self.write_i32(ptr, n), PrimVal::I32(n) => self.write_i32(ptr, n),
PrimVal::I64(n) => self.write_i64(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); byteorder::NativeEndian::write_i64(bytes, n);
Ok(()) Ok(())
} }
pub fn read_u8(&self, ptr: Pointer) -> EvalResult<u8> {
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<u16> {
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<u32> {
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<u64> {
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 { impl Allocation {
@ -287,13 +332,31 @@ impl Pointer {
} }
impl Repr { 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::<isize>() {
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::<isize>() {
4 => Repr::U32,
8 => Repr::U64,
_ => unimplemented!(),
}
}
pub fn size(&self) -> usize { pub fn size(&self) -> usize {
match *self { match *self {
Repr::Bool => 1, Repr::Bool => 1,
Repr::I8 => 1, Repr::I8 | Repr::U8 => 1,
Repr::I16 => 2, Repr::I16 | Repr::U16 => 2,
Repr::I32 => 4, Repr::I32 | Repr::U32 => 4,
Repr::I64 => 8, Repr::I64 | Repr::U64 => 8,
Repr::Product { size, .. } => size, Repr::Product { size, .. } => size,
Repr::Sum { ref discr, max_variant_size, .. } => discr.size() + max_variant_size, Repr::Sum { ref discr, max_variant_size, .. } => discr.size() + max_variant_size,
Repr::Pointer { .. } => POINTER_SIZE, Repr::Pointer { .. } => POINTER_SIZE,

View file

@ -5,31 +5,29 @@ use memory::Repr;
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum PrimVal { pub enum PrimVal {
Bool(bool), Bool(bool),
I8(i8), I8(i8), I16(i16), I32(i32), I64(i64),
I16(i16), U8(u8), U16(u16), U32(u32), U64(u64),
I32(i32),
I64(i64),
} }
impl PrimVal { 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. // TODO(tsion): Use checked casts.
match *repr { match *repr {
Repr::I8 => PrimVal::I8(n as i8), Repr::U8 => PrimVal::U8(n as u8),
Repr::I16 => PrimVal::I16(n as i16), Repr::U16 => PrimVal::U16(n as u16),
Repr::I32 => PrimVal::I32(n as i32), Repr::U32 => PrimVal::U32(n as u32),
Repr::I64 => PrimVal::I64(n), Repr::U64 => PrimVal::U64(n as u64),
_ => panic!("attempted to make integer primval from non-integer repr"), _ => panic!("attempted to make usize primval from non-uint repr"),
} }
} }
pub fn to_int(self) -> i64 { pub fn to_usize(self) -> usize {
match self { match self {
PrimVal::I8(n) => n as i64, PrimVal::U8(n) => n as usize,
PrimVal::I16(n) => n as i64, PrimVal::U16(n) => n as usize,
PrimVal::I32(n) => n as i64, PrimVal::U32(n) => n as usize,
PrimVal::I64(n) => n, PrimVal::U64(n) => n as usize,
_ => panic!("attempted to make integer from non-integer primval"), _ => 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::*; use self::PrimVal::*;
match (left, right) { 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), (I16(l), I16(r)) => int_binops!(I16, l, r),
(I32(l), I32(r)) => int_binops!(I32, l, r), (I32(l), I32(r)) => int_binops!(I32, l, r),
(I64(l), I64(r)) => int_binops!(I64, 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!(), _ => unimplemented!(),
} }
} }
@ -78,14 +80,18 @@ pub fn unary_op(un_op: mir::UnOp, val: PrimVal) -> PrimVal {
use self::PrimVal::*; use self::PrimVal::*;
match (un_op, val) { match (un_op, val) {
(Not, Bool(b)) => Bool(!b), (Not, Bool(b)) => Bool(!b),
(Not, I8(n)) => I8(!n), (Not, I8(n)) => I8(!n),
(Neg, I8(n)) => I8(-n), (Neg, I8(n)) => I8(-n),
(Not, I16(n)) => I16(!n), (Not, I16(n)) => I16(!n),
(Neg, I16(n)) => I16(-n), (Neg, I16(n)) => I16(-n),
(Not, I32(n)) => I32(!n), (Not, I32(n)) => I32(!n),
(Neg, I32(n)) => I32(-n), (Neg, I32(n)) => I32(-n),
(Not, I64(n)) => I64(!n), (Not, I64(n)) => I64(!n),
(Neg, 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!(), _ => unimplemented!(),
} }
} }