Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/layout.rs')
| -rw-r--r-- | crates/hir-ty/src/layout.rs | 106 |
1 files changed, 96 insertions, 10 deletions
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 35d3407c16..72e2bcc555 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -7,7 +7,7 @@ use hir_def::{ Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange, }, - LocalEnumVariantId, LocalFieldId, + LocalEnumVariantId, LocalFieldId, StructId, }; use la_arena::{Idx, RawIdx}; use stdx::never; @@ -24,8 +24,8 @@ pub use self::{ }; macro_rules! user_error { - ($x: expr) => { - return Err(LayoutError::UserError(format!($x))) + ($it: expr) => { + return Err(LayoutError::UserError(format!($it))) }; } @@ -77,18 +77,101 @@ impl<'a> LayoutCalculator for LayoutCx<'a> { } } +// FIXME: move this to the `rustc_abi`. +fn layout_of_simd_ty( + db: &dyn HirDatabase, + id: StructId, + subst: &Substitution, + krate: CrateId, + dl: &TargetDataLayout, +) -> Result<Arc<Layout>, LayoutError> { + let fields = db.field_types(id.into()); + + // Supported SIMD vectors are homogeneous ADTs with at least one field: + // + // * #[repr(simd)] struct S(T, T, T, T); + // * #[repr(simd)] struct S { it: T, y: T, z: T, w: T } + // * #[repr(simd)] struct S([T; 4]) + // + // where T is a primitive scalar (integer/float/pointer). + + let f0_ty = match fields.iter().next() { + Some(it) => it.1.clone().substitute(Interner, subst), + None => { + user_error!("simd type with zero fields"); + } + }; + + // The element type and number of elements of the SIMD vector + // are obtained from: + // + // * the element type and length of the single array field, if + // the first field is of array type, or + // + // * the homogeneous field type and the number of fields. + let (e_ty, e_len, is_array) = if let TyKind::Array(e_ty, _) = f0_ty.kind(Interner) { + // Extract the number of elements from the layout of the array field: + let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), krate)?.fields else { + user_error!("Array with non array layout"); + }; + + (e_ty.clone(), count, true) + } else { + // First ADT field is not an array: + (f0_ty, fields.iter().count() as u64, false) + }; + + // Compute the ABI of the element type: + let e_ly = db.layout_of_ty(e_ty, krate)?; + let Abi::Scalar(e_abi) = e_ly.abi else { + user_error!("simd type with inner non scalar type"); + }; + + // Compute the size and alignment of the vector: + let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow)?; + let align = dl.vector_align(size); + let size = size.align_to(align.abi); + + // Compute the placement of the vector fields: + let fields = if is_array { + FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() } + } else { + FieldsShape::Array { stride: e_ly.size, count: e_len } + }; + + Ok(Arc::new(Layout { + variants: Variants::Single { index: struct_variant_idx() }, + fields, + abi: Abi::Vector { element: e_abi, count: e_len }, + largest_niche: e_ly.largest_niche, + size, + align, + })) +} + pub fn layout_of_ty_query( db: &dyn HirDatabase, ty: Ty, krate: CrateId, ) -> Result<Arc<Layout>, LayoutError> { - let Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) }; + let Some(target) = db.target_data_layout(krate) else { + return Err(LayoutError::TargetLayoutNotAvailable); + }; let cx = LayoutCx { krate, target: &target }; let dl = &*cx.current_data_layout(); let trait_env = Arc::new(TraitEnvironment::empty(krate)); let ty = normalize(db, trait_env, ty.clone()); let result = match ty.kind(Interner) { - TyKind::Adt(AdtId(def), subst) => return db.layout_of_adt(*def, subst.clone(), krate), + TyKind::Adt(AdtId(def), subst) => { + if let hir_def::AdtId::StructId(s) = def { + let data = db.struct_data(*s); + let repr = data.repr.unwrap_or_default(); + if repr.simd() { + return layout_of_simd_ty(db, *s, subst, krate, &target); + } + }; + return db.layout_of_adt(*def, subst.clone(), krate); + } TyKind::Scalar(s) => match s { chalk_ir::Scalar::Bool => Layout::scalar( dl, @@ -147,7 +230,7 @@ pub fn layout_of_ty_query( .iter(Interner) .map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), krate)) .collect::<Result<Vec<_>, _>>()?; - let fields = fields.iter().map(|x| &**x).collect::<Vec<_>>(); + let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>(); let fields = fields.iter().collect::<Vec<_>>(); cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)? } @@ -265,14 +348,14 @@ pub fn layout_of_ty_query( let (captures, _) = infer.closure_info(c); let fields = captures .iter() - .map(|x| { + .map(|it| { db.layout_of_ty( - x.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()), + it.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()), krate, ) }) .collect::<Result<Vec<_>, _>>()?; - let fields = fields.iter().map(|x| &**x).collect::<Vec<_>>(); + let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>(); let fields = fields.iter().collect::<Vec<_>>(); cx.univariant(dl, &fields, &ReprOptions::default(), StructKind::AlwaysSized) .ok_or(LayoutError::Unknown)? @@ -315,7 +398,10 @@ fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty { let data = db.struct_data(*i); let mut it = data.variant_data.fields().iter().rev(); match it.next() { - Some((f, _)) => field_ty(db, (*i).into(), f, subst), + Some((f, _)) => { + let last_field_ty = field_ty(db, (*i).into(), f, subst); + struct_tail_erasing_lifetimes(db, last_field_ty) + } None => pointee, } } |