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.
|
/// 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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(())
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue