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