rustc: introduce layout::Abi for reduced general ABI "passing style".
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index e7e0d08..99dd73e 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1054,6 +1054,15 @@
}
}
+/// 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 @@
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 @@
}
}
};
+ 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 @@
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 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 @@
ty,
variant_index: None,
layout: cached.layout,
- fields: cached.fields
+ fields: cached.fields,
+ abi: cached.abi
})
}
}
@@ -2255,7 +2283,8 @@
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 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 1b4cbd6..8be2cb2 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -40,7 +40,7 @@
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 @@
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 @@
})
}
- 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;
}
@@ -356,57 +345,21 @@
}
// 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 @@
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 95470b0..2c3df8f 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -64,9 +64,8 @@
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 @@
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 40ddc32..b80fded 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -27,7 +27,7 @@
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_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
}
}