Skip to content
Open
4 changes: 2 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3902,7 +3902,6 @@ dependencies = [
"rustc_mir_dataflow",
"rustc_session",
"rustc_span",
"rustc_target",
"rustc_trait_selection",
"tracing",
]
Expand Down Expand Up @@ -4670,7 +4669,6 @@ dependencies = [
"rustc_middle",
"rustc_session",
"rustc_span",
"rustc_target",
]

[[package]]
Expand Down Expand Up @@ -4813,6 +4811,7 @@ version = "0.0.0"
dependencies = [
"arrayvec",
"bitflags",
"derive-where",
"object 0.37.3",
"rustc_abi",
"rustc_data_structures",
Expand All @@ -4821,6 +4820,7 @@ dependencies = [
"rustc_macros",
"rustc_serialize",
"rustc_span",
"rustc_type_ir",
"schemars",
"serde",
"serde_derive",
Expand Down
148 changes: 1 addition & 147 deletions compiler/rustc_abi/src/callconv.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
#[cfg(feature = "nightly")]
use crate::{BackendRepr, FieldsShape, Primitive, Size, TyAbiInterface, TyAndLayout, Variants};

mod reg;

pub use reg::{Reg, RegKind};
Expand Down Expand Up @@ -35,8 +32,7 @@ impl HomogeneousAggregate {
/// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in
/// the same `struct`. Only succeeds if only one of them has any data,
/// or both units are identical.
#[cfg(feature = "nightly")]
fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
pub fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
match (self, other) {
(x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),

Expand All @@ -49,145 +45,3 @@ impl HomogeneousAggregate {
}
}
}

#[cfg(feature = "nightly")]
impl<'a, Ty> TyAndLayout<'a, Ty> {
/// Returns `Homogeneous` if this layout is an aggregate containing fields of
/// only a single type (e.g., `(u32, u32)`). Such aggregates are often
/// special-cased in ABIs.
///
/// Note: We generally ignore 1-ZST fields when computing this value (see #56877).
///
/// This is public so that it can be used in unit tests, but
/// should generally only be relevant to the ABI details of
/// specific targets.
#[tracing::instrument(skip(cx), level = "debug")]
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this becomes a free function in rustc_target::callconv

where
Ty: TyAbiInterface<'a, C> + Copy,
{
match self.backend_repr {
// The primitive for this algorithm.
BackendRepr::Scalar(scalar) => {
let kind = match scalar.primitive() {
Primitive::Int(..) | Primitive::Pointer(_) => RegKind::Integer,
Primitive::Float(_) => RegKind::Float,
};
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
}

BackendRepr::SimdVector { element, count: _ } => {
assert!(!self.is_zst());

Ok(HomogeneousAggregate::Homogeneous(Reg {
kind: RegKind::Vector { hint_vector_elem: element.primitive() },
size: self.size,
}))
}

BackendRepr::SimdScalableVector { .. } => {
unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")
}

BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
// Helper for computing `homogeneous_aggregate`, allowing a custom
// starting offset (used below for handling variants).
let from_fields_at =
|layout: Self,
start: Size|
-> Result<(HomogeneousAggregate, Size), Heterogeneous> {
let is_union = match layout.fields {
FieldsShape::Primitive => {
unreachable!("aggregates can't have `FieldsShape::Primitive`")
}
FieldsShape::Array { count, .. } => {
assert_eq!(start, Size::ZERO);

let result = if count > 0 {
layout.field(cx, 0).homogeneous_aggregate(cx)?
} else {
HomogeneousAggregate::NoData
};
return Ok((result, layout.size));
}
FieldsShape::Union(_) => true,
FieldsShape::Arbitrary { .. } => false,
};

let mut result = HomogeneousAggregate::NoData;
let mut total = start;

for i in 0..layout.fields.count() {
let field = layout.field(cx, i);
if field.is_1zst() {
// No data here and no impact on layout, can be ignored.
// (We might be able to also ignore all aligned ZST but that's less clear.)
continue;
}

if !is_union && total != layout.fields.offset(i) {
// This field isn't just after the previous one we considered, abort.
return Err(Heterogeneous);
}

result = result.merge(field.homogeneous_aggregate(cx)?)?;

// Keep track of the offset (without padding).
let size = field.size;
if is_union {
total = total.max(size);
} else {
total += size;
}
}

Ok((result, total))
};

let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;

match &self.variants {
Variants::Single { .. } | Variants::Empty => {}
Variants::Multiple { variants, .. } => {
// Treat enum variants like union members.
// HACK(eddyb) pretend the `enum` field (discriminant)
// is at the start of every variant (otherwise the gap
// at the start of all variants would disqualify them).
//
// NB: for all tagged `enum`s (which include all non-C-like
// `enum`s with defined FFI representation), this will
// match the homogeneous computation on the equivalent
// `struct { tag; union { variant1; ... } }` and/or
// `union { struct { tag; variant1; } ... }`
// (the offsets of variant fields should be identical
// between the two for either to be a homogeneous aggregate).
let variant_start = total;
for variant_idx in variants.indices() {
let (variant_result, variant_total) =
from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;

result = result.merge(variant_result)?;
total = total.max(variant_total);
}
}
}

// There needs to be no padding.
if total != self.size {
Err(Heterogeneous)
} else {
match result {
HomogeneousAggregate::Homogeneous(_) => {
assert_ne!(total, Size::ZERO);
}
HomogeneousAggregate::NoData => {
assert_eq!(total, Size::ZERO);
}
}
Ok(result)
}
}
BackendRepr::Memory { sized: false } => Err(Heterogeneous),
}
}
}
34 changes: 10 additions & 24 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ use crate::{
mod coroutine;
mod simple;

#[cfg(feature = "nightly")]
mod ty;

#[cfg(feature = "nightly")]
pub use ty::{Layout, TyAbiInterface, TyAndLayout};

rustc_index::newtype_index! {
/// The *source-order* index of a field in a variant.
///
Expand Down Expand Up @@ -86,11 +80,11 @@ rustc_index::newtype_index! {
// but *not* an encoding of the discriminant (e.g., a tag value).
// See issue #49298 for more details on the need to leave space
// for non-ZST uninhabited data (mostly partial initialization).
fn absent<'a, FieldIdx, VariantIdx, F>(fields: &IndexSlice<FieldIdx, F>) -> bool
fn absent<FieldIdx, VariantIdx, F>(fields: &IndexSlice<FieldIdx, F>) -> bool
where
FieldIdx: Idx,
VariantIdx: Idx,
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
F: Deref<Target = LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
{
let uninhabited = fields.iter().any(|f| f.is_uninhabited());
// We cannot ignore alignment; that might lead us to entirely discard a variant and
Expand Down Expand Up @@ -240,8 +234,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
/// This uses dedicated code instead of [`Self::layout_of_struct_or_enum`], as coroutine
/// fields may be shared between multiple variants (see the [`coroutine`] module for details).
pub fn coroutine<
'a,
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
F: Deref<Target = LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
VariantIdx: Idx,
FieldIdx: Idx,
LocalIdx: Idx,
Expand All @@ -264,10 +257,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}

pub fn univariant<
'a,
FieldIdx: Idx,
VariantIdx: Idx,
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
F: Deref<Target = LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
>(
&self,
fields: &IndexSlice<FieldIdx, F>,
Expand Down Expand Up @@ -339,10 +331,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}

pub fn layout_of_struct_or_enum<
'a,
FieldIdx: Idx,
VariantIdx: Idx,
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
F: Deref<Target = LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
>(
&self,
repr: &ReprOptions,
Expand Down Expand Up @@ -393,10 +384,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}

pub fn layout_of_union<
'a,
FieldIdx: Idx,
VariantIdx: Idx,
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
F: Deref<Target = LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
>(
&self,
repr: &ReprOptions,
Expand Down Expand Up @@ -519,10 +509,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {

/// single-variant enums are just structs, if you think about it
fn layout_of_struct<
'a,
FieldIdx: Idx,
VariantIdx: Idx,
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
F: Deref<Target = LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
>(
&self,
repr: &ReprOptions,
Expand Down Expand Up @@ -572,10 +561,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}

fn layout_of_enum<
'a,
FieldIdx: Idx,
VariantIdx: Idx,
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
F: Deref<Target = LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
>(
&self,
repr: &ReprOptions,
Expand Down Expand Up @@ -1092,10 +1080,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}

fn univariant_biased<
'a,
FieldIdx: Idx,
VariantIdx: Idx,
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
F: Deref<Target = LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
>(
&self,
fields: &IndexSlice<FieldIdx, F>,
Expand Down Expand Up @@ -1433,10 +1420,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}

fn format_field_niches<
'a,
FieldIdx: Idx,
VariantIdx: Idx,
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
F: Deref<Target = LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
>(
&self,
layout: &LayoutData<FieldIdx, VariantIdx>,
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_abi/src/layout/coroutine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ fn coroutine_saved_local_eligibility<VariantIdx: Idx, FieldIdx: Idx, LocalIdx: I

/// Compute the full coroutine layout.
pub(super) fn layout<
'a,
F: core::ops::Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + core::fmt::Debug + Copy,
F: core::ops::Deref<Target = LayoutData<FieldIdx, VariantIdx>> + core::fmt::Debug + Copy,
VariantIdx: Idx,
FieldIdx: Idx,
LocalIdx: Idx,
Expand Down
Loading
Loading