1
Fork 0

rustc: don't track whether layouts are "packed".

This commit is contained in:
Eduard-Mihai Burtescu 2017-12-01 18:29:35 +02:00
parent 53a6d14e5b
commit 7c6f242ca8
10 changed files with 116 additions and 184 deletions

View file

@ -895,7 +895,7 @@ pub struct InterpretInterner<'tcx> {
/// Allows checking whether a constant already has an allocation /// Allows checking whether a constant already has an allocation
/// ///
/// The pointers are to the beginning of an `alloc_by_id` allocation /// The pointers are to the beginning of an `alloc_by_id` allocation
alloc_cache: FxHashMap<interpret::GlobalId<'tcx>, interpret::PtrAndAlign>, alloc_cache: FxHashMap<interpret::GlobalId<'tcx>, interpret::Pointer>,
/// A cache for basic byte allocations keyed by their contents. This is used to deduplicate /// A cache for basic byte allocations keyed by their contents. This is used to deduplicate
/// allocations for string and bytestring literals. /// allocations for string and bytestring literals.
@ -931,14 +931,14 @@ impl<'tcx> InterpretInterner<'tcx> {
pub fn get_cached( pub fn get_cached(
&self, &self,
global_id: interpret::GlobalId<'tcx>, global_id: interpret::GlobalId<'tcx>,
) -> Option<interpret::PtrAndAlign> { ) -> Option<interpret::Pointer> {
self.alloc_cache.get(&global_id).cloned() self.alloc_cache.get(&global_id).cloned()
} }
pub fn cache( pub fn cache(
&mut self, &mut self,
global_id: interpret::GlobalId<'tcx>, global_id: interpret::GlobalId<'tcx>,
ptr: interpret::PtrAndAlign, ptr: interpret::Pointer,
) { ) {
if let Some(old) = self.alloc_cache.insert(global_id, ptr) { if let Some(old) = self.alloc_cache.insert(global_id, ptr) {
bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old); bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old);

View file

@ -778,7 +778,6 @@ pub enum Abi {
Aggregate { Aggregate {
/// If true, the size is exact, otherwise it's only a lower bound. /// If true, the size is exact, otherwise it's only a lower bound.
sized: bool, sized: bool,
packed: bool
} }
} }
@ -790,18 +789,7 @@ impl Abi {
Abi::Scalar(_) | Abi::Scalar(_) |
Abi::ScalarPair(..) | Abi::ScalarPair(..) |
Abi::Vector { .. } => false, Abi::Vector { .. } => false,
Abi::Aggregate { sized, .. } => !sized Abi::Aggregate { sized } => !sized
}
}
/// Returns true if the fields of the layout are packed.
pub fn is_packed(&self) -> bool {
match *self {
Abi::Uninhabited |
Abi::Scalar(_) |
Abi::ScalarPair(..) |
Abi::Vector { .. } => false,
Abi::Aggregate { packed, .. } => packed
} }
} }
} }
@ -1077,10 +1065,7 @@ impl<'a, 'tcx> LayoutDetails {
} }
let size = min_size.abi_align(align); let size = min_size.abi_align(align);
let mut abi = Abi::Aggregate { let mut abi = Abi::Aggregate { sized };
sized,
packed
};
// Unpack newtype ABIs and find scalar pairs. // Unpack newtype ABIs and find scalar pairs.
if sized && size.bytes() > 0 { if sized && size.bytes() > 0 {
@ -1254,10 +1239,7 @@ impl<'a, 'tcx> LayoutDetails {
stride: element.size, stride: element.size,
count count
}, },
abi: Abi::Aggregate { abi: Abi::Aggregate { sized: true },
sized: true,
packed: false
},
align: element.align, align: element.align,
size size
}) })
@ -1270,10 +1252,7 @@ impl<'a, 'tcx> LayoutDetails {
stride: element.size, stride: element.size,
count: 0 count: 0
}, },
abi: Abi::Aggregate { abi: Abi::Aggregate { sized: false },
sized: false,
packed: false
},
align: element.align, align: element.align,
size: Size::from_bytes(0) size: Size::from_bytes(0)
}) })
@ -1285,10 +1264,7 @@ impl<'a, 'tcx> LayoutDetails {
stride: Size::from_bytes(1), stride: Size::from_bytes(1),
count: 0 count: 0
}, },
abi: Abi::Aggregate { abi: Abi::Aggregate { sized: false },
sized: false,
packed: false
},
align: dl.i8_align, align: dl.i8_align,
size: Size::from_bytes(0) size: Size::from_bytes(0)
}) })
@ -1302,7 +1278,7 @@ impl<'a, 'tcx> LayoutDetails {
let mut unit = univariant_uninterned(&[], &ReprOptions::default(), let mut unit = univariant_uninterned(&[], &ReprOptions::default(),
StructKind::AlwaysSized)?; StructKind::AlwaysSized)?;
match unit.abi { match unit.abi {
Abi::Aggregate { ref mut sized, .. } => *sized = false, Abi::Aggregate { ref mut sized } => *sized = false,
_ => bug!() _ => bug!()
} }
tcx.intern_layout(unit) tcx.intern_layout(unit)
@ -1418,10 +1394,7 @@ impl<'a, 'tcx> LayoutDetails {
return Ok(tcx.intern_layout(LayoutDetails { return Ok(tcx.intern_layout(LayoutDetails {
variants: Variants::Single { index: 0 }, variants: Variants::Single { index: 0 },
fields: FieldPlacement::Union(variants[0].len()), fields: FieldPlacement::Union(variants[0].len()),
abi: Abi::Aggregate { abi: Abi::Aggregate { sized: true },
sized: true,
packed
},
align, align,
size: size.abi_align(align) size: size.abi_align(align)
})); }));
@ -1525,15 +1498,10 @@ impl<'a, 'tcx> LayoutDetails {
let abi = if offset.bytes() == 0 && niche.value.size(dl) == size { let abi = if offset.bytes() == 0 && niche.value.size(dl) == size {
Abi::Scalar(niche.clone()) Abi::Scalar(niche.clone())
} else { } else {
let mut packed = st[i].abi.is_packed();
if offset.abi_align(niche_align) != offset { if offset.abi_align(niche_align) != offset {
packed = true;
niche_align = dl.i8_align; niche_align = dl.i8_align;
} }
Abi::Aggregate { Abi::Aggregate { sized: true }
sized: true,
packed
}
}; };
align = align.max(niche_align); align = align.max(niche_align);
@ -1681,10 +1649,7 @@ impl<'a, 'tcx> LayoutDetails {
let abi = if discr.value.size(dl) == size { let abi = if discr.value.size(dl) == size {
Abi::Scalar(discr.clone()) Abi::Scalar(discr.clone())
} else { } else {
Abi::Aggregate { Abi::Aggregate { sized: true }
sized: true,
packed: false
}
}; };
tcx.intern_layout(LayoutDetails { tcx.intern_layout(LayoutDetails {
variants: Variants::Tagged { variants: Variants::Tagged {
@ -2277,11 +2242,6 @@ impl<'a, 'tcx> TyLayout<'tcx> {
self.abi.is_unsized() self.abi.is_unsized()
} }
/// Returns true if the fields of the layout are packed.
pub fn is_packed(&self) -> bool {
self.abi.is_packed()
}
/// Returns true if the type is a ZST and not unsized. /// Returns true if the type is a ZST and not unsized.
pub fn is_zst(&self) -> bool { pub fn is_zst(&self) -> bool {
match self.abi { match self.abi {
@ -2289,7 +2249,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
Abi::Scalar(_) | Abi::Scalar(_) |
Abi::ScalarPair(..) | Abi::ScalarPair(..) |
Abi::Vector { .. } => false, Abi::Vector { .. } => false,
Abi::Aggregate { sized, .. } => sized && self.size.bytes() == 0 Abi::Aggregate { sized } => sized && self.size.bytes() == 0
} }
} }
@ -2452,8 +2412,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
element.hash_stable(hcx, hasher); element.hash_stable(hcx, hasher);
count.hash_stable(hcx, hasher); count.hash_stable(hcx, hasher);
} }
Aggregate { packed, sized } => { Aggregate { sized } => {
packed.hash_stable(hcx, hasher);
sized.hash_stable(hcx, hasher); sized.hash_stable(hcx, hasher);
} }
} }

View file

@ -12,7 +12,7 @@ use rustc_data_structures::indexed_vec::Idx;
use syntax::ast::Mutability; use syntax::ast::Mutability;
use syntax::codemap::Span; use syntax::codemap::Span;
use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, PrimVal, PtrAndAlign}; use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, Pointer, PrimVal, PtrAndAlign};
use super::{Place, PlaceExtra, EvalContext, StackPopCleanup, ValTy, HasMemory}; use super::{Place, PlaceExtra, EvalContext, StackPopCleanup, ValTy, HasMemory};
use rustc_const_math::ConstInt; use rustc_const_math::ConstInt;
@ -45,7 +45,7 @@ pub fn eval_body<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>, instance: Instance<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> EvalResult<'tcx, (PtrAndAlign, Ty<'tcx>)> { ) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> {
debug!("eval_body: {:?}, {:?}", instance, param_env); debug!("eval_body: {:?}, {:?}", instance, param_env);
let limits = super::ResourceLimits::default(); let limits = super::ResourceLimits::default();
let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ()); let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
@ -69,13 +69,7 @@ pub fn eval_body<'a, 'tcx>(
layout.align.abi(), layout.align.abi(),
None, None,
)?; )?;
tcx.interpret_interner.borrow_mut().cache( tcx.interpret_interner.borrow_mut().cache(cid, ptr.into());
cid,
PtrAndAlign {
ptr: ptr.into(),
aligned: !layout.is_packed(),
},
);
let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable); let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable);
let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id())); let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
trace!("const_eval: pushing stack frame for global: {}", name); trace!("const_eval: pushing stack frame for global: {}", name);
@ -101,7 +95,7 @@ pub fn eval_body_as_integer<'a, 'tcx>(
let ptr_ty = eval_body(tcx, instance, param_env); let ptr_ty = eval_body(tcx, instance, param_env);
let (ptr, ty) = ptr_ty?; let (ptr, ty) = ptr_ty?;
let ecx = mk_eval_cx(tcx, instance, param_env)?; let ecx = mk_eval_cx(tcx, instance, param_env)?;
let prim = match ecx.read_maybe_aligned(ptr.aligned, |ectx| ectx.try_read_value(ptr.ptr, ty))? { let prim = match ecx.try_read_value(ptr, ty)? {
Some(Value::ByVal(prim)) => prim.to_bytes()?, Some(Value::ByVal(prim)) => prim.to_bytes()?,
_ => return err!(TypeNotPrimitive(ty)), _ => return err!(TypeNotPrimitive(ty)),
}; };
@ -363,7 +357,10 @@ pub fn const_eval_provider<'a, 'tcx>(
(_, Err(err)) => Err(err), (_, Err(err)) => Err(err),
(Ok((miri_val, miri_ty)), Ok(ctfe)) => { (Ok((miri_val, miri_ty)), Ok(ctfe)) => {
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
check_ctfe_against_miri(&mut ecx, miri_val, miri_ty, ctfe.val); check_ctfe_against_miri(&mut ecx, PtrAndAlign {
ptr: miri_val,
aligned: true
}, miri_ty, ctfe.val);
Ok(ctfe) Ok(ctfe)
} }
} }

