Skip to content

Commit

Permalink
Merge pull request rust-lang#60 from oli-obk/dst
Browse files Browse the repository at this point in the history
some more cleanups getting rid of intermediate allocations and bad fat ptr assumptions
  • Loading branch information
solson authored Sep 27, 2016
2 parents 1e3659e + 7e29392 commit 10ab168
Show file tree
Hide file tree
Showing 9 changed files with 431 additions and 203 deletions.
10 changes: 9 additions & 1 deletion src/interpreter/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use primval::PrimVal;
use memory::Pointer;

use rustc::ty::Ty;
use syntax::ast;
use syntax::ast::{self, IntTy, UintTy};

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
pub(super) fn cast_primval(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
Expand Down Expand Up @@ -37,6 +37,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
ty::TyRef(..) |
ty::TyRawPtr(_) => Ok(Ptr(ptr)),
ty::TyFnPtr(_) => Ok(FnPtr(ptr)),
ty::TyInt(IntTy::I8) => Ok(I8(ptr.to_int()? as i8)),
ty::TyInt(IntTy::I16) => Ok(I16(ptr.to_int()? as i16)),
ty::TyInt(IntTy::I32) => Ok(I32(ptr.to_int()? as i32)),
ty::TyInt(IntTy::I64) => Ok(I64(ptr.to_int()? as i64)),
ty::TyUint(UintTy::U8) => Ok(U8(ptr.to_int()? as u8)),
ty::TyUint(UintTy::U16) => Ok(U16(ptr.to_int()? as u16)),
ty::TyUint(UintTy::U32) => Ok(U32(ptr.to_int()? as u32)),
ty::TyUint(UintTy::U64) => Ok(U64(ptr.to_int()? as u64)),
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
}
}
Expand Down
273 changes: 135 additions & 138 deletions src/interpreter/mod.rs

Large diffs are not rendered by default.

104 changes: 59 additions & 45 deletions src/interpreter/terminator/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ use rustc::hir::def_id::DefId;
use rustc::mir::repr as mir;
use rustc::ty::layout::Layout;
use rustc::ty::subst::Substs;
use rustc::ty;
use rustc::ty::{self, Ty};

