rustc: introduce layout::Abi for reduced general ABI "passing style".

This commit is contained in:
Eduard-Mihai Burtescu 2017-09-14 22:50:18 +03:00
parent 1dc572b85e
commit caef91d7c6
4 changed files with 104 additions and 126 deletions

View file

@ -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 {

View file

@ -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);

View file

@ -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(())

View file

@ -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
}
}