View file

@ -261,11 +261,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
Unevaluated(def_id, substs) => { Unevaluated(def_id, substs) => {
let instance = self.resolve(def_id, substs)?; let instance = self.resolve(def_id, substs)?;
let cid = GlobalId { return Ok(self.read_global_as_value(GlobalId {
instance, instance,
promoted: None, promoted: None,
}; }));
return Ok(Value::ByRef(self.tcx.interpret_interner.borrow().get_cached(cid).expect("static/const not cached")));
} }
Aggregate(..) | Aggregate(..) |
@ -834,11 +833,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
Literal::Value { ref value } => self.const_to_value(&value.val)?, Literal::Value { ref value } => self.const_to_value(&value.val)?,
Literal::Promoted { index } => { Literal::Promoted { index } => {
let cid = GlobalId { self.read_global_as_value(GlobalId {
instance: self.frame().instance, instance: self.frame().instance,
promoted: Some(index), promoted: Some(index),
}; })
Value::ByRef(self.tcx.interpret_interner.borrow().get_cached(cid).expect("promoted not cached"))
} }
}; };
@ -951,7 +949,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
} }
pub fn read_global_as_value(&self, gid: GlobalId) -> Value { pub fn read_global_as_value(&self, gid: GlobalId) -> Value {
Value::ByRef(self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached")) Value::ByRef(PtrAndAlign {
ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached"),
aligned: true
})
} }
fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> { fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> {
@ -1149,51 +1150,29 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
} }
Value::ByVal(primval) => { Value::ByVal(primval) => {
let layout = self.layout_of(dest_ty)?; let layout = self.layout_of(dest_ty)?;
if layout.is_zst() { match layout.abi {
assert!(primval.is_undef()); layout::Abi::Scalar(_) => {}
Ok(()) _ if primval.is_undef() => {}
} else { _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
// TODO: Do we need signedness?
self.memory.write_maybe_aligned_mut(!layout.is_packed(), |mem| {
mem.write_primval(dest.to_ptr()?, primval, layout.size.bytes(), false)
})
} }
// TODO: Do we need signedness?
self.memory.write_primval(dest.to_ptr()?, primval, layout.size.bytes(), false)
} }
Value::ByValPair(a, b) => { Value::ByValPair(a_val, b_val) => {
let ptr = dest.to_ptr()?; let ptr = dest.to_ptr()?;
let mut layout = self.layout_of(dest_ty)?; let mut layout = self.layout_of(dest_ty)?;
trace!("write_value_to_ptr valpair: {:#?}", layout); trace!("write_value_to_ptr valpair: {:#?}", layout);
let mut packed = layout.is_packed(); let (a, b) = match layout.abi {
'outer: loop { layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
for i in 0..layout.fields.count() { _ => bug!("write_value_to_ptr: invalid ByValPair layout: {:#?}", layout)
let field = layout.field(&self, i)?; };
if layout.fields.offset(i).bytes() == 0 && layout.size == field.size { let (a_size, b_size) = (a.size(&self), b.size(&self));
layout = field; let a_ptr = ptr;
packed |= layout.is_packed(); let b_offset = a_size.abi_align(b.align(&self));
continue 'outer; let b_ptr = ptr.offset(b_offset.bytes(), &self)?.into();
}
}
break;
}
trace!("write_value_to_ptr valpair: {:#?}", layout);
assert_eq!(layout.fields.count(), 2);
let field_0 = layout.field(&self, 0)?;
let field_1 = layout.field(&self, 1)?;
trace!("write_value_to_ptr field 0: {:#?}", field_0);
trace!("write_value_to_ptr field 1: {:#?}", field_1);
assert_eq!(
field_0.is_packed(),
field_1.is_packed(),
"the two fields must agree on being packed"
);
packed |= field_0.is_packed();
let field_0_ptr = ptr.offset(layout.fields.offset(0).bytes(), &self)?.into();
let field_1_ptr = ptr.offset(layout.fields.offset(1).bytes(), &self)?.into();
// TODO: What about signedess? // TODO: What about signedess?
self.memory.write_maybe_aligned_mut(!packed, |mem| { self.memory.write_primval(a_ptr, a_val, a_size.bytes(), false)?;
mem.write_primval(field_0_ptr, a, field_0.size.bytes(), false)?; self.memory.write_primval(b_ptr, b_val, b_size.bytes(), false)?;
mem.write_primval(field_1_ptr, b, field_1.size.bytes(), false)
})?;
Ok(()) Ok(())
} }
} }

