Skip to content

Commit 257158f

Browse files
committed
Support repr(simd) on ADTs containing a single array field
This PR allows using `#[repr(simd)]` on ADTs containing a single array field: ```rust #[repr(simd)] struct S0([f32; 4]); #[repr(simd)] struct S1<const N: usize>([f32; N]); #[repr(simd)] struct S2<T, const N: usize>([T; N]); ``` This should allow experimenting with portable packed SIMD abstractions on nightly that make use of const generics.
1 parent d4abb08 commit 257158f

File tree

10 files changed

+390
-155
lines changed

10 files changed

+390
-155
lines changed

src/librustc/ty/layout.rs

+101-23
Original file line numberDiff line numberDiff line change
@@ -687,34 +687,117 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
687687
}
688688

689689
// SIMD vector types.
690-
ty::Adt(def, ..) if def.repr.simd() => {
691-
let element = self.layout_of(ty.simd_type(tcx))?;
692-
let count = ty.simd_size(tcx) as u64;
693-
assert!(count > 0);
694-
let scalar = match element.abi {
695-
Abi::Scalar(ref scalar) => scalar.clone(),
696-
_ => {
697-
tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \
698-
a non-machine element type `{}`",
699-
ty, element.ty));
690+
ty::Adt(def, substs) if def.repr.simd() => {
691+
// Supported SIMD vectors are homogeneous ADTs with at least one field:
692+
//
693+
// * #[repr(simd)] struct S(T, T, T, T);
694+
// * #[repr(simd)] struct S { x: T, y: T, z: T, w: T }
695+
// * #[repr(simd)] struct S([T; 4])
696+
//
697+
// where T is a "machine type", e.g., `f32`, `i64`, `*mut _`.
698+
699+
// SIMD vectors with zero fields are not supported:
700+
if def.non_enum_variant().fields.is_empty() {
701+
tcx.sess.fatal(&format!(
702+
"monomorphising SIMD type `{}` of zero length", ty
703+
));
704+
}
705+
706+
// Type of the first ADT field:
707+
let f0_ty = def.non_enum_variant().fields[0].ty(tcx, substs);
708+
709+
// Heterogeneous SIMD vectors are not supported:
710+
for fi in &def.non_enum_variant().fields {
711+
if fi.ty(tcx, substs) != f0_ty {
712+
tcx.sess.fatal(&format!(
713+
"monomorphising heterogeneous SIMD type `{}`", ty
714+
));
700715
}
716+
}
717+
718+
// The element type and number of elements of the SIMD vector
719+
// are obtained from:
720+
//
721+
// * the element type and length of the single array field, if
722+
// the first field is of array type, or
723+
//
724+
// * the homogenous field type and the number of fields.
725+
let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.sty {
726+
// First ADT field is an array:
727+
728+
// SIMD vectors with multiple array fields are not supported:
729+
if def.non_enum_variant().fields.len() != 1 {
730+
tcx.sess.fatal(&format!(
731+
"monomorphising SIMD type `{}` with more than one array field",
732+
ty
733+
));
734+
}
735+
736+
// Extract the number of elements from the layout of the array field:
737+
let len = if let Ok(TyLayout{
738+
details: LayoutDetails {
739+
fields: FieldPlacement::Array {
740+
count, ..
741+
}, ..
742+
}, ..
743+
}) = self.layout_of(f0_ty) {
744+
count
745+
} else {
746+
unreachable!();
747+
};
748+
749+
(e_ty, *len, true)
750+
} else {
751+
// First ADT field is not an array:
752+
(f0_ty, def.non_enum_variant().fields.len() as _, false)
701753
};
702-
let size = element.size.checked_mul(count, dl)
754+
755+
// SIMD vectors of zero length are not supported:
756+
if e_len == 0 {
757+
tcx.sess.fatal(&format!(
758+
"monomorphising SIMD type `{}` of zero length", ty
759+
));
760+
}
761+
762+
// Compute the ABI of the element type:
763+
let e_ly = self.layout_of(e_ty)?;
764+
let e_abi = if let Abi::Scalar(ref scalar) = e_ly.abi {
765+
scalar.clone()
766+
} else {
767+
tcx.sess.fatal(&format!(
768+
"monomorphising SIMD type `{}` with a non-machine element type `{}`",
769+
ty, e_ty
770+
))
771+
};
772+
773+
774+
// Compute the size and alignment of the vector:
775+
let size = e_ly.size.checked_mul(e_len, dl)
703776
.ok_or(LayoutError::SizeOverflow(ty))?;
704777
let align = dl.vector_align(size);
705778
let size = size.align_to(align.abi);
706779

780+
// Compute the placement of the vector fields:
781+
let fields = if is_array {
782+
FieldPlacement::Arbitrary {
783+
offsets: vec![Size::ZERO],
784+
memory_index: vec![0],
785+
}
786+
} else {
787+
FieldPlacement::Array {
788+
stride: e_ly.size,
789+
count: e_len,
790+
}
791+
};
792+
707793
tcx.intern_layout(LayoutDetails {
708794
variants: Variants::Single { index: VariantIdx::new(0) },
709-
fields: FieldPlacement::Array {
710-
stride: element.size,
711-
count
712-
},
795+
fields,
713796
abi: Abi::Vector {
714-
element: scalar,
715-
count
797+
element: e_abi,
798+
count: e_len,
716799
},
717-
largest_niche: element.largest_niche.clone(),
800+
largest_niche: e_ly.largest_niche.clone(),
718801
size,
719802
align,
720803
})
@@ -2170,11 +2253,6 @@ where
21702253

21712254
ty::Tuple(tys) => tys[i].expect_ty(),
21722255

2173-
// SIMD vector types.
2174-
ty::Adt(def, ..) if def.repr.simd() => {
2175-
this.ty.simd_type(tcx)
2176-
}
2177-
21782256
// ADTs.
21792257
ty::Adt(def, substs) => {
21802258
match this.variants {

src/librustc/ty/sty.rs

-16
Original file line numberDiff line numberDiff line change
@@ -1823,22 +1823,6 @@ impl<'tcx> TyS<'tcx> {
18231823
}
18241824
}
18251825

1826-
pub fn simd_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
1827-
match self.sty {
1828-
Adt(def, substs) => {
1829-
def.non_enum_variant().fields[0].ty(tcx, substs)
1830-
}
1831-
_ => bug!("simd_type called on invalid type")
1832-
}
1833-
}
1834-
1835-
pub fn simd_size(&self, _cx: TyCtxt<'_>) -> usize {
1836-
match self.sty {
1837-
Adt(def, _) => def.non_enum_variant().fields.len(),
1838-
_ => bug!("simd_size called on invalid type")
1839-
}
1840-
}
1841-
18421826
#[inline]
18431827
pub fn is_region_ptr(&self) -> bool {
18441828
match self.sty {

0 commit comments

Comments
 (0)