1
Fork 0

Move a method used everywhere out of intrinsic.rs

This commit is contained in:
Oliver Schneider 2017-07-28 10:16:36 +02:00
parent e15d374dda
commit df7c42bcc8
No known key found for this signature in database
GPG key ID: A69F8D225B3AD7D9
2 changed files with 96 additions and 102 deletions

View file

@ -7,7 +7,7 @@ use rustc::middle::const_val::ConstVal;
use rustc::middle::region::CodeExtent;
use rustc::mir;
use rustc::traits::Reveal;
use rustc::ty::layout::{self, Layout, Size};
use rustc::ty::layout::{self, Layout, Size, Align};
use rustc::ty::subst::{Subst, Substs, Kind};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Binder};
use rustc::traits;
@ -277,6 +277,98 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
self.tcx.erase_regions(&value)
}
pub fn size_and_align_of_dst(
&mut self,
ty: ty::Ty<'tcx>,
value: Value,
) -> EvalResult<'tcx, (u64, u64)> {
if let Some(size) = self.type_size(ty)? {
Ok((size as u64, self.type_align(ty)? as u64))
} else {
match ty.sty {
ty::TyAdt(def, substs) => {
// First get the size of all statically known fields.
// Don't use type_of::sizing_type_of because that expects t to be sized,
// and it also rounds up to alignment, which we want to avoid,
// as the unsized field's alignment could be smaller.
assert!(!ty.is_simd());
let layout = self.type_layout(ty)?;
debug!("DST {} layout: {:?}", ty, layout);
let (sized_size, sized_align) = match *layout {
ty::layout::Layout::Univariant { ref variant, .. } => {
(variant.offsets.last().map_or(0, |o| o.bytes()), variant.align)
}
_ => {
bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
ty, layout);
}
};
debug!("DST {} statically sized prefix size: {} align: {:?}",
ty, sized_size, sized_align);
// Recurse to get the size of the dynamically sized field (must be
// the last field).
let last_field = def.struct_variant().fields.last().unwrap();
let field_ty = self.field_ty(substs, last_field);
let (unsized_size, unsized_align) = self.size_and_align_of_dst(field_ty, value)?;
// FIXME (#26403, #27023): We should be adding padding
// to `sized_size` (to accommodate the `unsized_align`
// required of the unsized field that follows) before
// summing it with `sized_size`. (Note that since #26403
// is unfixed, we do not yet add the necessary padding
// here. But this is where the add would go.)
// Return the sum of sizes and max of aligns.
let size = sized_size + unsized_size;
// Choose max of two known alignments (combined value must
// be aligned according to more restrictive of the two).
let align = sized_align.max(Align::from_bytes(unsized_align, unsized_align).unwrap());
// Issue #27023: must add any necessary padding to `size`
// (to make it a multiple of `align`) before returning it.
//
// Namely, the returned size should be, in C notation:
//
// `size + ((size & (align-1)) ? align : 0)`
//
// emulated via the semi-standard fast bit trick:
//
// `(size + (align-1)) & -align`
let size = Size::from_bytes(size).abi_align(align).bytes();
Ok((size, align.abi()))
}
ty::TyDynamic(..) => {
let (_, vtable) = value.into_ptr_vtable_pair(&mut self.memory)?;
// the second entry in the vtable is the dynamic size of the object.
self.read_size_and_align_from_vtable(vtable)
}
ty::TySlice(_) | ty::TyStr => {
let elem_ty = ty.sequence_element_type(self.tcx);
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized") as u64;
let (_, len) = value.into_slice(&mut self.memory)?;
let align = self.type_align(elem_ty)?;
Ok((len * elem_size, align as u64))
}
_ => bug!("size_of_val::<{:?}>", ty),
}
}
}
/// Returns the normalized type of a struct field
fn field_ty(
&self,
param_substs: &Substs<'tcx>,
f: &ty::FieldDef,
) -> ty::Ty<'tcx> {
self.tcx.normalize_associated_type(&f.ty(self.tcx, param_substs))
}
pub(super) fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<u64>> {
self.type_size_with_substs(ty, self.substs())
}
@ -1556,8 +1648,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
let dest = self.force_allocation(dest)?.to_ptr()?;
let iter = src_fields.zip(dst_fields).enumerate();
for (i, (src_f, dst_f)) in iter {
let src_fty = monomorphize_field_ty(self.tcx, src_f, substs_a);
let dst_fty = monomorphize_field_ty(self.tcx, dst_f, substs_b);
let src_fty = self.field_ty(substs_a, src_f);
let dst_fty = self.field_ty(substs_b, dst_f);
if self.type_size(dst_fty)? == Some(0) {
continue;
}
@ -1726,12 +1818,6 @@ impl IntegerExt for layout::Integer {
}
}
pub fn monomorphize_field_ty<'a, 'tcx:'a >(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &ty::FieldDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
let substituted = f.ty(tcx, substs);
tcx.normalize_associated_type(&substituted)
}
pub fn is_inhabited<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.uninhabited_from(&mut HashMap::default(), tcx).is_empty()
}

