Auto merge of #46701 - eddyb:vector-newtypes, r=nagisa
rustc: unpack newtyped of #[repr(simd)] vector types. Prerequisite for a `#[repr(transparent)]` implementation that works with SIMD vectors. cc @rkruppe
This commit is contained in:
commit
9331031909
7 changed files with 98 additions and 87 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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").
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue