rustc: introduce layout::Abi for reduced general ABI "passing style".
This commit is contained in:
parent
1dc572b85e
commit
caef91d7c6
4 changed files with 104 additions and 126 deletions
|
@ -1054,6 +1054,15 @@ impl<'a> FieldPlacement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Describes how values of the type are passed by target ABIs,
|
||||
/// in terms of categories of C types there are ABI rules for.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Abi {
|
||||
Scalar(Primitive),
|
||||
Vector,
|
||||
Aggregate
|
||||
}
|
||||
|
||||
/// Type layout, from which size and alignment can be cheaply computed.
|
||||
/// For ADTs, it also includes field placement and enum optimizations.
|
||||
/// NOTE: Because Layout is interned, redundant information should be
|
||||
|
@ -1172,6 +1181,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
|
|||
pub struct CachedLayout<'tcx> {
|
||||
pub layout: &'tcx Layout,
|
||||
pub fields: FieldPlacement<'tcx>,
|
||||
pub abi: Abi,
|
||||
}
|
||||
|
||||
fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
@ -1258,9 +1268,24 @@ impl<'a, 'tcx> Layout {
|
|||
}
|
||||
}
|
||||
};
|
||||
let abi = match *layout {
|
||||
Scalar { value, .. } |
|
||||
RawNullablePointer { discr: value, .. } => Abi::Scalar(value),
|
||||
CEnum { discr, .. } => Abi::Scalar(Int(discr)),
|
||||
|
||||
Vector { .. } => Abi::Vector,
|
||||
|
||||
Array { .. } |
|
||||
FatPointer { .. } |
|
||||
Univariant(_) |
|
||||
UntaggedUnion(_) |
|
||||
General { .. } |
|
||||
StructWrappedNullablePointer { .. } => Abi::Aggregate
|
||||
};
|
||||
Ok(CachedLayout {
|
||||
layout,
|
||||
fields
|
||||
fields,
|
||||
abi
|
||||
})
|
||||
};
|
||||
assert!(!ty.has_infer_types());
|
||||
|
@ -1670,7 +1695,8 @@ impl<'a, 'tcx> Layout {
|
|||
let layout = cx.layout_of(normalized)?;
|
||||
return Ok(CachedLayout {
|
||||
layout: layout.layout,
|
||||
fields: layout.fields
|
||||
fields: layout.fields,
|
||||
abi: layout.abi
|
||||
});
|
||||
}
|
||||
ty::TyParam(_) => {
|
||||
|
@ -2158,6 +2184,7 @@ pub struct FullLayout<'tcx> {
|
|||
pub variant_index: Option<usize>,
|
||||
pub layout: &'tcx Layout,
|
||||
pub fields: FieldPlacement<'tcx>,
|
||||
pub abi: Abi,
|
||||
}
|
||||
|
||||
impl<'tcx> Deref for FullLayout<'tcx> {
|
||||
|
@ -2225,7 +2252,8 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx
|
|||
ty,
|
||||
variant_index: None,
|
||||
layout: cached.layout,
|
||||
fields: cached.fields
|
||||
fields: cached.fields,
|
||||
abi: cached.abi
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -2255,7 +2283,8 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
|
|||
ty,
|
||||
variant_index: None,
|
||||
layout: cached.layout,
|
||||
fields: cached.fields
|
||||
fields: cached.fields,
|
||||
abi: cached.abi
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -2492,9 +2521,29 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for FieldPlacement<'gcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'gcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use ty::layout::Abi::*;
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match *self {
|
||||
Scalar(value) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
Vector => {
|
||||
}
|
||||
Aggregate => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct ::ty::layout::CachedLayout<'tcx> {
|
||||
layout,
|
||||
fields
|
||||
fields,
|
||||
abi
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum ::ty::layout::Integer {
|
||||
|
|
|
@ -40,7 +40,7 @@ use rustc::ty::layout::{HasDataLayout, LayoutOf};
|
|||
use rustc_back::PanicStrategy;
|
||||
|
||||
use libc::c_uint;
|
||||
use std::iter;
|
||||
use std::{cmp, iter};
|
||||
|
||||
pub use syntax::abi::Abi;
|
||||
pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
|
||||
|
@ -276,26 +276,17 @@ pub trait LayoutExt<'tcx> {
|
|||
|
||||
impl<'tcx> LayoutExt<'tcx> for FullLayout<'tcx> {
|
||||
fn is_aggregate(&self) -> bool {
|
||||
match *self.layout {
|
||||
Layout::Scalar { .. } |
|
||||
Layout::RawNullablePointer { .. } |
|
||||
Layout::CEnum { .. } |
|
||||
Layout::Vector { .. } => false,
|
||||
|
||||
Layout::Array { .. } |
|
||||
Layout::FatPointer { .. } |
|
||||
Layout::Univariant { .. } |
|
||||
Layout::UntaggedUnion { .. } |
|
||||
Layout::General { .. } |
|
||||
Layout::StructWrappedNullablePointer { .. } => true
|
||||
match self.abi {
|
||||
layout::Abi::Scalar(_) |
|
||||
layout::Abi::Vector => false,
|
||||
layout::Abi::Aggregate => true
|
||||
}
|
||||
}
|
||||
|
||||
fn homogeneous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg> {
|
||||
match *self.layout {
|
||||
// The primitives for this algorithm.
|
||||
Layout::Scalar { value, .. } |
|
||||
Layout::RawNullablePointer { discr: value, .. } => {
|
||||
match self.abi {
|
||||
// The primitive for this algorithm.
|
||||
layout::Abi::Scalar(value) => {
|
||||
let kind = match value {
|
||||
layout::Int(_) |
|
||||
layout::Pointer => RegKind::Integer,
|
||||
|
@ -308,34 +299,32 @@ impl<'tcx> LayoutExt<'tcx> for FullLayout<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
Layout::CEnum { .. } => {
|
||||
Some(Reg {
|
||||
kind: RegKind::Integer,
|
||||
size: self.size(ccx)
|
||||
})
|
||||
}
|
||||
|
||||
Layout::Vector { .. } => {
|
||||
layout::Abi::Vector => {
|
||||
Some(Reg {
|
||||
kind: RegKind::Vector,
|
||||
size: self.size(ccx)
|
||||
})
|
||||
}
|
||||
|
||||
Layout::Array { count, .. } => {
|
||||
if count > 0 {
|
||||
self.field(ccx, 0).homogeneous_aggregate(ccx)
|
||||
} else {
|
||||
None
|
||||
layout::Abi::Aggregate => {
|
||||
if let Layout::Array { count, .. } = *self.layout {
|
||||
if count > 0 {
|
||||
return self.field(ccx, 0).homogeneous_aggregate(ccx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Layout::Univariant(ref variant) => {
|
||||
let mut unaligned_offset = Size::from_bytes(0);
|
||||
let mut total = Size::from_bytes(0);
|
||||
let mut result = None;
|
||||
|
||||
let is_union = match self.fields {
|
||||
layout::FieldPlacement::Linear { stride, .. } => {
|
||||
stride.bytes() == 0
|
||||
}
|
||||
layout::FieldPlacement::Arbitrary { .. } => false
|
||||
};
|
||||
|
||||
for i in 0..self.fields.count() {
|
||||
if unaligned_offset != variant.offsets[i] {
|
||||
if !is_union && total != self.fields.offset(i) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -355,58 +344,22 @@ impl<'tcx> LayoutExt<'tcx> for FullLayout<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Keep track of the offset (without padding).
|
||||
unaligned_offset += field.size(ccx);
|
||||
}
|
||||
|
||||
// There needs to be no padding.
|
||||
if unaligned_offset != self.size(ccx) {
|
||||
None
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
Layout::UntaggedUnion { .. } => {
|
||||
let mut max = Size::from_bytes(0);
|
||||
let mut result = None;
|
||||
|
||||
for i in 0..self.fields.count() {
|
||||
let field = self.field(ccx, i);
|
||||
match (result, field.homogeneous_aggregate(ccx)) {
|
||||
// The field itself must be a homogeneous aggregate.
|
||||
(_, None) => return None,
|
||||
// If this is the first field, record the unit.
|
||||
(None, Some(unit)) => {
|
||||
result = Some(unit);
|
||||
}
|
||||
// For all following fields, the unit must be the same.
|
||||
(Some(prev_unit), Some(unit)) => {
|
||||
if prev_unit != unit {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of the offset (without padding).
|
||||
let size = field.size(ccx);
|
||||
if size > max {
|
||||
max = size;
|
||||
if is_union {
|
||||
total = cmp::max(total, size);
|
||||
} else {
|
||||
total += size;
|
||||
}
|
||||
}
|
||||
|
||||
// There needs to be no padding.
|
||||
if max != self.size(ccx) {
|
||||
if total != self.size(ccx) {
|
||||
None
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
// Rust-specific types, which we can ignore for C ABIs.
|
||||
Layout::FatPointer { .. } |
|
||||
Layout::General { .. } |
|
||||
Layout::StructWrappedNullablePointer { .. } => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -870,8 +823,9 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
if abi == Abi::Rust || abi == Abi::RustCall ||
|
||||
abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
|
||||
let fixup = |arg: &mut ArgType<'tcx>| {
|
||||
if !arg.layout.is_aggregate() {
|
||||
return;
|
||||
match arg.layout.abi {
|
||||
layout::Abi::Aggregate => {}
|
||||
_ => return
|
||||
}
|
||||
|
||||
let size = arg.layout.size(ccx);
|
||||
|
|
|
@ -64,9 +64,8 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
match *layout {
|
||||
Layout::Scalar { value, .. } |
|
||||
Layout::RawNullablePointer { discr: value, .. } => {
|
||||
match layout.abi {
|
||||
layout::Abi::Scalar(value) => {
|
||||
let reg = match value {
|
||||
layout::Int(_) |
|
||||
layout::Pointer => Class::Int,
|
||||
|
@ -76,47 +75,32 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
|
|||
unify(cls, off, reg);
|
||||
}
|
||||
|
||||
Layout::CEnum { .. } => {
|
||||
unify(cls, off, Class::Int);
|
||||
}
|
||||
|
||||
Layout::Vector { element, count } => {
|
||||
layout::Abi::Vector => {
|
||||
unify(cls, off, Class::Sse);
|
||||
|
||||
// everything after the first one is the upper
|
||||
// half of a register.
|
||||
let eltsz = element.size(ccx);
|
||||
for i in 1..count {
|
||||
unify(cls, off + eltsz * i, Class::SseUp);
|
||||
let eltsz = layout.field(ccx, 0).size(ccx);
|
||||
for i in 1..layout.fields.count() {
|
||||
unify(cls, off + eltsz * (i as u64), Class::SseUp);
|
||||
}
|
||||
}
|
||||
|
||||
Layout::Array { count, .. } => {
|
||||
if count > 0 {
|
||||
let elt = layout.field(ccx, 0);
|
||||
let eltsz = elt.size(ccx);
|
||||
for i in 0..count {
|
||||
classify(ccx, elt, cls, off + eltsz * i)?;
|
||||
}
|
||||
layout::Abi::Aggregate => {
|
||||
// FIXME(eddyb) have to work around Rust enums for now.
|
||||
// Fix is either guarantee no data where there is no field,
|
||||
// by putting variants in fields, or be more clever.
|
||||
match *layout {
|
||||
Layout::General { .. } |
|
||||
Layout::StructWrappedNullablePointer { .. } => return Err(Memory),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Layout::Univariant(ref variant) => {
|
||||
for i in 0..layout.fields.count() {
|
||||
let field_off = off + variant.offsets[i];
|
||||
let field_off = off + layout.fields.offset(i);
|
||||
classify(ccx, layout.field(ccx, i), cls, field_off)?;
|
||||
}
|
||||
}
|
||||
|
||||
Layout::UntaggedUnion { .. } => {
|
||||
for i in 0..layout.fields.count() {
|
||||
classify(ccx, layout.field(ccx, i), cls, off)?;
|
||||
}
|
||||
}
|
||||
|
||||
Layout::FatPointer { .. } |
|
||||
Layout::General { .. } |
|
||||
Layout::StructWrappedNullablePointer { .. } => return Err(Memory)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -27,7 +27,7 @@ use type_::Type;
|
|||
use value::Value;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::layout::{HasDataLayout, Layout, LayoutOf};
|
||||
use rustc::ty::layout::{self, HasDataLayout, Layout, LayoutOf};
|
||||
use rustc::ty::subst::{Kind, Subst, Substs};
|
||||
use rustc::hir;
|
||||
|
||||
|
@ -50,19 +50,10 @@ pub fn type_is_fat_ptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) ->
|
|||
|
||||
pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
let layout = ccx.layout_of(ty);
|
||||
match *layout {
|
||||
Layout::CEnum { .. } |
|
||||
Layout::Scalar { .. } |
|
||||
Layout::Vector { .. } => true,
|
||||
match layout.abi {
|
||||
layout::Abi::Scalar(_) | layout::Abi::Vector => true,
|
||||
|
||||
Layout::FatPointer { .. } => false,
|
||||
|
||||
Layout::Array { .. } |
|
||||
Layout::Univariant { .. } |
|
||||
Layout::General { .. } |
|
||||
Layout::UntaggedUnion { .. } |
|
||||
Layout::RawNullablePointer { .. } |
|
||||
Layout::StructWrappedNullablePointer { .. } => {
|
||||
layout::Abi::Aggregate => {
|
||||
!layout.is_unsized() && layout.size(ccx).bytes() == 0
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue