rustc: make Layout::NullablePointer a lot more like Layout::General.

This commit is contained in:
Eduard-Mihai Burtescu 2017-09-17 02:25:20 +03:00
parent 33a205b56f
commit bd86f3739e
7 changed files with 83 additions and 115 deletions

View File

@ -1128,9 +1128,12 @@ pub enum Layout {
/// identity function.
NullablePointer {
nndiscr: u64,
nonnull: Struct,
discr: Primitive,
discr_offset: Size,
variants: Vec<Struct>,
size: Size,
align: Align,
primitive_align: Align,
}
}
@ -1471,23 +1474,20 @@ impl<'a, 'tcx> Layout {
!def.repr.inhibit_enum_layout_opt() &&
no_explicit_discriminants {
// Nullable pointer optimization
let st0 = Struct::new(dl, &variants[0],
&def.repr, StructKind::AlwaysSizedUnivariant, ty)?;
let st1 = Struct::new(dl, &variants[1],
&def.repr, StructKind::AlwaysSizedUnivariant, ty)?;
let mut st = vec![
Struct::new(dl, &variants[0],
&def.repr, StructKind::AlwaysSizedUnivariant, ty)?,
Struct::new(dl, &variants[1],
&def.repr, StructKind::AlwaysSizedUnivariant, ty)?
];
let mut choice = None;
for discr in 0..2 {
let (st, other) = if discr == 0 {
(&st0, &st1)
} else {
(&st1, &st0)
};
if other.stride().bytes() > 0 {
if st[1 - discr].stride().bytes() > 0 {
continue;
}
let field = st.non_zero_field(tcx, param_env,
let field = st[discr].non_zero_field(tcx, param_env,
variants[discr].iter().map(|&f| Ok(f)))?;
if let Some((offset, primitive)) = field {
choice = Some((discr, offset, primitive));
@ -1496,23 +1496,22 @@ impl<'a, 'tcx> Layout {
}
if let Some((discr, offset, primitive)) = choice {
// HACK(eddyb) work around not being able to move
// out of arrays with just the indexing operator.
let mut st = if discr == 0 { st0 } else { st1 };
let mut discr_align = primitive.align(dl);
if offset.abi_align(discr_align) != offset {
st.packed = true;
st[discr].packed = true;
discr_align = dl.i8_align;
}
st.align = st.align.max(discr_align);
st.primitive_align = st.primitive_align.max(discr_align);
let align = st[discr].align.max(discr_align);
let primitive_align = st[discr].primitive_align.max(discr_align);
return success(NullablePointer {
nndiscr: discr as u64,
nonnull: st,
discr: primitive,
discr_offset: offset,
size: st[discr].stride(),
align,
primitive_align,
variants: st,
});
}
}
@ -1693,13 +1692,10 @@ impl<'a, 'tcx> Layout {
metadata.size(dl)).abi_align(self.align(dl))
}
NullablePointer { size, .. } |
General { size, .. } => size,
UntaggedUnion(ref un) => un.stride(),
Univariant(ref variant) |
NullablePointer { nonnull: ref variant, .. } => {
variant.stride()
}
Univariant(ref variant) => variant.stride()
}
}
@ -1726,13 +1722,11 @@ impl<'a, 'tcx> Layout {
Pointer.align(dl).max(metadata.align(dl))
}
Array { align, .. } | General { align, .. } => align,
Array { align, .. } |
NullablePointer { align, .. } |
General { align, .. } => align,
UntaggedUnion(ref un) => un.align,
Univariant(ref variant) |
NullablePointer { nonnull: ref variant, .. } => {
variant.align
}
Univariant(ref variant) => variant.align
}
}
@ -1743,11 +1737,11 @@ impl<'a, 'tcx> Layout {
/// Returns alignment before repr alignment is applied
pub fn primitive_align<C: HasDataLayout>(&self, cx: C) -> Align {
match *self {
Array { primitive_align, .. } | General { primitive_align, .. } => primitive_align,
Univariant(ref variant) |
NullablePointer { nonnull: ref variant, .. } => {
variant.primitive_align
},
Array { primitive_align, .. } |
NullablePointer { primitive_align, .. } |
General { primitive_align, .. } => primitive_align,
Univariant(ref variant) => variant.primitive_align,
_ => self.align(cx.data_layout())
}
@ -1850,23 +1844,6 @@ impl<'a, 'tcx> Layout {
};
match *layout {
Layout::NullablePointer { nonnull: ref variant_layout,
nndiscr,
discr: _,
discr_offset: _ } => {
debug!("print-type-size t: `{:?}` adt nullable nndiscr {} is {:?}",
ty, nndiscr, variant_layout);
let variant_def = &adt_def.variants[nndiscr as usize];
let fields: Vec<_> =
variant_def.fields.iter()
.map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
.collect();
record(adt_kind.into(),
None,
vec![build_variant_info(Some(variant_def.name),
&fields,
variant_layout)]);
}
Layout::Univariant(ref variant_layout) => {
let variant_names = || {
adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
@ -1893,7 +1870,8 @@ impl<'a, 'tcx> Layout {
}
}
Layout::General { ref variants, discr, .. } => {
Layout::NullablePointer { ref variants, .. } |
Layout::General { ref variants, .. } => {
debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}",
ty, adt_def.variants.len(), variants.len(), variants);
let variant_infos: Vec<_> =
@ -1910,7 +1888,10 @@ impl<'a, 'tcx> Layout {
variant_layout)
})
.collect();
record(adt_kind.into(), Some(discr.size(tcx)), variant_infos);
record(adt_kind.into(), match *layout {
Layout::General { discr, .. } => Some(discr.size(tcx)),
_ => None
}, variant_infos);
}
Layout::UntaggedUnion(ref un) => {
@ -2215,19 +2196,13 @@ impl<'a, 'tcx> FullLayout<'tcx> {
}
}
NullablePointer { ref variants, .. } |
General { ref variants, .. } => {
FieldPlacement::Arbitrary {
offsets: &variants[variant_index].offsets
}
}
NullablePointer { nndiscr, ref nonnull, .. }
if nndiscr as usize == variant_index => {
FieldPlacement::Arbitrary {
offsets: &nonnull.offsets
}
}
_ => FieldPlacement::union(count)
};
@ -2390,14 +2365,20 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Layout
}
NullablePointer {
nndiscr,
ref nonnull,
ref variants,
ref discr,
discr_offset,
size,
align,
primitive_align
} => {
nndiscr.hash_stable(hcx, hasher);
nonnull.hash_stable(hcx, hasher);
variants.hash_stable(hcx, hasher);
discr.hash_stable(hcx, hasher);
discr_offset.hash_stable(hcx, hasher);
size.hash_stable(hcx, hasher);
align.hash_stable(hcx, hasher);
primitive_align.hash_stable(hcx, hasher);
}
}
}

