提交 5b7f4e9e 编写于 作者: E Eduard-Mihai Burtescu

rustc_target: factor out common fields of non-Single Variants.

上级 70a497a4
......@@ -913,11 +913,13 @@ enum StructKind {
}
return Ok(tcx.intern_layout(LayoutDetails {
variants: Variants::NicheFilling {
dataful_variant: i,
niche_variants,
niche: niche_scalar,
niche_start,
variants: Variants::Multiple {
discr: niche_scalar,
discr_kind: DiscriminantKind::Niche {
dataful_variant: i,
niche_variants,
niche_start,
},
variants: st,
},
fields: FieldPlacement::Arbitrary {
......@@ -1137,8 +1139,9 @@ enum StructKind {
}
tcx.intern_layout(LayoutDetails {
variants: Variants::Tagged {
tag,
variants: Variants::Multiple {
discr: tag,
discr_kind: DiscriminantKind::Tag,
variants: layout_variants,
},
fields: FieldPlacement::Arbitrary {
......@@ -1293,8 +1296,7 @@ fn record_layout_for_printing_outlined(&self, layout: TyLayout<'tcx>) {
}
}
Variants::NicheFilling { .. } |
Variants::Tagged { .. } => {
Variants::Multiple { ref discr, ref discr_kind, .. } => {
debug!("print-type-size `{:#?}` adt general variants def {}",
layout.ty, adt_def.variants.len());
let variant_infos: Vec<_> =
......@@ -1306,8 +1308,8 @@ fn record_layout_for_printing_outlined(&self, layout: TyLayout<'tcx>) {
layout.for_variant(self, i))
})
.collect();
record(adt_kind.into(), adt_packed, match layout.variants {
Variants::Tagged { ref tag, .. } => Some(tag.value.size(self)),
record(adt_kind.into(), adt_packed, match discr_kind {
DiscriminantKind::Tag => Some(discr.value.size(self)),
_ => None
}, variant_infos);
}
......@@ -1627,8 +1629,7 @@ fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLay
})
}
Variants::NicheFilling { ref variants, .. } |
Variants::Tagged { ref variants, .. } => {
Variants::Multiple { ref variants, .. } => {
&variants[variant_index]
}
};
......@@ -1735,8 +1736,7 @@ fn field(this: TyLayout<'tcx>, cx: &C, i: usize) -> C::TyLayout {
}
// Discriminant field for enums (where applicable).
Variants::Tagged { tag: ref discr, .. } |
Variants::NicheFilling { niche: ref discr, .. } => {
Variants::Multiple { ref discr, .. } => {
assert_eq!(i, 0);
let layout = LayoutDetails::scalar(cx, discr.clone());
return MaybeResult::from_ok(TyLayout {
......@@ -1881,26 +1881,37 @@ fn hash_stable<W: StableHasherResult>(&self,
Single { index } => {
index.hash_stable(hcx, hasher);
}
Tagged {
ref tag,
Multiple {
ref discr,
ref discr_kind,
ref variants,
} => {
tag.hash_stable(hcx, hasher);
discr.hash_stable(hcx, hasher);
discr_kind.hash_stable(hcx, hasher);
variants.hash_stable(hcx, hasher);
}
NicheFilling {
}
}
}
impl<'a> HashStable<StableHashingContext<'a>> for DiscriminantKind {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
use crate::ty::layout::DiscriminantKind::*;
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
Tag => {}
Niche {
dataful_variant,
ref niche_variants,
ref niche,
niche_start,
ref variants,
} => {
dataful_variant.hash_stable(hcx, hasher);
niche_variants.start().hash_stable(hcx, hasher);
niche_variants.end().hash_stable(hcx, hasher);
niche.hash_stable(hcx, hasher);
niche_start.hash_stable(hcx, hasher);
variants.hash_stable(hcx, hasher);
}
}
}
......
......@@ -1235,7 +1235,11 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
}
]
}
layout::Variants::Tagged { ref variants, .. } => {
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Tag,
ref variants,
..
} => {
let discriminant_info = if fallback {
RegularDiscriminant(self.discriminant_type_metadata
.expect(""))
......@@ -1277,12 +1281,14 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
}
}).collect()
}
layout::Variants::NicheFilling {
ref niche_variants,
niche_start,
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Niche {
ref niche_variants,
niche_start,
dataful_variant,
},
ref discr,
ref variants,
dataful_variant,
ref niche,
} => {
if fallback {
let variant = self.layout.for_variant(cx, dataful_variant);
......@@ -1369,7 +1375,11 @@ fn compute_field_path<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
let value = (i.as_u32() as u128)
.wrapping_sub(niche_variants.start().as_u32() as u128)
.wrapping_add(niche_start);
let value = truncate(value, niche.value.size(cx));
let value = truncate(value, discr.value.size(cx));
// NOTE(eddyb) do *NOT* remove this assert, until
// we pass the full 128-bit value to LLVM, otherwise
// truncation will be silent and remain undetected.
assert_eq!(value as u64 as u128, value);
Some(value as u64)
};
......@@ -1586,8 +1596,11 @@ fn prepare_enum_metadata(
let layout = cx.layout_of(enum_type);
match (&layout.abi, &layout.variants) {
(&layout::Abi::Scalar(_), &layout::Variants::Tagged {ref tag, .. }) =>
return FinalMetadata(discriminant_type_metadata(tag.value)),
(&layout::Abi::Scalar(_), &layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Tag,
ref discr,
..
}) => return FinalMetadata(discriminant_type_metadata(discr.value)),
_ => {}
}
......@@ -1599,9 +1612,16 @@ fn prepare_enum_metadata(
if use_enum_fallback(cx) {
let discriminant_type_metadata = match layout.variants {
layout::Variants::Single { .. } |
layout::Variants::NicheFilling { .. } => None,
layout::Variants::Tagged { ref tag, .. } => {
Some(discriminant_type_metadata(tag.value))
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Niche { .. },
..
} => None,
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Tag,
ref discr,
..
} => {
Some(discriminant_type_metadata(discr.value))
}
};
......@@ -1636,16 +1656,20 @@ fn prepare_enum_metadata(
);
}
let discriminator_metadata = match &layout.variants {
let discriminator_metadata = match layout.variants {
// A single-variant enum has no discriminant.
&layout::Variants::Single { .. } => None,
layout::Variants::Single { .. } => None,
&layout::Variants::NicheFilling { ref niche, .. } => {
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Niche { .. },
ref discr,
..
} => {
// Find the integer type of the correct size.
let size = niche.value.size(cx);
let align = niche.value.align(cx);
let size = discr.value.size(cx);
let align = discr.value.align(cx);
let discr_type = match niche.value {
let discr_type = match discr.value {
layout::Int(t, _) => t,
layout::Float(layout::FloatTy::F32) => Integer::I32,
layout::Float(layout::FloatTy::F64) => Integer::I64,
......@@ -1668,8 +1692,12 @@ fn prepare_enum_metadata(
}
},
&layout::Variants::Tagged { ref tag, .. } => {
let discr_type = tag.value.to_ty(cx.tcx);
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Tag,
ref discr,
..
} => {
let discr_type = discr.value.to_ty(cx.tcx);
let (size, align) = cx.size_and_align_of(discr_type);
let discr_metadata = basic_type_metadata(cx, discr_type);
......
......@@ -452,7 +452,13 @@ fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size)
_ => {
let mut data_variant = match self.variants {
layout::Variants::NicheFilling { dataful_variant, .. } => {
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Niche {
dataful_variant,
..
},
..
} => {
// Only the niche itself is always initialized,
// so only check for a pointer at its offset.
//
......
......@@ -216,37 +216,36 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
if self.layout.abi.is_uninhabited() {
return bx.cx().const_undef(cast_to);
}
match self.layout.variants {
let (discr_scalar, discr_kind) = match self.layout.variants {
layout::Variants::Single { index } => {
let discr_val = self.layout.ty.ty_adt_def().map_or(
index.as_u32() as u128,
|def| def.discriminant_for_variant(bx.cx().tcx(), index).val);
return bx.cx().const_uint_big(cast_to, discr_val);
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},
}
layout::Variants::Multiple { ref discr, ref discr_kind, .. } => {
(discr, discr_kind)
}
};
let discr = self.project_field(bx, 0);
let lldiscr = bx.load_operand(discr).immediate();
match self.layout.variants {
layout::Variants::Single { .. } => bug!(),
layout::Variants::Tagged { ref tag, .. } => {
let signed = match tag.value {
match *discr_kind {
layout::DiscriminantKind::Tag => {
let signed = match discr_scalar.value {
// We use `i1` for bytes that are always `0` or `1`,
// e.g., `#[repr(i8)] enum E { A, B }`, but we can't
// let LLVM interpret the `i1` as signed, because
// then `i1 1` (i.e., E::B) is effectively `i8 -1`.
layout::Int(_, signed) => !tag.is_bool() && signed,
layout::Int(_, signed) => !discr_scalar.is_bool() && signed,
_ => false
};
bx.intcast(lldiscr, cast_to, signed)
}
layout::Variants::NicheFilling {
layout::DiscriminantKind::Niche {
dataful_variant,
ref niche_variants,
niche_start,
..
} => {
let niche_llty = bx.cx().immediate_backend_type(discr.layout);
if niche_variants.start() == niche_variants.end() {
......@@ -291,7 +290,10 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
layout::Variants::Single { index } => {
assert_eq!(index, variant_index);
}
layout::Variants::Tagged { .. } => {
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Tag,
..
} => {
let ptr = self.project_field(bx, 0);
let to = self.layout.ty.ty_adt_def().unwrap()
.discriminant_for_variant(bx.tcx(), variant_index)
......@@ -301,10 +303,12 @@ pub fn codegen_set_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
ptr.llval,
ptr.align);
}
layout::Variants::NicheFilling {
dataful_variant,
ref niche_variants,
niche_start,
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Niche {
dataful_variant,
ref niche_variants,
niche_start,
},
..
} => {
if variant_index != dataful_variant {
......
......@@ -303,8 +303,7 @@ pub fn codegen_rvalue_operand(
});
}
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},
layout::Variants::Multiple { .. } => {},
}
let llval = operand.immediate();
......
......@@ -842,51 +842,56 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
let item_def_id = cx.tcx.hir().local_def_id_from_hir_id(it.hir_id);
let t = cx.tcx.type_of(item_def_id);
let ty = cx.tcx.erase_regions(&t);
match cx.layout_of(ty) {
Ok(layout) => {
let variants = &layout.variants;
if let layout::Variants::Tagged { ref variants, ref tag, .. } = variants {
let discr_size = tag.value.size(&cx.tcx).bytes();
debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
t, layout.size.bytes(), layout);
let (largest, slargest, largest_index) = enum_definition.variants
.iter()
.zip(variants)
.map(|(variant, variant_layout)| {
// Subtract the size of the enum discriminant.
let bytes = variant_layout.size.bytes().saturating_sub(discr_size);
debug!("- variant `{}` is {} bytes large",
variant.node.ident,
bytes);
bytes
})
.enumerate()
.fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l {
(size, l, idx)
} else if size > s {
(l, size, li)
} else {
(l, s, li)
});
// We only warn if the largest variant is at least thrice as large as
// the second-largest.
if largest > slargest * 3 && slargest > 0 {
cx.span_lint(VARIANT_SIZE_DIFFERENCES,
enum_definition.variants[largest_index].span,
&format!("enum variant is more than three times \
larger ({} bytes) than the next largest",
largest));
}
}
}
let layout = match cx.layout_of(ty) {
Ok(layout) => layout,
Err(ty::layout::LayoutError::Unknown(_)) => return,
Err(err @ ty::layout::LayoutError::SizeOverflow(_)) => {
bug!("failed to get layout for `{}`: {}", t, err);
}
};
let (variants, tag) = match layout.variants {
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Tag,
ref discr,
ref variants,
} => (variants, discr),
_ => return,
};
let discr_size = tag.value.size(&cx.tcx).bytes();
debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
t, layout.size.bytes(), layout);
let (largest, slargest, largest_index) = enum_definition.variants
.iter()
.zip(variants)
.map(|(variant, variant_layout)| {
// Subtract the size of the enum discriminant.
let bytes = variant_layout.size.bytes().saturating_sub(discr_size);
debug!("- variant `{}` is {} bytes large",
variant.node.ident,
bytes);
bytes
})
.enumerate()
.fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l {
(size, l, idx)
} else if size > s {
(l, size, li)
} else {
(l, s, li)
});
// We only warn if the largest variant is at least thrice as large as
// the second-largest.
if largest > slargest * 3 && slargest > 0 {
cx.span_lint(VARIANT_SIZE_DIFFERENCES,
enum_definition.variants[largest_index].span,
&format!("enum variant is more than three times \
larger ({} bytes) than the next largest",
largest));
}
}
}
......
......@@ -64,8 +64,7 @@ pub fn cast(
dest);
}
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},
layout::Variants::Multiple { .. } => {},
}
let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?;
......
......@@ -610,25 +610,24 @@ pub fn read_discriminant(
) -> EvalResult<'tcx, (u128, VariantIdx)> {
trace!("read_discriminant_value {:#?}", rval.layout);
match rval.layout.variants {
let discr_kind = match rval.layout.variants {
layout::Variants::Single { index } => {
let discr_val = rval.layout.ty.ty_adt_def().map_or(
index.as_u32() as u128,
|def| def.discriminant_for_variant(*self.tcx, index).val);
return Ok((discr_val, index));
}
layout::Variants::Tagged { .. } |
layout::Variants::NicheFilling { .. } => {},
}
layout::Variants::Multiple { ref discr_kind, .. } => discr_kind,
};
// read raw discriminant value
let discr_op = self.operand_field(rval, 0)?;
let discr_val = self.read_immediate(discr_op)?;
let raw_discr = discr_val.to_scalar_or_undef();
trace!("discr value: {:?}", raw_discr);
// post-process
Ok(match rval.layout.variants {
layout::Variants::Single { .. } => bug!(),
layout::Variants::Tagged { .. } => {
Ok(match *discr_kind {
layout::DiscriminantKind::Tag => {
let bits_discr = match raw_discr.to_bits(discr_val.layout.size) {
Ok(raw_discr) => raw_discr,
Err(_) => return err!(InvalidDiscriminant(raw_discr.erase_tag())),
......@@ -657,11 +656,10 @@ pub fn read_discriminant(
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant(raw_discr.erase_tag()))?;
(real_discr, index.0)
},
layout::Variants::NicheFilling {
layout::DiscriminantKind::Niche {
dataful_variant,
ref niche_variants,
niche_start,
..
} => {
let variants_start = niche_variants.start().as_u32() as u128;
let variants_end = niche_variants.end().as_u32() as u128;
......
......@@ -958,7 +958,11 @@ pub fn write_discriminant_index(
layout::Variants::Single { index } => {
assert_eq!(index, variant_index);
}
layout::Variants::Tagged { ref tag, .. } => {
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Tag,
ref discr,
..
} => {
let adt_def = dest.layout.ty.ty_adt_def().unwrap();
assert!(variant_index.as_usize() < adt_def.variants.len());
let discr_val = adt_def
......@@ -968,16 +972,18 @@ pub fn write_discriminant_index(
// raw discriminants for enums are isize or bigger during
// their computation, but the in-memory tag is the smallest possible
// representation
let size = tag.value.size(self);
let size = discr.value.size(self);
let discr_val = truncate(discr_val, size);
let discr_dest = self.place_field(dest, 0)?;
self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
}
layout::Variants::NicheFilling {
dataful_variant,
ref niche_variants,
niche_start,
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Niche {
dataful_variant,
ref niche_variants,
niche_start,
},
..
} => {
assert!(
......
......@@ -241,8 +241,7 @@ fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx>
// If this is a multi-variant layout, we have find the right one and proceed with
// that.
match v.layout().variants {
layout::Variants::NicheFilling { .. } |
layout::Variants::Tagged { .. } => {
layout::Variants::Multiple { .. } => {
let op = v.to_op(self.ecx())?;
let idx = self.ecx().read_discriminant(op)?.1;
let inner = v.project_downcast(self.ecx(), idx)?;
......
......@@ -61,8 +61,7 @@ fn classify<'a, Ty, C>(cx: &C, layout: TyLayout<'a, Ty>,
}
return Ok(());
}
abi::Variants::Tagged { .. } |
abi::Variants::NicheFilling { .. } => return Err(Memory),
abi::Variants::Multiple { .. } => return Err(Memory),
}
}
......
......@@ -828,15 +828,22 @@ pub enum Variants {
index: VariantIdx,
},
/// General-case enums: for each case there is a struct, and they all have
/// all space reserved for the tag, and their first field starts
/// at a non-0 offset, after where the tag would go.
Tagged {
tag: Scalar,
/// Enums with more than one inhabited variant: for each case there is
/// a struct, and they all have space reserved for the discriminant,
/// which is the sole field of the enum layout.
Multiple {
discr: Scalar,
discr_kind: DiscriminantKind,
variants: IndexVec<VariantIdx, LayoutDetails>,
},
}
#[derive(PartialEq, Eq, Hash, Debug)]
pub enum DiscriminantKind {
/// Integer tag holding the discriminant value itself.
Tag,
/// Multiple cases distinguished by a niche (values invalid for a type):
/// Niche (values invalid for a type) encoding the discriminant:
/// the variant `dataful_variant` contains a niche at an arbitrary
/// offset (field 0 of the enum), which for a variant with discriminant
/// `d` is set to `(d - niche_variants.start).wrapping_add(niche_start)`.
......@@ -844,13 +851,11 @@ pub enum Variants {
/// For example, `Option<(usize, &T)>` is represented such that
/// `None` has a null pointer for the second tuple field, and
/// `Some` is the identity function (with a non-null reference).
NicheFilling {
Niche {
dataful_variant: VariantIdx,
niche_variants: RangeInclusive<VariantIdx>,
niche: Scalar,
niche_start: u128,
variants: IndexVec<VariantIdx, LayoutDetails>,
}
},
}
#[derive(PartialEq, Eq, Hash, Debug)]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册