about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/ty/layout.rs42
-rw-r--r--src/librustc_trans/abi.rs4
-rw-r--r--src/librustc_trans/cabi_x86_64.rs7
-rw-r--r--src/librustc_trans/cabi_x86_win64.rs2
-rw-r--r--src/librustc_trans/mir/constant.rs29
-rw-r--r--src/librustc_trans/mir/operand.rs4
-rw-r--r--src/librustc_trans/type_of.rs97
7 files changed, 98 insertions, 87 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index b2ed34cb913..9ae647c97d2 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -758,7 +758,10 @@ pub enum Abi {
     Uninhabited,
     Scalar(Scalar),
     ScalarPair(Scalar, Scalar),
-    Vector,
+    Vector {
+        element: Scalar,
+        count: u64
+    },
     Aggregate {
         /// If true, the size is exact, otherwise it's only a lower bound.
         sized: bool,
@@ -773,7 +776,7 @@ impl Abi {
             Abi::Uninhabited |
             Abi::Scalar(_) |
             Abi::ScalarPair(..) |
-            Abi::Vector => false,
+            Abi::Vector { .. } => false,
             Abi::Aggregate { sized, .. } => !sized
         }
     }
@@ -784,7 +787,7 @@ impl Abi {
             Abi::Uninhabited |
             Abi::Scalar(_) |
             Abi::ScalarPair(..) |
-            Abi::Vector => false,
+            Abi::Vector { .. } => false,
             Abi::Aggregate { packed, .. } => packed
         }
     }
@@ -1083,9 +1086,9 @@ impl<'a, 'tcx> LayoutDetails {
                                align.abi() == field.align.abi() &&
                                size == field.size {
                                 match field.abi {
-                                    // For plain scalars we can't unpack newtypes
-                                    // for `#[repr(C)]`, as that affects C ABIs.
-                                    Abi::Scalar(_) if optimize => {
+                                    // For plain scalars, or vectors of them, we can't unpack
+                                    // newtypes for `#[repr(C)]`, as that affects C ABIs.
+                                    Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
                                         abi = field.abi.clone();
                                     }
                                     // But scalar pairs are Rust-specific and get
@@ -1320,16 +1323,17 @@ impl<'a, 'tcx> LayoutDetails {
 
             // SIMD vector types.
             ty::TyAdt(def, ..) if def.repr.simd() => {
-                let count = ty.simd_size(tcx) as u64;
                 let element = cx.layout_of(ty.simd_type(tcx))?;
-                match element.abi {
-                    Abi::Scalar(_) => {}
+                let count = ty.simd_size(tcx) as u64;
+                assert!(count > 0);
+                let scalar = match element.abi {
+                    Abi::Scalar(ref scalar) => scalar.clone(),
                     _ => {
                         tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \
                                                 a non-machine element type `{}`",
                                                 ty, element.ty));
                     }
-                }
+                };
                 let size = element.size.checked_mul(count, dl)
                     .ok_or(LayoutError::SizeOverflow(ty))?;
                 let align = dl.vector_align(size);
@@ -1341,7 +1345,10 @@ impl<'a, 'tcx> LayoutDetails {
                         stride: element.size,
                         count
                     },
-                    abi: Abi::Vector,
+                    abi: Abi::Vector {
+                        element: scalar,
+                        count
+                    },
                     size,
                     align,
                 })
@@ -2266,8 +2273,9 @@ impl<'a, 'tcx> TyLayout<'tcx> {
     pub fn is_zst(&self) -> bool {
         match self.abi {
             Abi::Uninhabited => true,
-            Abi::Scalar(_) | Abi::ScalarPair(..) => false,
-            Abi::Vector => self.size.bytes() == 0,
+            Abi::Scalar(_) |
+            Abi::ScalarPair(..) |
+            Abi::Vector { .. } => false,
             Abi::Aggregate { sized, .. } => sized && self.size.bytes() == 0
         }
     }
@@ -2322,6 +2330,9 @@ impl<'a, 'tcx> TyLayout<'tcx> {
                     scalar_component(b, a.value.size(cx).abi_align(b.value.align(cx)))
                 }));
             }