use error::{EvalError, EvalResult};
use memory::Pointer;
use interpreter::EvalContext;
use primval;
use primval::{self, PrimVal};
use interpreter::value::Value;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
pub(super) fn call_intrinsic(
Expand All @@ -16,29 +17,35 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
substs: &'tcx Substs<'tcx>,
args: &[mir::Operand<'tcx>],
dest: Pointer,
dest_ty: Ty<'tcx>,
dest_layout: &'tcx Layout,
) -> EvalResult<'tcx, ()> {
// TODO(solson): We can probably remove this _to_ptr easily.
let args_res: EvalResult<Vec<Pointer>> = args.iter()
.map(|arg| self.eval_operand_to_ptr(arg))
let args_ptrs: EvalResult<Vec<Value>> = args.iter()
.map(|arg| self.eval_operand(arg))
.collect();
let args_ptrs = args_res?;
let args_ptrs = args_ptrs?;
let pointer_size = self.memory.pointer_size();
let i32 = self.tcx.types.i32;
let isize = self.tcx.types.isize;
let usize = self.tcx.types.usize;
let f32 = self.tcx.types.f32;
let f64 = self.tcx.types.f64;

match &self.tcx.item_name(def_id).as_str()[..] {
"add_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Add, &args[0], &args[1], dest, dest_layout)?,
"sub_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Sub, &args[0], &args[1], dest, dest_layout)?,
"mul_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Mul, &args[0], &args[1], dest, dest_layout)?,

"arith_offset" => {
let ptr = self.memory.read_ptr(args_ptrs[0])?;
let offset = self.memory.read_int(args_ptrs[1], pointer_size)?;
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
let offset = self.value_to_primval(args_ptrs[1], isize)?.expect_int("arith_offset second arg not isize");
let new_ptr = ptr.offset(offset as isize);
self.memory.write_ptr(dest, new_ptr)?;
}

"assume" => {
if !self.memory.read_bool(args_ptrs[0])? {
let bool = self.tcx.types.bool;
if !self.value_to_primval(args_ptrs[0], bool)?.expect_bool("assume arg not bool") {
return Err(EvalError::AssumptionNotHeld);
}
}
Expand All @@ -51,47 +58,59 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let elem_ty = substs.type_at(0);
let elem_size = self.type_size(elem_ty);
let elem_align = self.type_align(elem_ty);
let src = self.memory.read_ptr(args_ptrs[0])?;
let dest = self.memory.read_ptr(args_ptrs[1])?;
let count = self.memory.read_isize(args_ptrs[2])?;
let src = args_ptrs[0].read_ptr(&self.memory)?;
let dest = args_ptrs[1].read_ptr(&self.memory)?;
let count = self.value_to_primval(args_ptrs[2], usize)?.expect_uint("arith_offset second arg not isize");
self.memory.copy(src, dest, count as usize * elem_size, elem_align)?;
}

"ctpop" => {
let elem_ty = substs.type_at(0);
let elem_size = self.type_size(elem_ty);
let num = self.memory.read_uint(args_ptrs[0], elem_size)?.count_ones();
let num = self.value_to_primval(args_ptrs[2], elem_ty)?.expect_int("ctpop second arg not integral");
let num = num.count_ones();
self.memory.write_uint(dest, num.into(), elem_size)?;
}

"ctlz" => {
let elem_ty = substs.type_at(0);
let elem_size = self.type_size(elem_ty);
let num = self.memory.read_uint(args_ptrs[0], elem_size)?.leading_zeros();
let num = self.value_to_primval(args_ptrs[2], elem_ty)?;
let num = match num {
PrimVal::I8(i) => i.leading_zeros(),
PrimVal::U8(i) => i.leading_zeros(),
PrimVal::I16(i) => i.leading_zeros(),
PrimVal::U16(i) => i.leading_zeros(),
PrimVal::I32(i) => i.leading_zeros(),
PrimVal::U32(i) => i.leading_zeros(),
PrimVal::I64(i) => i.leading_zeros(),
PrimVal::U64(i) => i.leading_zeros(),
_ => bug!("ctlz called with non-integer type"),
};
self.memory.write_uint(dest, num.into(), elem_size)?;
}

"discriminant_value" => {
let ty = substs.type_at(0);
let adt_ptr = self.memory.read_ptr(args_ptrs[0])?;
let adt_ptr = args_ptrs[0].read_ptr(&self.memory)?;
let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
self.memory.write_uint(dest, discr_val, 8)?;
}

"fabsf32" => {
let f = self.memory.read_f32(args_ptrs[0])?;
let f = self.value_to_primval(args_ptrs[2], f32)?.expect_f32("fabsf32 read non f32");
self.memory.write_f32(dest, f.abs())?;
}

"fabsf64" => {
let f = self.memory.read_f64(args_ptrs[0])?;
let f = self.value_to_primval(args_ptrs[2], f64)?.expect_f64("fabsf64 read non f64");
self.memory.write_f64(dest, f.abs())?;
}

"fadd_fast" => {
let ty = substs.type_at(0);
let a = self.read_primval(args_ptrs[0], ty)?;
let b = self.read_primval(args_ptrs[0], ty)?;
let a = self.value_to_primval(args_ptrs[0], ty)?;
let b = self.value_to_primval(args_ptrs[0], ty)?;
let result = primval::binary_op(mir::BinOp::Add, a, b)?;
self.memory.write_primval(dest, result.0)?;
}
Expand All @@ -117,8 +136,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

"move_val_init" => {
let ty = substs.type_at(0);
let ptr = self.memory.read_ptr(args_ptrs[0])?;
self.move_(args_ptrs[1], ptr, ty)?;
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
self.write_value(args_ptrs[1], ptr, ty)?;
}

"needs_drop" => {
Expand All @@ -129,10 +148,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
"offset" => {
let pointee_ty = substs.type_at(0);
let pointee_size = self.type_size(pointee_ty) as isize;
let ptr_arg = args_ptrs[0];
let offset = self.memory.read_isize(args_ptrs[1])?;
let offset = self.value_to_primval(args_ptrs[1], isize)?.expect_int("offset second arg not isize");

let ptr = self.memory.read_ptr(ptr_arg)?;
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
let result_ptr = ptr.offset(offset as isize * pointee_size);
self.memory.write_ptr(dest, result_ptr)?;
}
Expand All @@ -150,24 +168,24 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}

"powif32" => {
let f = self.memory.read_f32(args_ptrs[0])?;
let i = self.memory.read_int(args_ptrs[1], 4)?;
let f = self.value_to_primval(args_ptrs[0], f32)?.expect_f32("powif32 first arg not f32");
let i = self.value_to_primval(args_ptrs[1], i32)?.expect_int("powif32 second arg not i32");
self.memory.write_f32(dest, f.powi(i as i32))?;
}

"powif64" => {
let f = self.memory.read_f32(args_ptrs[0])?;
let i = self.memory.read_int(args_ptrs[1], 4)?;
self.memory.write_f32(dest, f.powi(i as i32))?;
let f = self.value_to_primval(args_ptrs[0], f64)?.expect_f64("powif64 first arg not f64");
let i = self.value_to_primval(args_ptrs[1], i32)?.expect_int("powif64 second arg not i32");
self.memory.write_f64(dest, f.powi(i as i32))?;
}

"sqrtf32" => {
let f = self.memory.read_f32(args_ptrs[0])?;
let f = self.value_to_primval(args_ptrs[0], f32)?.expect_f32("sqrtf32 first arg not f32");
self.memory.write_f32(dest, f.sqrt())?;
}

"sqrtf64" => {
let f = self.memory.read_f64(args_ptrs[0])?;
let f = self.value_to_primval(args_ptrs[0], f64)?.expect_f64("sqrtf64 first arg not f64");
self.memory.write_f64(dest, f.sqrt())?;
}

Expand All @@ -182,14 +200,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let (size, _) = self.size_and_align_of_dst(ty, args_ptrs[0])?;
self.memory.write_uint(dest, size, pointer_size)?;
}
// FIXME: wait for eval_operand_to_ptr to be gone
/*
"type_name" => {
let ty = substs.type_at(0);
let ty_name = ty.to_string();
let s = self.str_to_value(&ty_name)?;
self.memory.write_ptr(dest, s)?;
}*/
self.write_value(s, dest, dest_ty)?;
}
"type_id" => {
let ty = substs.type_at(0);
let n = self.tcx.type_id_hash(ty);
Expand All @@ -198,7 +214,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

"transmute" => {
let ty = substs.type_at(0);
self.move_(args_ptrs[0], dest, ty)?;
self.write_value(args_ptrs[0], dest, ty)?;
}

"try" => unimplemented!(),
Expand All @@ -207,14 +223,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {

"volatile_load" => {
let ty = substs.type_at(0);
let ptr = self.memory.read_ptr(args_ptrs[0])?;
let ptr = args_ptrs[0].read_ptr(&self.memory)?;
self.move_(ptr, dest, ty)?;
}

"volatile_store" => {
let ty = substs.type_at(0);
let dest = self.memory.read_ptr(args_ptrs[0])?;
self.move_(args_ptrs[1], dest, ty)?;
let dest = args_ptrs[0].read_ptr(&self.memory)?;
self.write_value(args_ptrs[1], dest, ty)?;
}

name => return Err(EvalError::Unimplemented(format!("unimplemented intrinsic: {}", name))),
Expand All @@ -229,7 +245,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
fn size_and_align_of_dst(
&self,
ty: ty::Ty<'tcx>,
value: Pointer,
value: Value,
) -> EvalResult<'tcx, (u64, u64)> {
let pointer_size = self.memory.pointer_size();
if self.type_is_sized(ty) {
Expand Down Expand Up @@ -306,8 +322,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
}
ty::TyTrait(..) => {
let (_, vtable) = self.get_fat_ptr(value);
let vtable = self.memory.read_ptr(vtable)?;
let vtable = value.expect_vtable(&self.memory)?;
// the second entry in the vtable is the dynamic size of the object.
let size = self.memory.read_usize(vtable.offset(pointer_size as isize))?;
let align = self.memory.read_usize(vtable.offset(pointer_size as isize * 2))?;
Expand All @@ -317,10 +332,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
ty::TySlice(_) | ty::TyStr => {
let elem_ty = ty.sequence_element_type(self.tcx);
let elem_size = self.type_size(elem_ty) as u64;
let (_, len_ptr) = self.get_fat_ptr(value);
let n = self.memory.read_usize(len_ptr)?;
let len = value.expect_slice_len(&self.memory)?;
let align = self.type_align(elem_ty);
Ok((n * elem_size, align as u64))
Ok((len * elem_size, align as u64))
}

_ => bug!("size_of_val::<{:?}>", ty),
Expand Down
36 changes: 17 additions & 19 deletions src/interpreter/terminator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use syntax::{ast, attr};
use error::{EvalError, EvalResult};
use memory::Pointer;
use primval::PrimVal;
use super::{EvalContext, IntegerExt, StackPopCleanup, Value};
use super::{EvalContext, IntegerExt, StackPopCleanup};
use super::value::Value;

mod intrinsics;

Expand Down Expand Up @@ -164,7 +165,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let ty = fn_ty.sig.0.output;
let layout = self.type_layout(ty);
let (ret, target) = destination.unwrap();
self.call_intrinsic(def_id, substs, arg_operands, ret, layout)?;
self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout)?;
self.goto_block(target);
Ok(())
}
Expand Down Expand Up @@ -265,9 +266,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
None => name.as_str(),
};

