Skip to content

Commit

Permalink
rustc: unpack newtyped of #[repr(simd)] vector types.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Dec 12, 2017
1 parent 707d070 commit 95c0ad0
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 87 deletions.
42 changes: 28 additions & 14 deletions src/librustc/ty/layout.rs
Expand Up @@ -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,
Expand All @@ -773,7 +776,7 @@ impl Abi {
Abi::Uninhabited |
Abi::Scalar(_) |
Abi::ScalarPair(..) |
Abi::Vector => false,
Abi::Vector { .. } => false,
Abi::Aggregate { sized, .. } => !sized
}
}
Expand All @@ -784,7 +787,7 @@ impl Abi {
Abi::Uninhabited |
Abi::Scalar(_) |
Abi::ScalarPair(..) |
Abi::Vector => false,
Abi::Vector { .. } => false,
Abi::Aggregate { packed, .. } => packed
}
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -1341,7 +1345,10 @@ impl<'a, 'tcx> LayoutDetails {
stride: element.size,
count
},
abi: Abi::Vector,
abi: Abi::Vector {
element: scalar,
count
},
size,
align,
})
Expand Down Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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)));
}
_ => {}
}

Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/abi.rs
Expand Up @@ -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
}
Expand All @@ -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
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_trans/cabi_x86_64.rs
Expand Up @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/cabi_x86_win64.rs
Expand Up @@ -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").
}
Expand Down
29 changes: 17 additions & 12 deletions src/librustc_trans/mir/constant.rs
Expand Up @@ -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)));
Expand Down Expand Up @@ -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 = [
Expand All @@ -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)
}
}
Expand Down Expand Up @@ -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());
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/mir/operand.rs
Expand Up @@ -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);
Expand All @@ -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)))
}
Expand Down
97 changes: 44 additions & 53 deletions src/librustc_trans/type_of.rs
Expand Up @@ -25,23 +25,22 @@ 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
// recognize any one-element SIMD vector as "this should be an
// 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(..) => {
Expand Down Expand Up @@ -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;
Expand All @@ -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()
}
Expand All @@ -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
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 95c0ad0

Please sign in to comment.