View file

@ -1,6 +1,6 @@
use rustc::mir; use rustc::mir;
use rustc::ty::{self, Ty}; use rustc::ty::{self, Ty};
use rustc::ty::layout::{LayoutOf, TyLayout}; use rustc::ty::layout::{self, LayoutOf, TyLayout};
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use rustc::mir::interpret::{GlobalId, PtrAndAlign}; use rustc::mir::interpret::{GlobalId, PtrAndAlign};
@ -106,9 +106,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
instance, instance,
promoted: None, promoted: None,
}; };
Ok(Some(Value::ByRef( Ok(Some(self.read_global_as_value(cid)))
self.tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"),
)))
} }
Projection(ref proj) => self.try_read_place_projection(proj), Projection(ref proj) => self.try_read_place_projection(proj),
} }
@ -193,7 +191,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
promoted: None, promoted: None,
}; };
Place::Ptr { Place::Ptr {
ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("uncached global"), ptr: PtrAndAlign {
ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("uncached global"),
aligned: true
},
extra: PlaceExtra::None, extra: PlaceExtra::None,
} }
} }
@ -232,15 +233,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
let (base_ptr, base_extra) = match base { let (base_ptr, base_extra) = match base {
Place::Ptr { ptr, extra } => (ptr, extra), Place::Ptr { ptr, extra } => (ptr, extra),
Place::Local { frame, local } => { Place::Local { frame, local } => {
match self.stack[frame].get_local(local)? { match (&self.stack[frame].get_local(local)?, &base_layout.abi) {
// in case the field covers the entire type, just return the value // in case the field covers the entire type, just return the value
Value::ByVal(_) if offset.bytes() == 0 && (&Value::ByVal(_), &layout::Abi::Scalar(_)) |
field.size == base_layout.size => { (&Value::ByValPair(..), &layout::Abi::ScalarPair(..))
if offset.bytes() == 0 && field.size == base_layout.size =>
{
return Ok((base, field)); return Ok((base, field));
} }
Value::ByRef { .. } | _ => self.force_allocation(base)?.to_ptr_extra_aligned(),
Value::ByValPair(..) |
Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(),
} }
} }
}; };
@ -257,9 +258,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
}; };
let mut ptr = base_ptr.offset(offset, &self)?; let mut ptr = base_ptr.offset(offset, &self)?;
// if we were unaligned, stay unaligned ptr.aligned &= base_layout.align.abi() >= field.align.abi();
// no matter what we were, if we are packed, we must not be aligned anymore
ptr.aligned &= !base_layout.is_packed();
let extra = if !field.is_unsized() { let extra = if !field.is_unsized() {
PlaceExtra::None PlaceExtra::None

View file

@ -8,7 +8,7 @@ use rustc::mir;
use rustc::ty::{self, Instance}; use rustc::ty::{self, Instance};
use rustc::ty::layout::LayoutOf; use rustc::ty::layout::LayoutOf;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::mir::interpret::{PtrAndAlign, GlobalId}; use rustc::mir::interpret::GlobalId;
use rustc::mir::interpret::{EvalResult, EvalErrorKind}; use rustc::mir::interpret::{EvalResult, EvalErrorKind};
use super::{EvalContext, StackPopCleanup, Place, Machine}; use super::{EvalContext, StackPopCleanup, Place, Machine};
@ -182,13 +182,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
layout.align.abi(), layout.align.abi(),
None, None,
)?; )?;
self.tcx.interpret_interner.borrow_mut().cache( self.tcx.interpret_interner.borrow_mut().cache(cid, ptr.into());
cid,
PtrAndAlign {
ptr: ptr.into(),
aligned: !layout.is_packed(),
},
);
let internally_mutable = !layout.ty.is_freeze(self.tcx, self.param_env, span); let internally_mutable = !layout.ty.is_freeze(self.tcx, self.param_env, span);
let mutability = if mutability == Mutability::Mutable || internally_mutable { let mutability = if mutability == Mutability::Mutable || internally_mutable {
Mutability::Mutable Mutability::Mutable
@ -273,13 +267,7 @@ impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b,
layout.align.abi(), layout.align.abi(),
None, None,
)?; )?;
this.ecx.tcx.interpret_interner.borrow_mut().cache( this.ecx.tcx.interpret_interner.borrow_mut().cache(cid, ptr.into());
cid,
PtrAndAlign {
ptr: ptr.into(),
aligned: !layout.is_packed(),
},
);
trace!("pushing stack frame for {:?}", index); trace!("pushing stack frame for {:?}", index);
this.ecx.push_stack_frame( this.ecx.push_stack_frame(
this.instance, this.instance,

View file

@ -69,7 +69,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
// Recurse to get the size of the dynamically sized field (must be // Recurse to get the size of the dynamically sized field (must be
// the last field). // the last field).
let field_ty = layout.field(ccx, i).ty; let field_ty = layout.field(ccx, i).ty;
let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info); let (unsized_size, mut unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
// FIXME (#26403, #27023): We should be adding padding // FIXME (#26403, #27023): We should be adding padding
// to `sized_size` (to accommodate the `unsized_align` // to `sized_size` (to accommodate the `unsized_align`
@ -81,6 +81,13 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
// Return the sum of sizes and max of aligns. // Return the sum of sizes and max of aligns.
let size = bcx.add(sized_size, unsized_size); let size = bcx.add(sized_size, unsized_size);
// Packed types ignore the alignment of their fields.
if let ty::TyAdt(def, _) = t.sty {
if def.repr.packed() {
unsized_align = sized_align;
}
}
// Choose max of two known alignments (combined value must // Choose max of two known alignments (combined value must
// be aligned according to more restrictive of the two). // be aligned according to more restrictive of the two).
let align = match (const_to_opt_u128(sized_align, false), let align = match (const_to_opt_u128(sized_align, false),

View file

@ -1134,12 +1134,14 @@ fn trans_const_adt<'a, 'tcx>(
if let layout::FieldPlacement::Union(_) = l.fields { if let layout::FieldPlacement::Union(_) = l.fields {
assert_eq!(variant_index, 0); assert_eq!(variant_index, 0);
assert_eq!(vals.len(), 1); assert_eq!(vals.len(), 1);
let (field_size, field_align) = ccx.size_and_align_of(vals[0].ty);
let contents = [ let contents = [
vals[0].llval, vals[0].llval,
padding(ccx, l.size - ccx.size_of(vals[0].ty)) padding(ccx, l.size - field_size)
]; ];
Const::new(C_struct(ccx, &contents, l.is_packed()), t) let packed = l.align.abi() < field_align.abi();
Const::new(C_struct(ccx, &contents, packed), t)
} else { } else {
if let layout::Abi::Vector { .. } = l.abi { if let layout::Abi::Vector { .. } = l.abi {
if let layout::FieldPlacement::Array { .. } = l.fields { if let layout::FieldPlacement::Array { .. } = l.fields {
@ -1232,28 +1234,33 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
} }
// offset of current value // offset of current value
let mut packed = false;
let mut offset = Size::from_bytes(0); let mut offset = Size::from_bytes(0);
let mut cfields = Vec::new(); let mut cfields = Vec::new();
cfields.reserve(discr.is_some() as usize + 1 + layout.fields.count() * 2); cfields.reserve(discr.is_some() as usize + 1 + layout.fields.count() * 2);
if let Some(discr) = discr { if let Some(discr) = discr {
let (field_size, field_align) = ccx.size_and_align_of(discr.ty);
packed |= layout.align.abi() < field_align.abi();
cfields.push(discr.llval); cfields.push(discr.llval);
offset = ccx.size_of(discr.ty); offset = field_size;
} }
let parts = layout.fields.index_by_increasing_offset().map(|i| { let parts = layout.fields.index_by_increasing_offset().map(|i| {
(vals[i], layout.fields.offset(i)) (vals[i], layout.fields.offset(i))
}); });
for (val, target_offset) in parts { for (val, target_offset) in parts {
let (field_size, field_align) = ccx.size_and_align_of(val.ty);
packed |= layout.align.abi() < field_align.abi();
cfields.push(padding(ccx, target_offset - offset)); cfields.push(padding(ccx, target_offset - offset));
cfields.push(val.llval); cfields.push(val.llval);
offset = target_offset + ccx.size_of(val.ty); offset = target_offset + field_size;
} }
// Pad to the size of the whole type, not e.g. the variant. // Pad to the size of the whole type, not e.g. the variant.
cfields.push(padding(ccx, ccx.size_of(layout.ty) - offset)); cfields.push(padding(ccx, ccx.size_of(layout.ty) - offset));
Const::new(C_struct(ccx, &cfields, layout.is_packed()), layout.ty) Const::new(C_struct(ccx, &cfields, packed), layout.ty)
} }
fn padding(ccx: &CrateContext, size: Size) -> ValueRef { fn padding(ccx: &CrateContext, size: Size) -> ValueRef {

View file

@ -55,11 +55,7 @@ impl ops::BitOr for Alignment {
impl<'a> From<TyLayout<'a>> for Alignment { impl<'a> From<TyLayout<'a>> for Alignment {
fn from(layout: TyLayout) -> Self { fn from(layout: TyLayout) -> Self {
if layout.is_packed() { Alignment::Packed(layout.align)
Alignment::Packed(layout.align)
} else {
Alignment::AbiAligned
}
} }
} }
@ -232,25 +228,27 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
} }
}; };
// Simple case - we can just GEP the field // Simple cases, which don't need DST adjustment:
// * Packed struct - There is no alignment padding // * no metadata available - just log the case
// * Field is sized - pointer is properly aligned already // * known alignment - sized types, [T], str or a foreign type
if self.layout.is_packed() || !field.is_unsized() { // * packed struct - there is no alignment padding
return simple();
}
// If the type of the last field is [T], str or a foreign type, then we don't need to do
// any adjusments
match field.ty.sty { match field.ty.sty {
_ if !self.has_extra() => {
debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
ix, Value(self.llval));
return simple();
}
_ if !field.is_unsized() => return simple(),
ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => return simple(), ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => return simple(),
_ => () ty::TyAdt(def, _) => {
} if def.repr.packed() {
// FIXME(eddyb) generalize the adjustment when we
// There's no metadata available, log the case and just do the GEP. // start supporting packing to larger alignments.
if !self.has_extra() { assert_eq!(self.layout.align.abi(), 1);
debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment", return simple();
ix, Value(self.llval)); }
return simple(); }
_ => {}
} }
// We need to get the pointer manually now. // We need to get the pointer manually now.

View file

@ -79,13 +79,14 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
match layout.fields { match layout.fields {
layout::FieldPlacement::Union(_) => { layout::FieldPlacement::Union(_) => {
let fill = Type::padding_filler(ccx, layout.size, layout.align); let fill = Type::padding_filler(ccx, layout.size, layout.align);
let packed = false;
match name { match name {
None => { None => {
Type::struct_(ccx, &[fill], layout.is_packed()) Type::struct_(ccx, &[fill], packed)
} }
Some(ref name) => { Some(ref name) => {
let mut llty = Type::named_struct(ccx, name); let mut llty = Type::named_struct(ccx, name);
llty.set_struct_body(&[fill], layout.is_packed()); llty.set_struct_body(&[fill], packed);
llty llty
} }
} }
@ -96,7 +97,8 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
layout::FieldPlacement::Arbitrary { .. } => { layout::FieldPlacement::Arbitrary { .. } => {
match name { match name {
None => { None => {
Type::struct_(ccx, &struct_llfields(ccx, layout), layout.is_packed()) let (llfields, packed) = struct_llfields(ccx, layout);
Type::struct_(ccx, &llfields, packed)
} }
Some(ref name) => { Some(ref name) => {
let llty = Type::named_struct(ccx, name); let llty = Type::named_struct(ccx, name);
@ -109,15 +111,19 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
} }
fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
layout: TyLayout<'tcx>) -> Vec<Type> { layout: TyLayout<'tcx>)
-> (Vec<Type>, bool) {
debug!("struct_llfields: {:#?}", layout); debug!("struct_llfields: {:#?}", layout);
let field_count = layout.fields.count(); let field_count = layout.fields.count();
let mut packed = false;
let mut offset = Size::from_bytes(0); let mut offset = Size::from_bytes(0);
let mut prev_align = layout.align; let mut prev_align = layout.align;
let mut result: Vec<Type> = Vec::with_capacity(1 + field_count * 2); let mut result: Vec<Type> = Vec::with_capacity(1 + field_count * 2);
for i in layout.fields.index_by_increasing_offset() { for i in layout.fields.index_by_increasing_offset() {
let field = layout.field(ccx, i); let field = layout.field(ccx, i);
packed |= layout.align.abi() < field.align.abi();
let target_offset = layout.fields.offset(i as usize); let target_offset = layout.fields.offset(i as usize);
debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}", debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}",
i, field, offset, target_offset); i, field, offset, target_offset);
@ -129,15 +135,6 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
debug!(" padding before: {:?}", padding); debug!(" padding before: {:?}", padding);
result.push(field.llvm_type(ccx)); result.push(field.llvm_type(ccx));
if layout.is_packed() {
assert_eq!(padding.bytes(), 0);
} else {
assert!(field.align.abi() <= layout.align.abi(),
"non-packed type has field with larger align ({}): {:#?}",
field.align.abi(), layout);
}
offset = target_offset + field.size; offset = target_offset + field.size;
prev_align = field.align; prev_align = field.align;
} }
@ -158,7 +155,7 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
offset, layout.size); offset, layout.size);
} }
result (result, packed)
} }
impl<'a, 'tcx> CrateContext<'a, 'tcx> { impl<'a, 'tcx> CrateContext<'a, 'tcx> {
@ -301,7 +298,8 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
ccx.lltypes().borrow_mut().insert((self.ty, variant_index), llty); ccx.lltypes().borrow_mut().insert((self.ty, variant_index), llty);
if let Some((mut llty, layout)) = defer { if let Some((mut llty, layout)) = defer {
llty.set_struct_body(&struct_llfields(ccx, layout), layout.is_packed()) let (llfields, packed) = struct_llfields(ccx, layout);
llty.set_struct_body(&llfields, packed)
} }
llty llty