View File

@ -68,28 +68,24 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>, llty: &mut Type) {
let l = cx.layout_of(t);
debug!("finish_type_of: {} with layout {:#?}", t, l);
if let layout::Abi::Scalar(_) = l.abi {
return;
}
match *l {
layout::General { .. } | layout::UntaggedUnion { .. } => { }
layout::Univariant { ..} | layout::NullablePointer { .. } => {
if let layout::Abi::Scalar(_) = l.abi {
return;
}
let (variant_layout, variant) = match *l {
layout::Univariant(ref variant) => {
let is_enum = if let ty::TyAdt(def, _) = t.sty {
def.is_enum()
} else {
false
};
if is_enum {
(l.for_variant(0), variant)
} else {
(l, variant)
}
}
layout::NullablePointer { nndiscr, ref nonnull, .. } =>
(l.for_variant(nndiscr as usize), nonnull),
_ => unreachable!()
layout::NullablePointer { .. } |
layout::General { .. } |
layout::UntaggedUnion { .. } => { }
layout::Univariant(ref variant) => {
let is_enum = if let ty::TyAdt(def, _) = t.sty {
def.is_enum()
} else {
false
};
let variant_layout = if is_enum {
l.for_variant(0)
} else {
l
};
llty.set_struct_body(&struct_llfields(cx, variant_layout, variant), variant.packed)
},
@ -106,18 +102,6 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
return cx.llvm_type_of(value.to_ty(cx.tcx()));
}
match *l {
layout::NullablePointer { nndiscr, ref nonnull, .. } => {
match name {
None => {
Type::struct_(cx, &struct_llfields(cx, l.for_variant(nndiscr as usize),
nonnull),
nonnull.packed)
}
Some(name) => {
Type::named_struct(cx, name)
}
}
}
layout::Univariant(ref variant) => {
match name {
None => {
@ -143,6 +127,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
}
}
layout::NullablePointer { size, align, .. } |
layout::General { size, align, .. } => {
let fill = union_fill(cx, size, align);
match name {

View File

@ -1218,11 +1218,13 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
}
}
layout::NullablePointer {
nonnull: ref struct_def,
nndiscr,
discr,
discr_offset
discr_offset,
ref variants,
..
} => {
let struct_def = &variants[nndiscr as usize];
// Create a description of the non-null variant
let (variant_type_metadata, member_description_factory) =
describe_enum_variant(cx,

View File

@ -1124,9 +1124,9 @@ fn trans_const_adt<'a, 'tcx>(
layout::Vector { .. } => {
Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t)
}
layout::NullablePointer { ref nonnull, nndiscr, .. } => {
layout::NullablePointer { ref variants, nndiscr, .. } => {
if variant_index as u64 == nndiscr {
build_const_struct(ccx, l, &nonnull, vals, None)
build_const_struct(ccx, l, &variants[variant_index], vals, None)
} else {
// Always use null even if it's not the `discrfield`th
// field; see #8506.

View File

@ -273,7 +273,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
// Check whether the variant being used is packed, if applicable.
let is_packed = match (&*l, l.variant_index) {
(&layout::Univariant(ref variant), _) => variant.packed,
(&layout::NullablePointer { ref nonnull, .. }, _) => nonnull.packed,
(&layout::NullablePointer { ref variants, .. }, Some(v)) |
(&layout::General { ref variants, .. }, Some(v)) => variants[v].packed,
_ => return simple()
};
@ -471,11 +471,15 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
// If this is an enum, cast to the appropriate variant struct type.
let layout = bcx.ccx.layout_of(ty).for_variant(variant_index);
if let layout::General { ref variants, .. } = *layout {
let st = &variants[variant_index];
let variant_ty = Type::struct_(bcx.ccx,
&adt::struct_llfields(bcx.ccx, layout, st), st.packed);
downcast.llval = bcx.pointercast(downcast.llval, variant_ty.ptr_to());
match *layout {
layout::NullablePointer { ref variants, .. } |
layout::General { ref variants, .. } => {
let st = &variants[variant_index];
let variant_ty = Type::struct_(bcx.ccx,
&adt::struct_llfields(bcx.ccx, layout, st), st.packed);
downcast.llval = bcx.pointercast(downcast.llval, variant_ty.ptr_to());
}
_ => {}
}
downcast

View File

@ -259,6 +259,7 @@ impl<'tcx> LayoutLlvmExt for FullLayout<'tcx> {
adt::memory_index_to_gep(variant.memory_index[index] as u64)
}
Layout::NullablePointer { ref variants, .. } |
Layout::General { ref variants, .. } => {
if let Some(v) = self.variant_index {
adt::memory_index_to_gep(variants[v].memory_index[index] as u64)
@ -266,14 +267,6 @@ impl<'tcx> LayoutLlvmExt for FullLayout<'tcx> {
bug!("FullLayout::llvm_field_index({:?}): not applicable", self)
}
}
Layout::NullablePointer { nndiscr, ref nonnull, .. } => {
if self.variant_index == Some(nndiscr as usize) {
adt::memory_index_to_gep(nonnull.memory_index[index] as u64)
} else {
bug!("FullLayout::llvm_field_index({:?}): not applicable", self)
}
}
}
}
}

View File

@ -4,9 +4,11 @@ print-type-size field `.post`: 2 bytes
print-type-size field `.pre`: 1 bytes
print-type-size end padding: 1 bytes
print-type-size type: `MyOption<IndirectNonZero<u32>>`: 12 bytes, alignment: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size variant `Some`: 12 bytes
print-type-size field `.0`: 12 bytes
print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size variant `Record`: 7 bytes
print-type-size field `.val`: 4 bytes
print-type-size field `.post`: 2 bytes
@ -18,6 +20,7 @@ print-type-size field `.post`: 2 bytes
print-type-size field `.pre`: 1 bytes
print-type-size end padding: 1 bytes
print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size type: `core::nonzero::NonZero<u32>`: 4 bytes, alignment: 4 bytes