Skip to content

rustc: unpack newtyped of #[repr(simd)] vector types. #46701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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