1
Fork 0

don't duplicate field access logic, always go through lvalue_field

This commit is contained in:
Oliver Schneider 2017-02-13 11:58:42 +01:00
parent a727ceb7e9
commit ac71d6f345
No known key found for this signature in database
GPG key ID: A69F8D225B3AD7D9
3 changed files with 46 additions and 38 deletions

View file

@ -358,45 +358,45 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
pub fn assign_discr_and_fields<
I: IntoIterator<Item = u64>,
V: IntoValTyPair<'tcx>,
J: IntoIterator<Item = V>,
>(
&mut self,
dest: Lvalue<'tcx>,
offsets: I,
dest_ty: Ty<'tcx>,
discr_offset: u64,
operands: J,
discr_val: u128,
variant_idx: usize,
discr_size: u64,
) -> EvalResult<'tcx> {
// FIXME(solson)
let dest_ptr = self.force_allocation(dest)?.to_ptr();
let mut offsets = offsets.into_iter();
let discr_offset = offsets.next().unwrap();
let discr_dest = dest_ptr.offset(discr_offset);
self.memory.write_uint(discr_dest, discr_val, discr_size)?;
self.assign_fields(dest, offsets, operands)
let dest = Lvalue::Ptr {
ptr: dest_ptr,
extra: LvalueExtra::DowncastVariant(variant_idx),
};
self.assign_fields(dest, dest_ty, operands)
}
pub fn assign_fields<
I: IntoIterator<Item = u64>,
V: IntoValTyPair<'tcx>,
J: IntoIterator<Item = V>,
>(
&mut self,
dest: Lvalue<'tcx>,
offsets: I,
dest_ty: Ty<'tcx>,
operands: J,
) -> EvalResult<'tcx> {
// FIXME(solson)
let dest = self.force_allocation(dest)?.to_ptr();
for (offset, operand) in offsets.into_iter().zip(operands) {
for (field_index, operand) in operands.into_iter().enumerate() {
let (value, value_ty) = operand.into_val_ty_pair(self)?;
let field_dest = dest.offset(offset);
self.write_value_to_ptr(value, field_dest, value_ty)?;
let field_dest = self.lvalue_field(dest, field_index, dest_ty, value_ty)?;
self.write_value(value, field_dest, value_ty)?;
}
Ok(())
}
@ -444,22 +444,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
use rustc::ty::layout::Layout::*;
match *dest_layout {
Univariant { ref variant, .. } => {
let offsets = variant.offsets.iter().map(|s| s.bytes());
if variant.packed {
let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
self.memory.mark_packed(ptr, variant.stride().bytes());
}
self.assign_fields(dest, offsets, operands)?;
self.assign_fields(dest, dest_ty, operands)?;
}
Array { .. } => {
let elem_size = match dest_ty.sty {
ty::TyArray(elem_ty, _) => self.type_size(elem_ty)?
.expect("array elements are sized") as u64,
_ => bug!("tried to assign {:?} to non-array type {:?}", kind, dest_ty),
};
let offsets = (0..).map(|i| i * elem_size);
self.assign_fields(dest, offsets, operands)?;
self.assign_fields(dest, dest_ty, operands)?;
}
General { discr, ref variants, .. } => {
@ -473,9 +466,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
self.assign_discr_and_fields(
dest,
variants[variant].offsets.iter().cloned().map(Size::bytes),
dest_ty,
variants[variant].offsets[0].bytes(),
operands,
discr_val,
variant,
discr_size,
)?;
} else {
@ -511,8 +506,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
self.memory.mark_packed(ptr, nonnull.stride().bytes());
}
if nndiscr == variant as u64 {
let offsets = nonnull.offsets.iter().map(|s| s.bytes());
self.assign_fields(dest, offsets, operands)?;
self.assign_fields(dest, dest_ty, operands)?;
} else {
for operand in operands {
let operand_ty = self.operand_ty(operand);
@ -543,11 +537,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}
}
Vector { element, count } => {
let elem_size = element.size(&self.tcx.data_layout).bytes();
Vector { count, .. } => {
debug_assert_eq!(count, operands.len() as u64);
let offsets = (0..).map(|i| i * elem_size);
self.assign_fields(dest, offsets, operands)?;
self.assign_fields(dest, dest_ty, operands)?;
}
UntaggedUnion { .. } => {

View file

@ -195,6 +195,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
(Size::from_bytes(field * elem_size), false)
}
// We treat arrays + fixed sized indexing like field accesses
Array { .. } => {
let field = field_index as u64;
let elem_size = match base_ty.sty {
ty::TyArray(elem_ty, n) => {
assert!(field < n as u64);
self.type_size(elem_ty)?.expect("array elements are sized") as u64
},
_ => bug!("lvalue_field: got Array layout but non-array type {:?}", base_ty),
};
(Size::from_bytes(field * elem_size), false)
}
_ => bug!("field access on non-product type: {:?}", base_layout),
};
@ -205,6 +218,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
assert!(field.is_none(), "local can't be ByRef and have a field offset");
(ptr, LvalueExtra::None)
},
Value::ByVal(PrimVal::Undef) => {
// FIXME: add some logic for when to not allocate
(self.force_allocation(base)?.to_ptr(), LvalueExtra::None)
},
Value::ByVal(_) => {
assert_eq!(offset.bytes(), 0, "ByVal can only have 1 non zst field with offset 0");
return Ok(base);

View file

@ -1,6 +1,6 @@
use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::ty::layout::{Layout, Size};
use rustc::ty::layout::Layout;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, BareFnTy};
use syntax::codemap::Span;
@ -215,29 +215,28 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let dest_layout = self.type_layout(dest_ty)?;
trace!("layout({:?}) = {:#?}", dest_ty, dest_layout);
match *dest_layout {
Layout::Univariant { ref variant, .. } => {
Layout::Univariant { .. } => {
let disr_val = v.disr_val.to_u128_unchecked();
assert_eq!(disr_val, 0);
let offsets = variant.offsets.iter().map(|s| s.bytes());
self.assign_fields(lvalue, offsets, args)?;
self.assign_fields(lvalue, dest_ty, args)?;
},
Layout::General { discr, ref variants, .. } => {
let disr_val = v.disr_val.to_u128_unchecked();
let discr_size = discr.size().bytes();
self.assign_discr_and_fields(
lvalue,
variants[disr_val as usize].offsets.iter().cloned().map(Size::bytes),
dest_ty,
variants[disr_val as usize].offsets[0].bytes(),
args,
disr_val,
disr_val as usize,
discr_size,
)?;
},
Layout::StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield, .. } => {
Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
let disr_val = v.disr_val.to_u128_unchecked();
if nndiscr as u128 == disr_val {
let offsets = nonnull.offsets.iter().map(|s| s.bytes());
self.assign_fields(lvalue, offsets, args)?;
self.assign_fields(lvalue, dest_ty, args)?;
} else {
for (_, ty) in args {
assert_eq!(self.type_size(ty)?, Some(0));