From ac71d6f345001031a46fb49f0513ec576752eaee Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 13 Feb 2017 11:58:42 +0100 Subject: [PATCH] don't duplicate field access logic, always go through lvalue_field --- src/eval_context.rs | 50 ++++++++++++++++++------------------------- src/lvalue.rs | 17 +++++++++++++++ src/terminator/mod.rs | 17 +++++++-------- 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/src/eval_context.rs b/src/eval_context.rs index 9fb6492efd3..b57e3a49bd6 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -358,45 +358,45 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } pub fn assign_discr_and_fields< - I: IntoIterator, V: IntoValTyPair<'tcx>, J: IntoIterator, >( &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, V: IntoValTyPair<'tcx>, J: IntoIterator, >( &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 { .. } => { diff --git a/src/lvalue.rs b/src/lvalue.rs index f3f8c3fde0c..d4d292cd4e5 100644 --- a/src/lvalue.rs +++ b/src/lvalue.rs @@ -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); diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index d8035c9f670..4fb39681613 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -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));