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. /// Type layout, from which size and alignment can be cheaply computed.
/// For ADTs, it also includes field placement and enum optimizations. /// For ADTs, it also includes field placement and enum optimizations.
/// NOTE: Because Layout is interned, redundant information should be /// 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 struct CachedLayout<'tcx> {
pub layout: &'tcx Layout, pub layout: &'tcx Layout,
pub fields: FieldPlacement<'tcx>, pub fields: FieldPlacement<'tcx>,
pub abi: Abi,
} }
fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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 { Ok(CachedLayout {
layout, layout,
fields fields,
abi
}) })
}; };
assert!(!ty.has_infer_types()); assert!(!ty.has_infer_types());
@ -1670,7 +1695,8 @@ impl<'a, 'tcx> Layout {
let layout = cx.layout_of(normalized)?; let layout = cx.layout_of(normalized)?;
return Ok(CachedLayout { return Ok(CachedLayout {
layout: layout.layout, layout: layout.layout,
fields: layout.fields fields: layout.fields,
abi: layout.abi
}); });
} }
ty::TyParam(_) => { ty::TyParam(_) => {
@ -2158,6 +2184,7 @@ pub struct FullLayout<'tcx> {
pub variant_index: Option<usize>, pub variant_index: Option<usize>,
pub layout: &'tcx Layout, pub layout: &'tcx Layout,
pub fields: FieldPlacement<'tcx>, pub fields: FieldPlacement<'tcx>,
pub abi: Abi,
} }
impl<'tcx> Deref for FullLayout<'tcx> { 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, ty,
variant_index: None, variant_index: None,
layout: cached.layout, 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, ty,
variant_index: None, variant_index: None,
layout: cached.layout, 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> { impl_stable_hash_for!(struct ::ty::layout::CachedLayout<'tcx> {
layout, layout,
fields fields,
abi
}); });
impl_stable_hash_for!(enum ::ty::layout::Integer { 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 rustc_back::PanicStrategy;
use libc::c_uint; use libc::c_uint;
use std::iter; use std::{cmp, iter};
pub use syntax::abi::Abi; pub use syntax::abi::Abi;
pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; 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> { impl<'tcx> LayoutExt<'tcx> for FullLayout<'tcx> {
fn is_aggregate(&self) -> bool { fn is_aggregate(&self) -> bool {
match *self.layout { match self.abi {
Layout::Scalar { .. } | layout::Abi::Scalar(_) |
Layout::RawNullablePointer { .. } | layout::Abi::Vector => false,
Layout::CEnum { .. } | layout::Abi::Aggregate => true
Layout::Vector { .. } => false,
Layout::Array { .. } |
Layout::FatPointer { .. } |
Layout::Univariant { .. } |
Layout::UntaggedUnion { .. } |
Layout::General { .. } |
Layout::StructWrappedNullablePointer { .. } => true
} }
} }
fn homogeneous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg> { fn homogeneous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option<Reg> {
match *self.layout { match self.abi {
// The primitives for this algorithm. // The primitive for this algorithm.
Layout::Scalar { value, .. } | layout::Abi::Scalar(value) => {
Layout::RawNullablePointer { discr: value, .. } => {
let kind = match value { let kind = match value {
layout::Int(_) | layout::Int(_) |
layout::Pointer => RegKind::Integer, layout::Pointer => RegKind::Integer,
@ -308,34 +299,32 @@ impl<'tcx> LayoutExt<'tcx> for FullLayout<'tcx> {
}) })
} }
Layout::CEnum { .. } => { layout::Abi::Vector => {
Some(Reg {
kind: RegKind::Integer,
size: self.size(ccx)
})
}
Layout::Vector { .. } => {
Some(Reg { Some(Reg {
kind: RegKind::Vector, kind: RegKind::Vector,
size: self.size(ccx) size: self.size(ccx)
}) })
} }
Layout::Array { count, .. } => { layout::Abi::Aggregate => {
if let Layout::Array { count, .. } = *self.layout {
if count > 0 { if count > 0 {
self.field(ccx, 0).homogeneous_aggregate(ccx) return self.field(ccx, 0).homogeneous_aggregate(ccx);
} else {
None
} }
} }
Layout::Univariant(ref variant) => { let mut total = Size::from_bytes(0);
let mut unaligned_offset = Size::from_bytes(0);
let mut result = None; 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() { for i in 0..self.fields.count() {
if unaligned_offset != variant.offsets[i] { if !is_union && total != self.fields.offset(i) {
return None; 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). // Keep track of the offset (without padding).
let size = field.size(ccx); let size = field.size(ccx);
if size > max { if is_union {
max = size; total = cmp::max(total, size);
} else {
total += size;
} }
} }
// There needs to be no padding. // There needs to be no padding.
if max != self.size(ccx) { if total != self.size(ccx) {
None None
} else { } else {
result 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 || if abi == Abi::Rust || abi == Abi::RustCall ||
abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
let fixup = |arg: &mut ArgType<'tcx>| { let fixup = |arg: &mut ArgType<'tcx>| {
if !arg.layout.is_aggregate() { match arg.layout.abi {
return; layout::Abi::Aggregate => {}
_ => return
} }
let size = arg.layout.size(ccx); 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(()); return Ok(());
} }
match *layout { match layout.abi {
Layout::Scalar { value, .. } | layout::Abi::Scalar(value) => {
Layout::RawNullablePointer { discr: value, .. } => {
let reg = match value { let reg = match value {
layout::Int(_) | layout::Int(_) |
layout::Pointer => Class::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); unify(cls, off, reg);
} }
Layout::CEnum { .. } => { layout::Abi::Vector => {
unify(cls, off, Class::Int);
}
Layout::Vector { element, count } => {
unify(cls, off, Class::Sse); unify(cls, off, Class::Sse);
// everything after the first one is the upper // everything after the first one is the upper
// half of a register. // half of a register.
let eltsz = element.size(ccx); let eltsz = layout.field(ccx, 0).size(ccx);
for i in 1..count { for i in 1..layout.fields.count() {
unify(cls, off + eltsz * i, Class::SseUp); unify(cls, off + eltsz * (i as u64), Class::SseUp);
} }
} }
Layout::Array { count, .. } => { layout::Abi::Aggregate => {
if count > 0 { // FIXME(eddyb) have to work around Rust enums for now.
let elt = layout.field(ccx, 0); // Fix is either guarantee no data where there is no field,
let eltsz = elt.size(ccx); // by putting variants in fields, or be more clever.
for i in 0..count { match *layout {
classify(ccx, elt, cls, off + eltsz * i)?; Layout::General { .. } |
Layout::StructWrappedNullablePointer { .. } => return Err(Memory),
_ => {}
} }
}
}
Layout::Univariant(ref variant) => {
for i in 0..layout.fields.count() { 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)?; 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(()) Ok(())

View file

@ -27,7 +27,7 @@ use type_::Type;
use value::Value; use value::Value;
use rustc::traits; use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt}; 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::ty::subst::{Kind, Subst, Substs};
use rustc::hir; 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 { pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
let layout = ccx.layout_of(ty); let layout = ccx.layout_of(ty);
match *layout { match layout.abi {
Layout::CEnum { .. } | layout::Abi::Scalar(_) | layout::Abi::Vector => true,
Layout::Scalar { .. } |
Layout::Vector { .. } => true,
Layout::FatPointer { .. } => false, layout::Abi::Aggregate => {
Layout::Array { .. } |
Layout::Univariant { .. } |
Layout::General { .. } |
Layout::UntaggedUnion { .. } |
Layout::RawNullablePointer { .. } |
Layout::StructWrappedNullablePointer { .. } => {
!layout.is_unsized() && layout.size(ccx).bytes() == 0 !layout.is_unsized() && layout.size(ccx).bytes() == 0
} }
} }