+            Abi::Vector { ref element, .. } => {
+                return Ok(scalar_component(element, Size::from_bytes(0)));
+            }
             _ => {}
         }
 
@@ -2424,7 +2435,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
                 a.hash_stable(hcx, hasher);
                 b.hash_stable(hcx, hasher);
             }
-            Vector => {}
+            Vector { ref element, count } => {
+                element.hash_stable(hcx, hasher);
+                count.hash_stable(hcx, hasher);
+            }
             Aggregate { packed, sized } => {
                 packed.hash_stable(hcx, hasher);
                 sized.hash_stable(hcx, hasher);
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 834558fc166..29905184001 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -315,7 +315,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
         match self.abi {
             layout::Abi::Uninhabited |
             layout::Abi::Scalar(_) |
-            layout::Abi::Vector => false,
+            layout::Abi::Vector { .. } => false,
             layout::Abi::ScalarPair(..) |
             layout::Abi::Aggregate { .. } => true
         }
@@ -339,7 +339,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
                 })
             }
 
-            layout::Abi::Vector => {
+            layout::Abi::Vector { .. } => {
                 Some(Reg {
                     kind: RegKind::Vector,
                     size: self.size
diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index 81eb362ca46..7c9f2574693 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -77,13 +77,14 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
                 unify(cls, off, reg);
             }
 
-            layout::Abi::Vector => {
+            layout::Abi::Vector { ref element, count } => {
                 unify(cls, off, Class::Sse);
 
                 // everything after the first one is the upper
                 // half of a register.
-                for i in 1..layout.fields.count() {
-                    let field_off = off + layout.fields.offset(i);
+                let stride = element.value.size(ccx);
+                for i in 1..count {
+                    let field_off = off + stride * i;
                     unify(cls, field_off, Class::SseUp);
                 }
             }
diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_trans/cabi_x86_win64.rs
index 473c00120a7..eb5ec403490 100644
--- a/src/librustc_trans/cabi_x86_win64.rs
+++ b/src/librustc_trans/cabi_x86_win64.rs
@@ -28,7 +28,7 @@ pub fn compute_abi_info(fty: &mut FnType) {
                     _ => a.make_indirect()
                 }
             }
-            layout::Abi::Vector => {
+            layout::Abi::Vector { .. } => {
                 // FIXME(eddyb) there should be a size cap here
                 // (probably what clang calls "illegal vectors").
             }
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 0799a388a8b..5521d842c95 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -122,17 +122,17 @@ impl<'a, 'tcx> Const<'tcx> {
         if field.is_zst() {
             return C_undef(field.immediate_llvm_type(ccx));
         }
+        let offset = layout.fields.offset(i);
         match layout.abi {
-            layout::Abi::Scalar(_) => self.llval,
+            layout::Abi::Scalar(_) |
+            layout::Abi::ScalarPair(..) |
+            layout::Abi::Vector { .. }
+                if offset.bytes() == 0 && field.size == layout.size => self.llval,
+
             layout::Abi::ScalarPair(ref a, ref b) => {
-                let offset = layout.fields.offset(i);
                 if offset.bytes() == 0 {
-                    if field.size == layout.size {
-                        self.llval
-                    } else {
-                        assert_eq!(field.size, a.value.size(ccx));
-                        const_get_elt(self.llval, 0)
-                    }
+                    assert_eq!(field.size, a.value.size(ccx));
+                    const_get_elt(self.llval, 0)
                 } else {
                     assert_eq!(offset, a.value.size(ccx)
                         .abi_align(b.value.align(ccx)));
@@ -1131,9 +1131,7 @@ fn trans_const_adt<'a, 'tcx>(
     match l.variants {
         layout::Variants::Single { index } => {
             assert_eq!(variant_index, index);
-            if let layout::Abi::Vector = l.abi {
-                Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t)
-            } else if let layout::FieldPlacement::Union(_) = l.fields {
+            if let layout::FieldPlacement::Union(_) = l.fields {
                 assert_eq!(variant_index, 0);
                 assert_eq!(vals.len(), 1);
                 let contents = [
@@ -1143,6 +1141,12 @@ fn trans_const_adt<'a, 'tcx>(
 
                 Const::new(C_struct(ccx, &contents, l.is_packed()), t)
             } else {
+                if let layout::Abi::Vector { .. } = l.abi {
+                    if let layout::FieldPlacement::Array { .. } = l.fields {
+                        return Const::new(C_vector(&vals.iter().map(|x| x.llval)
+                            .collect::<Vec<_>>()), t);
+                    }
+                }
                 build_const_struct(ccx, l, vals, None)
             }
         }
@@ -1206,7 +1210,8 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     match layout.abi {
         layout::Abi::Scalar(_) |
-        layout::Abi::ScalarPair(..) if discr.is_none() => {
+        layout::Abi::ScalarPair(..) |
+        layout::Abi::Vector { .. } if discr.is_none() => {
             let mut non_zst_fields = vals.iter().enumerate().map(|(i, f)| {
                 (f, layout.fields.offset(i))
             }).filter(|&(f, _)| !ccx.layout_of(f.ty).is_zst());
diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs
index 9f971025772..38817817552 100644
--- a/src/librustc_trans/mir/operand.rs
+++ b/src/librustc_trans/mir/operand.rs
@@ -163,7 +163,7 @@ impl<'a, 'tcx> OperandRef<'tcx> {
                 };
             }
 
-            // Newtype of a scalar or scalar pair.
+            // Newtype of a scalar, scalar pair or vector.
             (OperandValue::Immediate(_), _) |
             (OperandValue::Pair(..), _) if field.size == self.layout.size => {
                 assert_eq!(offset.bytes(), 0);
@@ -184,7 +184,7 @@ impl<'a, 'tcx> OperandRef<'tcx> {
             }
 
             // `#[repr(simd)]` types are also immediate.
-            (OperandValue::Immediate(llval), &layout::Abi::Vector) => {
+            (OperandValue::Immediate(llval), &layout::Abi::Vector { .. }) => {
                 OperandValue::Immediate(
                     bcx.extract_element(llval, C_usize(bcx.ccx, i as u64)))
             }
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 9ee4e7d4922..690b990c8b4 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -25,7 +25,7 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 -> Type {
     match layout.abi {
         layout::Abi::Scalar(_) => bug!("handled elsewhere"),
-        layout::Abi::Vector => {
+        layout::Abi::Vector { ref element, count } => {
             // LLVM has a separate type for 64-bit SIMD vectors on X86 called
             // `x86_mmx` which is needed for some SIMD operations. As a bit of a
             // hack (all SIMD definitions are super unstable anyway) we
@@ -33,15 +33,14 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             // x86_mmx" type. In general there shouldn't be a need for other
             // one-element SIMD vectors, so it's assumed this won't clash with
             // much else.
-            let use_x86_mmx = layout.fields.count() == 1 &&
-                layout.size.bits() == 64 &&
+            let use_x86_mmx = count == 1 && layout.size.bits() == 64 &&
                 (ccx.sess().target.target.arch == "x86" ||
                  ccx.sess().target.target.arch == "x86_64");
             if use_x86_mmx {
                 return Type::x86_mmx(ccx)
             } else {
-                return Type::vector(&layout.field(ccx, 0).llvm_type(ccx),
-                                    layout.fields.count() as u64);
+                let element = layout.scalar_llvm_type_at(ccx, element, Size::from_bytes(0));
+                return Type::vector(&element, count);
             }
         }
         layout::Abi::ScalarPair(..) => {
@@ -198,6 +197,8 @@ pub trait LayoutLlvmExt<'tcx> {
     fn is_llvm_scalar_pair<'a>(&self) -> bool;
     fn llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type;
     fn immediate_llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type;
+    fn scalar_llvm_type_at<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
+                               scalar: &layout::Scalar, offset: Size) -> Type;
     fn scalar_pair_element_llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
                                          index: usize) -> Type;
     fn llvm_field_index(&self, index: usize) -> u64;
@@ -210,7 +211,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
         match self.abi {
             layout::Abi::Uninhabited |
             layout::Abi::Scalar(_) |
-            layout::Abi::Vector => true,
+            layout::Abi::Vector { .. } => true,
             layout::Abi::ScalarPair(..) => false,
             layout::Abi::Aggregate { .. } => self.is_zst()
         }
@@ -221,7 +222,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
             layout::Abi::ScalarPair(..) => true,
             layout::Abi::Uninhabited |
             layout::Abi::Scalar(_) |
-            layout::Abi::Vector |
+            layout::Abi::Vector { .. } |
             layout::Abi::Aggregate { .. } => false
         }
     }
@@ -244,34 +245,19 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
             if let Some(&llty) = ccx.scalar_lltypes().borrow().get(&self.ty) {
                 return llty;
             }
-            let llty = match scalar.value {
-                layout::Int(i, _) => Type::from_integer(ccx, i),
-                layout::F32 => Type::f32(ccx),
-                layout::F64 => Type::f64(ccx),
-                layout::Pointer => {
-                    let pointee = match self.ty.sty {
-                        ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
-                        ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
-                            ccx.layout_of(ty).llvm_type(ccx)
-                        }
-                        ty::TyAdt(def, _) if def.is_box() => {
-                            ccx.layout_of(self.ty.boxed_ty()).llvm_type(ccx)
-                        }
-                        ty::TyFnPtr(sig) => {
-                            let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
-                            FnType::new(ccx, sig, &[]).llvm_type(ccx)
-                        }
-                        _ => {
-                            // If we know the alignment, pick something better than i8.
-                            if let Some(pointee) = self.pointee_info_at(ccx, Size::from_bytes(0)) {
-                                Type::pointee_for_abi_align(ccx, pointee.align)
-                            } else {
-                                Type::i8(ccx)
-                            }
-                        }
-                    };
-                    pointee.ptr_to()
+            let llty = match self.ty.sty {
+                ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
+                ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
+                    ccx.layout_of(ty).llvm_type(ccx).ptr_to()
+                }
+                ty::TyAdt(def, _) if def.is_box() => {
+                    ccx.layout_of(self.ty.boxed_ty()).llvm_type(ccx).ptr_to()
                 }
+                ty::TyFnPtr(sig) => {
+                    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
+                    FnType::new(ccx, sig, &[]).llvm_type(ccx).ptr_to()
+                }
+                _ => self.scalar_llvm_type_at(ccx, scalar, Size::from_bytes(0))
             };
             ccx.scalar_lltypes().borrow_mut().insert(self.ty, llty);
             return llty;
@@ -325,6 +311,24 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
         self.llvm_type(ccx)
     }
 
+    fn scalar_llvm_type_at<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
+                               scalar: &layout::Scalar, offset: Size) -> Type {
+        match scalar.value {
+            layout::Int(i, _) => Type::from_integer(ccx, i),
+            layout::F32 => Type::f32(ccx),
+            layout::F64 => Type::f64(ccx),
+            layout::Pointer => {
+                // If we know the alignment, pick something better than i8.
+                let pointee = if let Some(pointee) = self.pointee_info_at(ccx, offset) {
+                    Type::pointee_for_abi_align(ccx, pointee.align)
+                } else {
+                    Type::i8(ccx)
+                };
+                pointee.ptr_to()
+            }
+        }
+    }
+
     fn scalar_pair_element_llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
                                          index: usize) -> Type {
         // HACK(eddyb) special-case fat pointers until LLVM removes
@@ -358,25 +362,12 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
             return Type::i1(ccx);
         }
 
-        match scalar.value {
-            layout::Int(i, _) => Type::from_integer(ccx, i),
-            layout::F32 => Type::f32(ccx),
-            layout::F64 => Type::f64(ccx),
-            layout::Pointer => {
-                // If we know the alignment, pick something better than i8.
-                let offset = if index == 0 {
-                    Size::from_bytes(0)
-                } else {
-                    a.value.size(ccx).abi_align(b.value.align(ccx))
-                };
-                let pointee = if let Some(pointee) = self.pointee_info_at(ccx, offset) {
-                    Type::pointee_for_abi_align(ccx, pointee.align)
-                } else {
-                    Type::i8(ccx)
-                };
-                pointee.ptr_to()
-            }
-        }
+        let offset = if index == 0 {
+            Size::from_bytes(0)
+        } else {
+            a.value.size(ccx).abi_align(b.value.align(ccx))
+        };
+        self.scalar_llvm_type_at(ccx, scalar, offset)
     }
 
     fn llvm_field_index(&self, index: usize) -> u64 {