Minor comment and whitespace tweaks.
This commit is contained in:
parent
2ba4eb2d49
commit
86ecfdd605
2 changed files with 53 additions and 51 deletions
|
@ -53,24 +53,24 @@ pub trait LayoutCalculator {
|
||||||
kind: StructKind,
|
kind: StructKind,
|
||||||
) -> Option<LayoutS> {
|
) -> Option<LayoutS> {
|
||||||
let layout = univariant(self, dl, fields, repr, kind, NicheBias::Start);
|
let layout = univariant(self, dl, fields, repr, kind, NicheBias::Start);
|
||||||
// Enums prefer niches close to the beginning or the end of the variants so that other (smaller)
|
// Enums prefer niches close to the beginning or the end of the variants so that other
|
||||||
// data-carrying variants can be packed into the space after/before the niche.
|
// (smaller) data-carrying variants can be packed into the space after/before the niche.
|
||||||
// If the default field ordering does not give us a niche at the front then we do a second
|
// If the default field ordering does not give us a niche at the front then we do a second
|
||||||
// run and bias niches to the right and then check which one is closer to one of the struct's
|
// run and bias niches to the right and then check which one is closer to one of the
|
||||||
// edges.
|
// struct's edges.
|
||||||
if let Some(layout) = &layout {
|
if let Some(layout) = &layout {
|
||||||
// Don't try to calculate an end-biased layout for unsizable structs,
|
// Don't try to calculate an end-biased layout for unsizable structs,
|
||||||
// otherwise we could end up with different layouts for
|
// otherwise we could end up with different layouts for
|
||||||
// Foo<Type> and Foo<dyn Trait> which would break unsizing
|
// Foo<Type> and Foo<dyn Trait> which would break unsizing.
|
||||||
if !matches!(kind, StructKind::MaybeUnsized) {
|
if !matches!(kind, StructKind::MaybeUnsized) {
|
||||||
if let Some(niche) = layout.largest_niche {
|
if let Some(niche) = layout.largest_niche {
|
||||||
let head_space = niche.offset.bytes();
|
let head_space = niche.offset.bytes();
|
||||||
let niche_length = niche.value.size(dl).bytes();
|
let niche_length = niche.value.size(dl).bytes();
|
||||||
let tail_space = layout.size.bytes() - head_space - niche_length;
|
let tail_space = layout.size.bytes() - head_space - niche_length;
|
||||||
|
|
||||||
// This may end up doing redundant work if the niche is already in the last field
|
// This may end up doing redundant work if the niche is already in the last
|
||||||
// (e.g. a trailing bool) and there is tail padding. But it's non-trivial to get
|
// field (e.g. a trailing bool) and there is tail padding. But it's non-trivial
|
||||||
// the unpadded size so we try anyway.
|
// to get the unpadded size so we try anyway.
|
||||||
if fields.len() > 1 && head_space != 0 && tail_space > 0 {
|
if fields.len() > 1 && head_space != 0 && tail_space > 0 {
|
||||||
let alt_layout = univariant(self, dl, fields, repr, kind, NicheBias::End)
|
let alt_layout = univariant(self, dl, fields, repr, kind, NicheBias::End)
|
||||||
.expect("alt layout should always work");
|
.expect("alt layout should always work");
|
||||||
|
@ -684,7 +684,8 @@ pub trait LayoutCalculator {
|
||||||
// Also do not overwrite any already existing "clever" ABIs.
|
// Also do not overwrite any already existing "clever" ABIs.
|
||||||
if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) {
|
if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) {
|
||||||
variant.abi = abi;
|
variant.abi = abi;
|
||||||
// Also need to bump up the size and alignment, so that the entire value fits in here.
|
// Also need to bump up the size and alignment, so that the entire value fits
|
||||||
|
// in here.
|
||||||
variant.size = cmp::max(variant.size, size);
|
variant.size = cmp::max(variant.size, size);
|
||||||
variant.align.abi = cmp::max(variant.align.abi, align.abi);
|
variant.align.abi = cmp::max(variant.align.abi, align.abi);
|
||||||
}
|
}
|
||||||
|
@ -868,15 +869,15 @@ fn univariant(
|
||||||
|
|
||||||
// If `-Z randomize-layout` was enabled for the type definition we can shuffle
|
// If `-Z randomize-layout` was enabled for the type definition we can shuffle
|
||||||
// the field ordering to try and catch some code making assumptions about layouts
|
// the field ordering to try and catch some code making assumptions about layouts
|
||||||
// we don't guarantee
|
// we don't guarantee.
|
||||||
if repr.can_randomize_type_layout() && cfg!(feature = "randomize") {
|
if repr.can_randomize_type_layout() && cfg!(feature = "randomize") {
|
||||||
#[cfg(feature = "randomize")]
|
#[cfg(feature = "randomize")]
|
||||||
{
|
{
|
||||||
// `ReprOptions.layout_seed` is a deterministic seed that we can use to
|
// `ReprOptions.layout_seed` is a deterministic seed we can use to randomize field
|
||||||
// randomize field ordering with
|
// ordering.
|
||||||
let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed.as_u64());
|
let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed.as_u64());
|
||||||
|
|
||||||
// Shuffle the ordering of the fields
|
// Shuffle the ordering of the fields.
|
||||||
optimizing.shuffle(&mut rng);
|
optimizing.shuffle(&mut rng);
|
||||||
}
|
}
|
||||||
// Otherwise we just leave things alone and actually optimize the type's fields
|
// Otherwise we just leave things alone and actually optimize the type's fields
|
||||||
|
@ -892,27 +893,26 @@ fn univariant(
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
// Calculates a sort key to group fields by their alignment or possibly some size-derived
|
// Calculates a sort key to group fields by their alignment or possibly some
|
||||||
// pseudo-alignment.
|
// size-derived pseudo-alignment.
|
||||||
let alignment_group_key = |layout: Layout<'_>| {
|
let alignment_group_key = |layout: Layout<'_>| {
|
||||||
if let Some(pack) = pack {
|
if let Some(pack) = pack {
|
||||||
// return the packed alignment in bytes
|
// Return the packed alignment in bytes.
|
||||||
layout.align().abi.min(pack).bytes()
|
layout.align().abi.min(pack).bytes()
|
||||||
} else {
|
} else {
|
||||||
// returns log2(effective-align).
|
// Returns `log2(effective-align)`. This is ok since `pack` applies to all
|
||||||
// This is ok since `pack` applies to all fields equally.
|
// fields equally. The calculation assumes that size is an integer multiple of
|
||||||
// The calculation assumes that size is an integer multiple of align, except for ZSTs.
|
// align, except for ZSTs.
|
||||||
//
|
|
||||||
let align = layout.align().abi.bytes();
|
let align = layout.align().abi.bytes();
|
||||||
let size = layout.size().bytes();
|
let size = layout.size().bytes();
|
||||||
let niche_size = layout.largest_niche().map(|n| n.available(dl)).unwrap_or(0);
|
let niche_size = layout.largest_niche().map(|n| n.available(dl)).unwrap_or(0);
|
||||||
// group [u8; 4] with align-4 or [u8; 6] with align-2 fields
|
// Group [u8; 4] with align-4 or [u8; 6] with align-2 fields.
|
||||||
let size_as_align = align.max(size).trailing_zeros();
|
let size_as_align = align.max(size).trailing_zeros();
|
||||||
let size_as_align = if largest_niche_size > 0 {
|
let size_as_align = if largest_niche_size > 0 {
|
||||||
match niche_bias {
|
match niche_bias {
|
||||||
// Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the array
|
// Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the
|
||||||
// to the front in the first case (for aligned loads) but keep the bool in front
|
// array to the front in the first case (for aligned loads) but keep
|
||||||
// in the second case for its niches.
|
// the bool in front in the second case for its niches.
|
||||||
NicheBias::Start => max_field_align.trailing_zeros().min(size_as_align),
|
NicheBias::Start => max_field_align.trailing_zeros().min(size_as_align),
|
||||||
// When moving niches towards the end of the struct then for
|
// When moving niches towards the end of the struct then for
|
||||||
// A((u8, u8, u8, bool), (u8, bool, u8)) we want to keep the first tuple
|
// A((u8, u8, u8, bool), (u8, bool, u8)) we want to keep the first tuple
|
||||||
|
@ -931,14 +931,14 @@ fn univariant(
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
StructKind::AlwaysSized | StructKind::MaybeUnsized => {
|
StructKind::AlwaysSized | StructKind::MaybeUnsized => {
|
||||||
// Currently `LayoutS` only exposes a single niche so sorting is usually sufficient
|
// Currently `LayoutS` only exposes a single niche so sorting is usually
|
||||||
// to get one niche into the preferred position. If it ever supported multiple niches
|
// sufficient to get one niche into the preferred position. If it ever
|
||||||
// then a more advanced pick-and-pack approach could provide better results.
|
// supported multiple niches then a more advanced pick-and-pack approach could
|
||||||
// But even for the single-niche cache it's not optimal. E.g. for
|
// provide better results. But even for the single-niche cache it's not
|
||||||
// A(u32, (bool, u8), u16) it would be possible to move the bool to the front
|
// optimal. E.g. for A(u32, (bool, u8), u16) it would be possible to move the
|
||||||
// but it would require packing the tuple together with the u16 to build a 4-byte
|
// bool to the front but it would require packing the tuple together with the
|
||||||
// group so that the u32 can be placed after it without padding. This kind
|
// u16 to build a 4-byte group so that the u32 can be placed after it without
|
||||||
// of packing can't be achieved by sorting.
|
// padding. This kind of packing can't be achieved by sorting.
|
||||||
optimizing.sort_by_key(|&x| {
|
optimizing.sort_by_key(|&x| {
|
||||||
let f = fields[x];
|
let f = fields[x];
|
||||||
let field_size = f.size().bytes();
|
let field_size = f.size().bytes();
|
||||||
|
|
|
@ -53,10 +53,11 @@ bitflags! {
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||||
pub enum IntegerType {
|
pub enum IntegerType {
|
||||||
/// Pointer sized integer type, i.e. isize and usize. The field shows signedness, that
|
/// Pointer-sized integer type, i.e. `isize` and `usize`. The field shows signedness, e.g.
|
||||||
/// is, `Pointer(true)` is isize.
|
/// `Pointer(true)` means `isize`.
|
||||||
Pointer(bool),
|
Pointer(bool),
|
||||||
/// Fix sized integer type, e.g. i8, u32, i128 The bool field shows signedness, `Fixed(I8, false)` means `u8`
|
/// Fixed-sized integer type, e.g. `i8`, `u32`, `i128`. The bool field shows signedness, e.g.
|
||||||
|
/// `Fixed(I8, false)` means `u8`.
|
||||||
Fixed(Integer, bool),
|
Fixed(Integer, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ impl IntegerType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the repr options provided by the user,
|
/// Represents the repr options provided by the user.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||||
pub struct ReprOptions {
|
pub struct ReprOptions {
|
||||||
|
@ -139,7 +140,7 @@ impl ReprOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
|
/// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
|
||||||
/// was enabled for its declaration crate
|
/// was enabled for its declaration crate.
|
||||||
pub fn can_randomize_type_layout(&self) -> bool {
|
pub fn can_randomize_type_layout(&self) -> bool {
|
||||||
!self.inhibit_struct_field_reordering_opt()
|
!self.inhibit_struct_field_reordering_opt()
|
||||||
&& self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
|
&& self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
|
||||||
|
@ -217,7 +218,8 @@ pub enum TargetDataLayoutErrors<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TargetDataLayout {
|
impl TargetDataLayout {
|
||||||
/// Parse data layout from an [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
|
/// Parse data layout from an
|
||||||
|
/// [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
|
||||||
///
|
///
|
||||||
/// This function doesn't fill `c_enum_min_size` and it will always be `I32` since it can not be
|
/// This function doesn't fill `c_enum_min_size` and it will always be `I32` since it can not be
|
||||||
/// determined from llvm string.
|
/// determined from llvm string.
|
||||||
|
@ -747,7 +749,6 @@ impl Align {
|
||||||
/// A pair of alignments, ABI-mandated and preferred.
|
/// A pair of alignments, ABI-mandated and preferred.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
||||||
|
|
||||||
pub struct AbiAndPrefAlign {
|
pub struct AbiAndPrefAlign {
|
||||||
pub abi: Align,
|
pub abi: Align,
|
||||||
pub pref: Align,
|
pub pref: Align,
|
||||||
|
@ -773,7 +774,6 @@ impl AbiAndPrefAlign {
|
||||||
/// Integers, also used for enum discriminants.
|
/// Integers, also used for enum discriminants.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
|
||||||
|
|
||||||
pub enum Integer {
|
pub enum Integer {
|
||||||
I8,
|
I8,
|
||||||
I16,
|
I16,
|
||||||
|
@ -937,8 +937,7 @@ impl Primitive {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inclusive wrap-around range of valid values, that is, if
|
/// Inclusive wrap-around range of valid values, that is, if
|
||||||
/// start > end, it represents `start..=MAX`,
|
/// start > end, it represents `start..=MAX`, followed by `0..=end`.
|
||||||
/// followed by `0..=end`.
|
|
||||||
///
|
///
|
||||||
/// That is, for an i8 primitive, a range of `254..=2` means following
|
/// That is, for an i8 primitive, a range of `254..=2` means following
|
||||||
/// sequence:
|
/// sequence:
|
||||||
|
@ -1066,7 +1065,8 @@ impl Scalar {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Allows the caller to mutate the valid range. This operation will panic if attempted on a union.
|
/// Allows the caller to mutate the valid range. This operation will panic if attempted on a
|
||||||
|
/// union.
|
||||||
pub fn valid_range_mut(&mut self) -> &mut WrappingRange {
|
pub fn valid_range_mut(&mut self) -> &mut WrappingRange {
|
||||||
match self {
|
match self {
|
||||||
Scalar::Initialized { valid_range, .. } => valid_range,
|
Scalar::Initialized { valid_range, .. } => valid_range,
|
||||||
|
@ -1074,7 +1074,8 @@ impl Scalar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if all possible numbers are valid, i.e `valid_range` covers the whole layout
|
/// Returns `true` if all possible numbers are valid, i.e `valid_range` covers the whole
|
||||||
|
/// layout.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_always_valid<C: HasDataLayout>(&self, cx: &C) -> bool {
|
pub fn is_always_valid<C: HasDataLayout>(&self, cx: &C) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -1252,7 +1253,6 @@ impl AddressSpace {
|
||||||
/// in terms of categories of C types there are ABI rules for.
|
/// in terms of categories of C types there are ABI rules for.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
||||||
|
|
||||||
pub enum Abi {
|
pub enum Abi {
|
||||||
Uninhabited,
|
Uninhabited,
|
||||||
Scalar(Scalar),
|
Scalar(Scalar),
|
||||||
|
@ -1457,17 +1457,19 @@ impl Niche {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound.
|
// Extend the range of valid values being reserved by moving either `v.start` or `v.end`
|
||||||
// Given an eventual `Option<T>`, we try to maximize the chance for `None` to occupy the niche of zero.
|
// bound. Given an eventual `Option<T>`, we try to maximize the chance for `None` to occupy
|
||||||
// This is accomplished by preferring enums with 2 variants(`count==1`) and always taking the shortest path to niche zero.
|
// the niche of zero. This is accomplished by preferring enums with 2 variants(`count==1`)
|
||||||
// Having `None` in niche zero can enable some special optimizations.
|
// and always taking the shortest path to niche zero. Having `None` in niche zero can
|
||||||
|
// enable some special optimizations.
|
||||||
//
|
//
|
||||||
// Bound selection criteria:
|
// Bound selection criteria:
|
||||||
// 1. Select closest to zero given wrapping semantics.
|
// 1. Select closest to zero given wrapping semantics.
|
||||||
// 2. Avoid moving past zero if possible.
|
// 2. Avoid moving past zero if possible.
|
||||||
//
|
//
|
||||||
// In practice this means that enums with `count > 1` are unlikely to claim niche zero, since they have to fit perfectly.
|
// In practice this means that enums with `count > 1` are unlikely to claim niche zero,
|
||||||
// If niche zero is already reserved, the selection of bounds are of little interest.
|
// since they have to fit perfectly. If niche zero is already reserved, the selection of
|
||||||
|
// bounds are of little interest.
|
||||||
let move_start = |v: WrappingRange| {
|
let move_start = |v: WrappingRange| {
|
||||||
let start = v.start.wrapping_sub(count) & max_value;
|
let start = v.start.wrapping_sub(count) & max_value;
|
||||||
Some((start, Scalar::Initialized { value, valid_range: v.with_start(start) }))
|
Some((start, Scalar::Initialized { value, valid_range: v.with_start(start) }))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue