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

View file

@ -195,6 +195,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
(Size::from_bytes(field * elem_size), false) (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), _ => 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"); assert!(field.is_none(), "local can't be ByRef and have a field offset");
(ptr, LvalueExtra::None) (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(_) => { Value::ByVal(_) => {
assert_eq!(offset.bytes(), 0, "ByVal can only have 1 non zst field with offset 0"); assert_eq!(offset.bytes(), 0, "ByVal can only have 1 non zst field with offset 0");
return Ok(base); return Ok(base);

View file

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