View file

@ -1,7 +1,6 @@
use rustc::mir;
use rustc::traits::Reveal;
use rustc::ty::layout::{Layout, Size, Align};
use rustc::ty::subst::Substs;
use rustc::ty::layout::Layout;
use rustc::ty::{self, Ty};
use interpret::{
@ -487,97 +486,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
// current frame.
Ok(())
}
pub fn size_and_align_of_dst(
&mut self,
ty: ty::Ty<'tcx>,
value: Value,
) -> EvalResult<'tcx, (u64, u64)> {
if let Some(size) = self.type_size(ty)? {
Ok((size as u64, self.type_align(ty)? as u64))
} else {
match ty.sty {
ty::TyAdt(def, substs) => {
// First get the size of all statically known fields.
// Don't use type_of::sizing_type_of because that expects t to be sized,
// and it also rounds up to alignment, which we want to avoid,
// as the unsized field's alignment could be smaller.
assert!(!ty.is_simd());
let layout = self.type_layout(ty)?;
debug!("DST {} layout: {:?}", ty, layout);
let (sized_size, sized_align) = match *layout {
ty::layout::Layout::Univariant { ref variant, .. } => {
(variant.offsets.last().map_or(0, |o| o.bytes()), variant.align)
}
_ => {
bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
ty, layout);
}
};
debug!("DST {} statically sized prefix size: {} align: {:?}",
ty, sized_size, sized_align);
// Recurse to get the size of the dynamically sized field (must be
// the last field).
let last_field = def.struct_variant().fields.last().unwrap();
let field_ty = self.field_ty(substs, last_field);
let (unsized_size, unsized_align) = self.size_and_align_of_dst(field_ty, value)?;
// FIXME (#26403, #27023): We should be adding padding
// to `sized_size` (to accommodate the `unsized_align`
// required of the unsized field that follows) before
// summing it with `sized_size`. (Note that since #26403
// is unfixed, we do not yet add the necessary padding
// here. But this is where the add would go.)
// Return the sum of sizes and max of aligns.
let size = sized_size + unsized_size;
// Choose max of two known alignments (combined value must
// be aligned according to more restrictive of the two).
let align = sized_align.max(Align::from_bytes(unsized_align, unsized_align).unwrap());
// Issue #27023: must add any necessary padding to `size`
// (to make it a multiple of `align`) before returning it.
//
// Namely, the returned size should be, in C notation:
//
// `size + ((size & (align-1)) ? align : 0)`
//
// emulated via the semi-standard fast bit trick:
//
// `(size + (align-1)) & -align`
let size = Size::from_bytes(size).abi_align(align).bytes();
Ok((size, align.abi()))
}
ty::TyDynamic(..) => {
let (_, vtable) = value.into_ptr_vtable_pair(&self.memory)?;
// the second entry in the vtable is the dynamic size of the object.
self.read_size_and_align_from_vtable(vtable)
}
ty::TySlice(_) | ty::TyStr => {
let elem_ty = ty.sequence_element_type(self.tcx);
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized") as u64;
let (_, len) = value.into_slice(&self.memory)?;
let align = self.type_align(elem_ty)?;
Ok((len * elem_size, align as u64))
}
_ => bug!("size_of_val::<{:?}>", ty),
}
}
}
/// Returns the normalized type of a struct field
fn field_ty(
&self,
param_substs: &Substs<'tcx>,
f: &ty::FieldDef,
) -> ty::Ty<'tcx> {
self.tcx.normalize_associated_type(&f.ty(self.tcx, param_substs))
}
}
fn numeric_intrinsic<'tcx>(