// TODO(solson): We can probably remove this _to_ptr easily.
let args_res: EvalResult<Vec<Pointer>> = args.iter()
.map(|arg| self.eval_operand_to_ptr(arg))
let args_res: EvalResult<Vec<Value>> = args.iter()
.map(|arg| self.eval_operand(arg))
.collect();
let args = args_res?;

Expand All @@ -276,26 +276,28 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
return Ok(());
}

let usize = self.tcx.types.usize;

match &link_name[..] {
"__rust_allocate" => {
let size = self.memory.read_usize(args[0])?;
let align = self.memory.read_usize(args[1])?;
let size = self.value_to_primval(args[0], usize)?.expect_uint("__rust_allocate first arg not usize");
let align = self.value_to_primval(args[1], usize)?.expect_uint("__rust_allocate second arg not usize");
let ptr = self.memory.allocate(size as usize, align as usize)?;
self.memory.write_ptr(dest, ptr)?;
}

"__rust_reallocate" => {
let ptr = self.memory.read_ptr(args[0])?;
let size = self.memory.read_usize(args[2])?;
let align = self.memory.read_usize(args[3])?;
let ptr = args[0].read_ptr(&self.memory)?;
let size = self.value_to_primval(args[2], usize)?.expect_uint("__rust_reallocate third arg not usize");
let align = self.value_to_primval(args[3], usize)?.expect_uint("__rust_reallocate fourth arg not usize");
let new_ptr = self.memory.reallocate(ptr, size as usize, align as usize)?;
self.memory.write_ptr(dest, new_ptr)?;
}

"memcmp" => {
let left = self.memory.read_ptr(args[0])?;
let right = self.memory.read_ptr(args[1])?;
let n = self.memory.read_usize(args[2])? as usize;
let left = args[0].read_ptr(&self.memory)?;
let right = args[1].read_ptr(&self.memory)?;
let n = self.value_to_primval(args[2], usize)?.expect_uint("__rust_reallocate first arg not usize") as usize;

let result = {
let left_bytes = self.memory.read_bytes(left, n)?;
Expand Down Expand Up @@ -419,7 +421,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// intermediate function call.
// FIXME: this is a memory leak, should probably add the pointer to the
// current stack.
let first = self.value_to_ptr(args[0].0, args[0].1)?;
let first = self.value_to_ptr_dont_use(args[0].0, args[0].1)?;
args[0].0 = Value::ByVal(PrimVal::Ptr(first));
args[0].1 = self.tcx.mk_mut_ptr(args[0].1);
}
Expand All @@ -442,11 +444,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
traits::VtableObject(ref data) => {
let idx = self.tcx.get_vtable_index_of_object_method(data, def_id);
if let Some(&mut(ref mut first_arg, ref mut first_ty)) = args.get_mut(0) {
// FIXME(solson): Remove this allocating hack.
let ptr = self.value_to_ptr(*first_arg, *first_ty)?;
*first_arg = Value::ByRef(ptr);
let (_, vtable) = self.get_fat_ptr(ptr);
let vtable = self.memory.read_ptr(vtable)?;
let vtable = first_arg.expect_vtable(&self.memory)?;
let idx = idx + 3;
let offset = idx * self.memory.pointer_size();
let fn_ptr = self.memory.read_ptr(vtable.offset(offset as isize))?;
Expand Down
Loading

0 comments on commit 10ab168

Please sign in to comment.