@@ -8,12 +8,10 @@ use itertools::Itertools;
88use rspirv:: spirv:: { Dim , ImageFormat , StorageClass , Word } ;
99use rustc_abi:: ExternAbi as Abi ;
1010use rustc_abi:: {
11- Align , BackendRepr , FieldIdx , FieldsShape , HasDataLayout as _, LayoutData , Primitive ,
12- ReprFlags , ReprOptions , Scalar , Size , TagEncoding , VariantIdx , Variants ,
11+ Align , BackendRepr , FieldIdx , FieldsShape , Primitive , Scalar , Size , VariantIdx , Variants ,
1312} ;
1413use rustc_data_structures:: fx:: FxHashMap ;
1514use rustc_errors:: ErrorGuaranteed ;
16- use rustc_hashes:: Hash64 ;
1715use rustc_index:: Idx ;
1816use rustc_middle:: query:: Providers ;
1917use rustc_middle:: ty:: layout:: { FnAbiOf , LayoutOf , TyAndLayout } ;
@@ -107,267 +105,6 @@ pub(crate) fn provide(providers: &mut Providers) {
107105 Ok ( readjust_fn_abi ( tcx, result?) )
108106 } ;
109107
110- // FIXME(eddyb) remove this by deriving `Clone` for `LayoutData` upstream.
111- fn clone_layout < FieldIdx : Idx , VariantIdx : Idx > (
112- layout : & LayoutData < FieldIdx , VariantIdx > ,
113- ) -> LayoutData < FieldIdx , VariantIdx > {
114- let LayoutData {
115- ref fields,
116- ref variants,
117- backend_repr,
118- largest_niche,
119- uninhabited,
120- align,
121- size,
122- max_repr_align,
123- unadjusted_abi_align,
124- randomization_seed,
125- } = * layout;
126- LayoutData {
127- fields : match * fields {
128- FieldsShape :: Primitive => FieldsShape :: Primitive ,
129- FieldsShape :: Union ( count) => FieldsShape :: Union ( count) ,
130- FieldsShape :: Array { stride, count } => FieldsShape :: Array { stride, count } ,
131- FieldsShape :: Arbitrary {
132- ref offsets,
133- ref memory_index,
134- } => FieldsShape :: Arbitrary {
135- offsets : offsets. clone ( ) ,
136- memory_index : memory_index. clone ( ) ,
137- } ,
138- } ,
139- variants : match * variants {
140- Variants :: Empty => Variants :: Empty ,
141- Variants :: Single { index } => Variants :: Single { index } ,
142- Variants :: Multiple {
143- tag,
144- ref tag_encoding,
145- tag_field,
146- ref variants,
147- } => Variants :: Multiple {
148- tag,
149- tag_encoding : match * tag_encoding {
150- TagEncoding :: Direct => TagEncoding :: Direct ,
151- TagEncoding :: Niche {
152- untagged_variant,
153- ref niche_variants,
154- niche_start,
155- } => TagEncoding :: Niche {
156- untagged_variant,
157- niche_variants : niche_variants. clone ( ) ,
158- niche_start,
159- } ,
160- } ,
161- tag_field,
162- variants : variants. clone ( ) ,
163- } ,
164- } ,
165- backend_repr,
166- largest_niche,
167- uninhabited,
168- align,
169- size,
170- max_repr_align,
171- unadjusted_abi_align,
172- randomization_seed,
173- }
174- }
175-
176- providers. layout_of = |tcx, key| {
177- // HACK(eddyb) to special-case any types at all, they must be normalized,
178- // but when normalization would be needed, `layout_of`'s default provider
179- // recurses (supposedly for caching reasons), i.e. its calls `layout_of`
180- // w/ the normalized type in input, which once again reaches this hook,
181- // without ever needing any explicit normalization here.
182- let ty = key. value ;
183-
184- // HACK(eddyb) bypassing upstream `#[repr(simd)]` changes (see also
185- // the later comment above `check_well_formed`, for more details).
186- let reimplement_old_style_repr_simd = match ty. kind ( ) {
187- ty:: Adt ( def, args) if def. repr ( ) . simd ( ) && !def. repr ( ) . packed ( ) && def. is_struct ( ) => {
188- Some ( def. non_enum_variant ( ) ) . and_then ( |v| {
189- let ( count, e_ty) = v
190- . fields
191- . iter ( )
192- . map ( |f| f. ty ( tcx, args) )
193- . dedup_with_count ( )
194- . exactly_one ( )
195- . ok ( ) ?;
196- let e_len = u64:: try_from ( count) . ok ( ) . filter ( |& e_len| e_len > 1 ) ?;
197- Some ( ( def, e_ty, e_len) )
198- } )
199- }
200- _ => None ,
201- } ;
202-
203- // HACK(eddyb) tweaked copy of the old upstream logic for `#[repr(simd)]`:
204- // https://github.com/rust-lang/rust/blob/1.86.0/compiler/rustc_ty_utils/src/layout.rs#L464-L590
205- if let Some ( ( adt_def, e_ty, e_len) ) = reimplement_old_style_repr_simd {
206- let cx = rustc_middle:: ty:: layout:: LayoutCx :: new (
207- tcx,
208- key. typing_env . with_post_analysis_normalized ( tcx) ,
209- ) ;
210- let dl = cx. data_layout ( ) ;
211-
212- // Compute the ABI of the element type:
213- let e_ly = cx. layout_of ( e_ty) ?;
214- let BackendRepr :: Scalar ( e_repr) = e_ly. backend_repr else {
215- // This error isn't caught in typeck, e.g., if
216- // the element type of the vector is generic.
217- tcx. dcx ( ) . span_fatal (
218- tcx. def_span ( adt_def. did ( ) ) ,
219- format ! (
220- "SIMD type `{ty}` with a non-primitive-scalar \
221- (integer/float/pointer) element type `{}`",
222- e_ly. ty
223- ) ,
224- ) ;
225- } ;
226-
227- // Compute the size and alignment of the vector:
228- let size = e_ly. size . checked_mul ( e_len, dl) . unwrap ( ) ;
229- let align = dl. llvmlike_vector_align ( size) ;
230- let size = size. align_to ( align. abi ) ;
231-
232- let layout = tcx. mk_layout ( LayoutData {
233- variants : Variants :: Single {
234- index : rustc_abi:: FIRST_VARIANT ,
235- } ,
236- fields : FieldsShape :: Array {
237- stride : e_ly. size ,
238- count : e_len,
239- } ,
240- backend_repr : BackendRepr :: SimdVector {
241- element : e_repr,
242- count : e_len,
243- } ,
244- largest_niche : e_ly. largest_niche ,
245- uninhabited : false ,
246- size,
247- align,
248- max_repr_align : None ,
249- unadjusted_abi_align : align. abi ,
250- randomization_seed : e_ly. randomization_seed . wrapping_add ( Hash64 :: new ( e_len) ) ,
251- } ) ;
252-
253- return Ok ( TyAndLayout { ty, layout } ) ;
254- }
255-
256- let TyAndLayout { ty, mut layout } =
257- ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . layout_of ) ( tcx, key) ?;
258-
259- #[ allow( clippy:: match_like_matches_macro) ]
260- let hide_niche = match ty. kind ( ) {
261- ty:: Bool => {
262- // HACK(eddyb) we can't bypass e.g. `Option<bool>` being a byte,
263- // due to `core` PR https://github.com/rust-lang/rust/pull/138881
264- // (which adds a new `transmute`, from `ControlFlow<bool>` to `u8`).
265- let libcore_needs_bool_niche = true ;
266-
267- !libcore_needs_bool_niche
268- }
269- _ => false ,
270- } ;
271-
272- if hide_niche {
273- layout = tcx. mk_layout ( LayoutData {
274- largest_niche : None ,
275- ..clone_layout ( layout. 0 . 0 )
276- } ) ;
277- }
278-
279- Ok ( TyAndLayout { ty, layout } )
280- } ;
281-
282- // HACK(eddyb) work around https://github.com/rust-lang/rust/pull/129403
283- // banning "struct-style" `#[repr(simd)]` (in favor of "array-newtype-style"),
284- // by simply bypassing "type definition WF checks" for affected types, which:
285- // - can only really be sound for types with trivial field types, that are
286- // either completely non-generic (covering most `#[repr(simd)]` `struct`s),
287- // or *at most* one generic type parameter with no bounds/where clause
288- // - relies on upstream `layout_of` not having had the non-array logic removed
289- //
290- // FIXME(eddyb) remove this once migrating beyond `#[repr(simd)]` becomes
291- // an option (may require Rust-GPU distinguishing between "SPIR-V interface"
292- // and "Rust-facing" types, which is even worse when the `OpTypeVector`s
293- // may be e.g. nested in `struct`s/arrays/etc. - at least buffers are easy).
294- //
295- // FIXME(eddyb) maybe using `#[spirv(vector)]` and `BackendRepr::Memory`,
296- // no claims at `rustc`-understood SIMD whatsoever, would be enough?
297- // (i.e. only SPIR-V caring about such a type vs a struct/array)
298- providers. check_well_formed = |tcx, def_id| {
299- let trivial_struct = match tcx. hir_node_by_def_id ( def_id) {
300- rustc_hir:: Node :: Item ( item) => match item. kind {
301- rustc_hir:: ItemKind :: Struct (
302- _,
303- & rustc_hir:: Generics {
304- params :
305- & [ ]
306- | & [
307- rustc_hir:: GenericParam {
308- kind :
309- rustc_hir:: GenericParamKind :: Type {
310- default : None ,
311- synthetic : false ,
312- } ,
313- ..
314- } ,
315- ] ,
316- predicates : & [ ] ,
317- has_where_clause_predicates : false ,
318- where_clause_span : _,
319- span : _,
320- } ,
321- _,
322- ) => Some ( tcx. adt_def ( def_id) ) ,
323- _ => None ,
324- } ,
325- _ => None ,
326- } ;
327- let valid_non_array_simd_struct = trivial_struct. is_some_and ( |adt_def| {
328- let ReprOptions {
329- int : None ,
330- align : None ,
331- pack : None ,
332- flags : ReprFlags :: IS_SIMD ,
333- field_shuffle_seed : _,
334- } = adt_def. repr ( )
335- else {
336- return false ;
337- } ;
338- if adt_def. destructor ( tcx) . is_some ( ) {
339- return false ;
340- }
341-
342- let field_types = adt_def
343- . non_enum_variant ( )
344- . fields
345- . iter ( )
346- . map ( |f| tcx. type_of ( f. did ) . instantiate_identity ( ) ) ;
347- field_types. dedup ( ) . exactly_one ( ) . is_ok_and ( |elem_ty| {
348- matches ! (
349- elem_ty. kind( ) ,
350- ty:: Bool | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) | ty:: Param ( _)
351- )
352- } )
353- } ) ;
354-
355- if valid_non_array_simd_struct {
356- tcx. dcx ( )
357- . struct_span_warn (
358- tcx. def_span ( def_id) ,
359- "[Rust-GPU] temporarily re-allowing old-style `#[repr(simd)]` (with fields)" ,
360- )
361- . with_note ( "removed upstream by https://github.com/rust-lang/rust/pull/129403" )
362- . with_note ( "in favor of the new `#[repr(simd)] struct TxN([T; N]);` style" )
363- . with_note ( "(taking effect since `nightly-2024-09-12` / `1.83.0` stable)" )
364- . emit ( ) ;
365- return Ok ( ( ) ) ;
366- }
367-
368- ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . check_well_formed ) ( tcx, def_id)
369- } ;
370-
371108 // HACK(eddyb) work around https://github.com/rust-lang/rust/pull/132173
372109 // (and further changes from https://github.com/rust-lang/rust/pull/132843)
373110 // starting to ban SIMD ABI misuse (or at least starting to warn about it).
0 commit comments