diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index b2ed34cb91305ea9078af13cc087c0058ae35d60..9ae647c97d28f8deaa1a44ca9b143e09055d46cc 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 @@ pub fn is_unsized(&self) -> bool { Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | - Abi::Vector => false, + Abi::Vector { .. } => false, Abi::Aggregate { sized, .. } => !sized } } @@ -784,7 +787,7 @@ pub fn is_packed(&self) -> bool { Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | - Abi::Vector => false, + Abi::Vector { .. } => false, Abi::Aggregate { packed, .. } => packed } } @@ -1083,9 +1086,9 @@ enum StructKind { 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 @@ enum StructKind { // 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 @@ enum StructKind { stride: element.size, count }, - abi: Abi::Vector, + abi: Abi::Vector { + element: scalar, + count + }, size, align, }) @@ -2266,8 +2273,9 @@ pub fn is_packed(&self) -> bool { 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 @@ fn find_niche(&self, cx: C, count: u128) 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 @@ fn hash_stable(&self, 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 834558fc16614825af9dd3dde7684502fcde389b..29905184001663e84c274895bec3a273786c980a 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -315,7 +315,7 @@ fn is_aggregate(&self) -> bool { 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 @@ fn homogeneous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option }) } - 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 81eb362ca46dc776281e3a7d62cd763dd12d2bd3..7c9f257469370d84ccba9cdb561a349aca189f5f 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -77,13 +77,14 @@ fn classify<'a, 'tcx>(ccx: &CrateContext<'a, '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 473c00120a740c6b2d3e3e4068a975f36c373ce1..eb5ec4034904bff72117186a11228acdbe73fe0b 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 0799a388a8becf207a37b58af9932ddc7a3dacdf..5521d842c9531fe4bdbf6eac0b0f5ef78b23d386 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -122,17 +122,17 @@ fn get_field(&self, ccx: &CrateContext<'a, 'tcx>, i: usize) -> ValueRef { 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::>()), 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::>()), 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 9f9710257723145ef02efafe333773f0ab98f5ac..38817817552045ffd2e920f6d745fd125c3e9bdd 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -163,7 +163,7 @@ pub fn extract_field(&self, bcx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tc }; } - // 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 @@ pub fn extract_field(&self, bcx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tc } // `#[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 9ee4e7d4922e27d8f1b558c179fbecbec99ce64e..690b990c8b464b2c06e0d5a54274241a68ce743f 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 @@ fn is_llvm_immediate(&self) -> bool { 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 @@ fn is_llvm_scalar_pair<'a>(&self) -> bool { layout::Abi::ScalarPair(..) => true, layout::Abi::Uninhabited | layout::Abi::Scalar(_) | - layout::Abi::Vector | + layout::Abi::Vector { .. } | layout::Abi::Aggregate { .. } => false } } @@ -244,34 +245,19 @@ fn llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type { 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 @@ fn immediate_llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type { 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 @@ fn scalar_pair_element_llvm_type<'a>(&self, ccx: &CrateContext<'a, '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 {