@@ -8,11 +8,12 @@ use itertools::Itertools;
88use rspirv:: spirv:: { Dim , ImageFormat , StorageClass , Word } ;
99use rustc_abi:: ExternAbi as Abi ;
1010use rustc_abi:: {
11- Align , BackendRepr , FieldIdx , FieldsShape , LayoutData , Primitive , ReprFlags , ReprOptions ,
12- Scalar , Size , TagEncoding , VariantIdx , Variants ,
11+ Align , BackendRepr , FieldIdx , FieldsShape , HasDataLayout as _ , LayoutData , Primitive ,
12+ ReprFlags , ReprOptions , Scalar , Size , TagEncoding , VariantIdx , Variants ,
1313} ;
1414use rustc_data_structures:: fx:: FxHashMap ;
1515use rustc_errors:: ErrorGuaranteed ;
16+ use rustc_hashes:: Hash64 ;
1617use rustc_index:: Idx ;
1718use rustc_middle:: query:: Providers ;
1819use rustc_middle:: ty:: layout:: { FnAbiOf , LayoutOf , TyAndLayout } ;
@@ -164,6 +165,85 @@ pub(crate) fn provide(providers: &mut Providers) {
164165 }
165166
166167 providers. layout_of = |tcx, key| {
168+ // HACK(eddyb) to special-case any types at all, they must be normalized,
169+ // but when normalization would be needed, `layout_of`'s default provider
170+ // recurses (supposedly for caching reasons), i.e. its calls `layout_of`
171+ // w/ the normalized type in input, which once again reaches this hook,
172+ // without ever needing any explicit normalization here.
173+ let ty = key. value ;
174+
175+ // HACK(eddyb) bypassing upstream `#[repr(simd)]` changes (see also
176+ // the later comment above `check_well_formed`, for more details).
177+ let reimplement_old_style_repr_simd = match ty. kind ( ) {
178+ ty:: Adt ( def, args) if def. repr ( ) . simd ( ) && !def. repr ( ) . packed ( ) && def. is_struct ( ) => {
179+ Some ( def. non_enum_variant ( ) ) . and_then ( |v| {
180+ let ( count, e_ty) = v
181+ . fields
182+ . iter ( )
183+ . map ( |f| f. ty ( tcx, args) )
184+ . dedup_with_count ( )
185+ . exactly_one ( )
186+ . ok ( ) ?;
187+ let e_len = u64:: try_from ( count) . ok ( ) . filter ( |& e_len| e_len > 1 ) ?;
188+ Some ( ( def, e_ty, e_len) )
189+ } )
190+ }
191+ _ => None ,
192+ } ;
193+
194+ // HACK(eddyb) tweaked copy of the old upstream logic for `#[repr(simd)]`:
195+ // https://github.com/rust-lang/rust/blob/1.86.0/compiler/rustc_ty_utils/src/layout.rs#L464-L590
196+ if let Some ( ( adt_def, e_ty, e_len) ) = reimplement_old_style_repr_simd {
197+ let cx = rustc_middle:: ty:: layout:: LayoutCx :: new (
198+ tcx,
199+ key. typing_env . with_post_analysis_normalized ( tcx) ,
200+ ) ;
201+ let dl = cx. data_layout ( ) ;
202+
203+ // Compute the ABI of the element type:
204+ let e_ly = cx. layout_of ( e_ty) ?;
205+ let BackendRepr :: Scalar ( e_repr) = e_ly. backend_repr else {
206+ // This error isn't caught in typeck, e.g., if
207+ // the element type of the vector is generic.
208+ tcx. dcx ( ) . span_fatal (
209+ tcx. def_span ( adt_def. did ( ) ) ,
210+ format ! (
211+ "SIMD type `{ty}` with a non-primitive-scalar \
212+ (integer/float/pointer) element type `{}`",
213+ e_ly. ty
214+ ) ,
215+ ) ;
216+ } ;
217+
218+ // Compute the size and alignment of the vector:
219+ let size = e_ly. size . checked_mul ( e_len, dl) . unwrap ( ) ;
220+ let align = dl. llvmlike_vector_align ( size) ;
221+ let size = size. align_to ( align. abi ) ;
222+
223+ let layout = tcx. mk_layout ( LayoutData {
224+ variants : Variants :: Single {
225+ index : rustc_abi:: FIRST_VARIANT ,
226+ } ,
227+ fields : FieldsShape :: Array {
228+ stride : e_ly. size ,
229+ count : e_len,
230+ } ,
231+ backend_repr : BackendRepr :: SimdVector {
232+ element : e_repr,
233+ count : e_len,
234+ } ,
235+ largest_niche : e_ly. largest_niche ,
236+ uninhabited : false ,
237+ size,
238+ align,
239+ max_repr_align : None ,
240+ unadjusted_abi_align : align. abi ,
241+ randomization_seed : e_ly. randomization_seed . wrapping_add ( Hash64 :: new ( e_len) ) ,
242+ } ) ;
243+
244+ return Ok ( TyAndLayout { ty, layout } ) ;
245+ }
246+
167247 let TyAndLayout { ty, mut layout } =
168248 ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . layout_of ) ( tcx, key) ?;
169249
0 commit comments