mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
compiler: Wire {TyAnd,}Layout
into rustc_abi
This finally unites TyAndLayout, Layout, and LayoutS into the same crate, as one might imagine they would be placed. No functional changes.
This commit is contained in:
parent
255bdd2f24
commit
10721909f2
254
compiler/rustc_abi/src/callconv.rs
Normal file
254
compiler/rustc_abi/src/callconv.rs
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
mod abi {
|
||||||
|
pub(crate) use crate::Primitive::*;
|
||||||
|
pub(crate) use crate::Variants;
|
||||||
|
}
|
||||||
|
|
||||||
|
use rustc_macros::HashStable_Generic;
|
||||||
|
|
||||||
|
use crate::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||||
|
pub enum RegKind {
|
||||||
|
Integer,
|
||||||
|
Float,
|
||||||
|
Vector,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||||
|
pub struct Reg {
|
||||||
|
pub kind: RegKind,
|
||||||
|
pub size: Size,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! reg_ctor {
|
||||||
|
($name:ident, $kind:ident, $bits:expr) => {
|
||||||
|
pub fn $name() -> Reg {
|
||||||
|
Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reg {
|
||||||
|
reg_ctor!(i8, Integer, 8);
|
||||||
|
reg_ctor!(i16, Integer, 16);
|
||||||
|
reg_ctor!(i32, Integer, 32);
|
||||||
|
reg_ctor!(i64, Integer, 64);
|
||||||
|
reg_ctor!(i128, Integer, 128);
|
||||||
|
|
||||||
|
reg_ctor!(f32, Float, 32);
|
||||||
|
reg_ctor!(f64, Float, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reg {
|
||||||
|
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
|
||||||
|
let dl = cx.data_layout();
|
||||||
|
match self.kind {
|
||||||
|
RegKind::Integer => match self.size.bits() {
|
||||||
|
1 => dl.i1_align.abi,
|
||||||
|
2..=8 => dl.i8_align.abi,
|
||||||
|
9..=16 => dl.i16_align.abi,
|
||||||
|
17..=32 => dl.i32_align.abi,
|
||||||
|
33..=64 => dl.i64_align.abi,
|
||||||
|
65..=128 => dl.i128_align.abi,
|
||||||
|
_ => panic!("unsupported integer: {self:?}"),
|
||||||
|
},
|
||||||
|
RegKind::Float => match self.size.bits() {
|
||||||
|
16 => dl.f16_align.abi,
|
||||||
|
32 => dl.f32_align.abi,
|
||||||
|
64 => dl.f64_align.abi,
|
||||||
|
128 => dl.f128_align.abi,
|
||||||
|
_ => panic!("unsupported float: {self:?}"),
|
||||||
|
},
|
||||||
|
RegKind::Vector => dl.vector_align(self.size).abi,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return value from the `homogeneous_aggregate` test function.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum HomogeneousAggregate {
|
||||||
|
/// Yes, all the "leaf fields" of this struct are passed in the
|
||||||
|
/// same way (specified in the `Reg` value).
|
||||||
|
Homogeneous(Reg),
|
||||||
|
|
||||||
|
/// There are no leaf fields at all.
|
||||||
|
NoData,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error from the `homogeneous_aggregate` test function, indicating
|
||||||
|
/// there are distinct leaf fields passed in different ways,
|
||||||
|
/// or this is uninhabited.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct Heterogeneous;
|
||||||
|
|
||||||
|
impl HomogeneousAggregate {
|
||||||
|
/// If this is a homogeneous aggregate, returns the homogeneous
|
||||||
|
/// unit, else `None`.
|
||||||
|
pub fn unit(self) -> Option<Reg> {
|
||||||
|
match self {
|
||||||
|
HomogeneousAggregate::Homogeneous(reg) => Some(reg),
|
||||||
|
HomogeneousAggregate::NoData => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
|
||||||
|
match (self, other) {
|
||||||
|
(x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
|
||||||
|
|
||||||
|
(HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {
|
||||||
|
if a != b {
|
||||||
|
return Err(Heterogeneous);
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
|
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
|
||||||
|
pub fn is_aggregate(&self) -> bool {
|
||||||
|
match self.abi {
|
||||||
|
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
|
||||||
|
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
|
||||||
|
where
|
||||||
|
Ty: TyAbiInterface<'a, C> + Copy,
|
||||||
|
{
|
||||||
|
match self.abi {
|
||||||
|
Abi::Uninhabited => Err(Heterogeneous),
|
||||||
|
|
||||||
|
// The primitive for this algorithm.
|
||||||
|
Abi::Scalar(scalar) => {
|
||||||
|
let kind = match scalar.primitive() {
|
||||||
|
abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
|
||||||
|
abi::Float(_) => RegKind::Float,
|
||||||
|
};
|
||||||
|
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
|
||||||
|
}
|
||||||
|
|
||||||
|
Abi::Vector { .. } => {
|
||||||
|
assert!(!self.is_zst());
|
||||||
|
Ok(HomogeneousAggregate::Homogeneous(Reg {
|
||||||
|
kind: RegKind::Vector,
|
||||||
|
size: self.size,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
Abi::ScalarPair(..) | Abi::Aggregate { 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 {
|
||||||
|
abi::Variants::Single { .. } => {}
|
||||||
|
abi::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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Abi::Aggregate { sized: false } => Err(Heterogeneous),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,10 @@ use crate::{
|
|||||||
Variants, WrappingRange,
|
Variants, WrappingRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod ty;
|
||||||
|
|
||||||
|
pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
|
||||||
|
|
||||||
// A variant is absent if it's uninhabited and only has ZST fields.
|
// A variant is absent if it's uninhabited and only has ZST fields.
|
||||||
// Present uninhabited variants only require space for their fields,
|
// Present uninhabited variants only require space for their fields,
|
||||||
// but *not* an encoding of the discriminant (e.g., a tag value).
|
// but *not* an encoding of the discriminant (e.g., a tag value).
|
||||||
|
@ -6,10 +6,8 @@ use Primitive::*;
|
|||||||
use rustc_data_structures::intern::Interned;
|
use rustc_data_structures::intern::Interned;
|
||||||
use rustc_macros::HashStable_Generic;
|
use rustc_macros::HashStable_Generic;
|
||||||
|
|
||||||
pub mod call;
|
|
||||||
|
|
||||||
// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
|
// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
|
||||||
pub use rustc_abi::{Float, *};
|
use crate::{Float, *};
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
/// The *source-order* index of a field in a variant.
|
/// The *source-order* index of a field in a variant.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||||
#![cfg_attr(feature = "nightly", doc(rust_logo))]
|
#![cfg_attr(feature = "nightly", doc(rust_logo))]
|
||||||
|
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
|
||||||
#![cfg_attr(feature = "nightly", feature(rustdoc_internals))]
|
#![cfg_attr(feature = "nightly", feature(rustdoc_internals))]
|
||||||
#![cfg_attr(feature = "nightly", feature(step_trait))]
|
#![cfg_attr(feature = "nightly", feature(step_trait))]
|
||||||
#![warn(unreachable_pub)]
|
#![warn(unreachable_pub)]
|
||||||
@ -22,11 +23,16 @@ use rustc_macros::HashStable_Generic;
|
|||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
use rustc_macros::{Decodable_Generic, Encodable_Generic};
|
use rustc_macros::{Decodable_Generic, Encodable_Generic};
|
||||||
|
|
||||||
|
mod callconv;
|
||||||
mod layout;
|
mod layout;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub use layout::{LayoutCalculator, LayoutCalculatorError};
|
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
|
||||||
|
pub use layout::{
|
||||||
|
FIRST_VARIANT, FieldIdx, Layout, LayoutCalculator, LayoutCalculatorError, TyAbiInterface,
|
||||||
|
TyAndLayout, VariantIdx,
|
||||||
|
};
|
||||||
|
|
||||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||||
|
@ -12,6 +12,7 @@ use std::marker::PhantomData;
|
|||||||
use std::ops::{Bound, Deref};
|
use std::ops::{Bound, Deref};
|
||||||
use std::{fmt, iter, mem};
|
use std::{fmt, iter, mem};
|
||||||
|
|
||||||
|
use rustc_abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
|
||||||
use rustc_ast::{self as ast, attr};
|
use rustc_ast::{self as ast, attr};
|
||||||
use rustc_data_structures::defer;
|
use rustc_data_structures::defer;
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
@ -48,7 +49,6 @@ use rustc_session::{Limit, MetadataKind, Session};
|
|||||||
use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
|
use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
|
||||||
use rustc_span::symbol::{Ident, Symbol, kw, sym};
|
use rustc_span::symbol::{Ident, Symbol, kw, sym};
|
||||||
use rustc_span::{DUMMY_SP, Span};
|
use rustc_span::{DUMMY_SP, Span};
|
||||||
use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
|
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use rustc_type_ir::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
use rustc_type_ir::fold::TypeFoldable;
|
use rustc_type_ir::fold::TypeFoldable;
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
pub use rustc_abi::{Reg, RegKind};
|
||||||
use rustc_macros::HashStable_Generic;
|
use rustc_macros::HashStable_Generic;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
|
|
||||||
use crate::abi::{self, Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
|
use crate::abi::{self, Abi, Align, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
|
||||||
use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
|
use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
|
||||||
|
|
||||||
mod aarch64;
|
mod aarch64;
|
||||||
@ -192,63 +193,6 @@ impl ArgAttributes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
|
||||||
pub enum RegKind {
|
|
||||||
Integer,
|
|
||||||
Float,
|
|
||||||
Vector,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
|
||||||
pub struct Reg {
|
|
||||||
pub kind: RegKind,
|
|
||||||
pub size: Size,
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! reg_ctor {
|
|
||||||
($name:ident, $kind:ident, $bits:expr) => {
|
|
||||||
pub fn $name() -> Reg {
|
|
||||||
Reg { kind: RegKind::$kind, size: Size::from_bits($bits) }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reg {
|
|
||||||
reg_ctor!(i8, Integer, 8);
|
|
||||||
reg_ctor!(i16, Integer, 16);
|
|
||||||
reg_ctor!(i32, Integer, 32);
|
|
||||||
reg_ctor!(i64, Integer, 64);
|
|
||||||
reg_ctor!(i128, Integer, 128);
|
|
||||||
|
|
||||||
reg_ctor!(f32, Float, 32);
|
|
||||||
reg_ctor!(f64, Float, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reg {
|
|
||||||
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
|
|
||||||
let dl = cx.data_layout();
|
|
||||||
match self.kind {
|
|
||||||
RegKind::Integer => match self.size.bits() {
|
|
||||||
1 => dl.i1_align.abi,
|
|
||||||
2..=8 => dl.i8_align.abi,
|
|
||||||
9..=16 => dl.i16_align.abi,
|
|
||||||
17..=32 => dl.i32_align.abi,
|
|
||||||
33..=64 => dl.i64_align.abi,
|
|
||||||
65..=128 => dl.i128_align.abi,
|
|
||||||
_ => panic!("unsupported integer: {self:?}"),
|
|
||||||
},
|
|
||||||
RegKind::Float => match self.size.bits() {
|
|
||||||
16 => dl.f16_align.abi,
|
|
||||||
32 => dl.f32_align.abi,
|
|
||||||
64 => dl.f64_align.abi,
|
|
||||||
128 => dl.f128_align.abi,
|
|
||||||
_ => panic!("unsupported float: {self:?}"),
|
|
||||||
},
|
|
||||||
RegKind::Vector => dl.vector_align(self.size).abi,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An argument passed entirely registers with the
|
/// An argument passed entirely registers with the
|
||||||
/// same kind (e.g., HFA / HVA on PPC64 and AArch64).
|
/// same kind (e.g., HFA / HVA on PPC64 and AArch64).
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||||
@ -380,195 +324,6 @@ impl CastTarget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return value from the `homogeneous_aggregate` test function.
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub enum HomogeneousAggregate {
|
|
||||||
/// Yes, all the "leaf fields" of this struct are passed in the
|
|
||||||
/// same way (specified in the `Reg` value).
|
|
||||||
Homogeneous(Reg),
|
|
||||||
|
|
||||||
/// There are no leaf fields at all.
|
|
||||||
NoData,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error from the `homogeneous_aggregate` test function, indicating
|
|
||||||
/// there are distinct leaf fields passed in different ways,
|
|
||||||
/// or this is uninhabited.
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct Heterogeneous;
|
|
||||||
|
|
||||||
impl HomogeneousAggregate {
|
|
||||||
/// If this is a homogeneous aggregate, returns the homogeneous
|
|
||||||
/// unit, else `None`.
|
|
||||||
pub fn unit(self) -> Option<Reg> {
|
|
||||||
match self {
|
|
||||||
HomogeneousAggregate::Homogeneous(reg) => Some(reg),
|
|
||||||
HomogeneousAggregate::NoData => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
|
||||||
fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
|
|
||||||
match (self, other) {
|
|
||||||
(x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
|
|
||||||
|
|
||||||
(HomogeneousAggregate::Homogeneous(a), HomogeneousAggregate::Homogeneous(b)) => {
|
|
||||||
if a != b {
|
|
||||||
return Err(Heterogeneous);
|
|
||||||
}
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|
||||||
/// Returns `true` if this is an aggregate type (including a ScalarPair!)
|
|
||||||
fn is_aggregate(&self) -> bool {
|
|
||||||
match self.abi {
|
|
||||||
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false,
|
|
||||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
|
||||||
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
|
|
||||||
where
|
|
||||||
Ty: TyAbiInterface<'a, C> + Copy,
|
|
||||||
{
|
|
||||||
match self.abi {
|
|
||||||
Abi::Uninhabited => Err(Heterogeneous),
|
|
||||||
|
|
||||||
// The primitive for this algorithm.
|
|
||||||
Abi::Scalar(scalar) => {
|
|
||||||
let kind = match scalar.primitive() {
|
|
||||||
abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
|
|
||||||
abi::Float(_) => RegKind::Float,
|
|
||||||
};
|
|
||||||
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
|
|
||||||
}
|
|
||||||
|
|
||||||
Abi::Vector { .. } => {
|
|
||||||
assert!(!self.is_zst());
|
|
||||||
Ok(HomogeneousAggregate::Homogeneous(Reg {
|
|
||||||
kind: RegKind::Vector,
|
|
||||||
size: self.size,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
Abi::ScalarPair(..) | Abi::Aggregate { 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 {
|
|
||||||
abi::Variants::Single { .. } => {}
|
|
||||||
abi::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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Abi::Aggregate { sized: false } => Err(Heterogeneous),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information about how to pass an argument to,
|
/// Information about how to pass an argument to,
|
||||||
/// or return a value from, a function, under some ABI.
|
/// or return a value from, a function, under some ABI.
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)]
|
#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub mod abi;
|
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
|
pub mod callconv;
|
||||||
pub mod json;
|
pub mod json;
|
||||||
pub mod spec;
|
pub mod spec;
|
||||||
pub mod target_features;
|
pub mod target_features;
|
||||||
@ -30,6 +30,15 @@ pub mod target_features;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
pub mod abi {
|
||||||
|
pub(crate) use Float::*;
|
||||||
|
pub(crate) use Primitive::*;
|
||||||
|
// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
|
||||||
|
pub use rustc_abi::{Float, *};
|
||||||
|
|
||||||
|
pub use crate::callconv as call;
|
||||||
|
}
|
||||||
|
|
||||||
pub use rustc_abi::HashStableContext;
|
pub use rustc_abi::HashStableContext;
|
||||||
|
|
||||||
/// The name of rustc's own place to organize libraries.
|
/// The name of rustc's own place to organize libraries.
|
||||||
|
Loading…
Reference in New Issue
Block a user