diff options
| author | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-09-14 22:50:18 +0300 |
|---|---|---|
| committer | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-11-19 02:14:30 +0200 |
| commit | caef91d7c6dcfc307b9e915bd9a80a25063cce22 (patch) | |
| tree | 16402f874177b9d462263c3e68dea2be288023c4 | |
| parent | 1dc572b85e1f7bc245fb31ba659c822d68fda0bc (diff) | |
| download | rust-caef91d7c6dcfc307b9e915bd9a80a25063cce22.tar.gz rust-caef91d7c6dcfc307b9e915bd9a80a25063cce22.zip | |
rustc: introduce layout::Abi for reduced general ABI "passing style".
| -rw-r--r-- | src/librustc/ty/layout.rs | 59 | ||||
| -rw-r--r-- | src/librustc_trans/abi.rs | 108 | ||||
| -rw-r--r-- | src/librustc_trans/cabi_x86_64.rs | 46 | ||||
| -rw-r--r-- | src/librustc_trans/common.rs | 19 |
4 files changed, 105 insertions, 127 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index e7e0d08b69c..99dd73e03c7 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -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 { diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 1b4cbd687df..8be2cb2a1d3 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -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,70 +299,35 @@ 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; - for i in 0..self.fields.count() { - if unaligned_offset != variant.offsets[i] { - return None; + let is_union = match self.fields { + layout::FieldPlacement::Linear { stride, .. } => { + stride.bytes() == 0 } + layout::FieldPlacement::Arbitrary { .. } => false + }; - 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; - } - } + for i in 0..self.fields.count() { + if !is_union && total != self.fields.offset(i) { + return None; } - // 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. @@ -390,23 +346,20 @@ impl<'tcx> LayoutExt<'tcx> for FullLayout<'tcx> { // 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); diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 95470b07564..2c3df8f02e6 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -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(()) diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 40ddc329ddd..b80fded638d 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -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, - - Layout::FatPointer { .. } => false, - - Layout::Array { .. } | - Layout::Univariant { .. } | - Layout::General { .. } | - Layout::UntaggedUnion { .. } | - Layout::RawNullablePointer { .. } | - Layout::StructWrappedNullablePointer { .. } => { + match layout.abi { + layout::Abi::Scalar(_) | layout::Abi::Vector => true, + + layout::Abi::Aggregate => { !layout.is_unsized() && layout.size(ccx).bytes() == 0 } } |
