@@ -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 } ;
@@ -98,267 +96,6 @@ pub(crate) fn provide(providers: &mut Providers) {
9896 Ok ( readjust_fn_abi ( tcx, result?) )
9997 } ;
10098
101- // FIXME(eddyb) remove this by deriving `Clone` for `LayoutData` upstream.
102- fn clone_layout < FieldIdx : Idx , VariantIdx : Idx > (
103- layout : & LayoutData < FieldIdx , VariantIdx > ,
104- ) -> LayoutData < FieldIdx , VariantIdx > {
105- let LayoutData {
106- ref fields,
107- ref variants,
108- backend_repr,
109- largest_niche,
110- uninhabited,
111- align,
112- size,
113- max_repr_align,
114- unadjusted_abi_align,
115- randomization_seed,
116- } = * layout;
117- LayoutData {
118- fields : match * fields {
119- FieldsShape :: Primitive => FieldsShape :: Primitive ,
120- FieldsShape :: Union ( count) => FieldsShape :: Union ( count) ,
121- FieldsShape :: Array { stride, count } => FieldsShape :: Array { stride, count } ,
122- FieldsShape :: Arbitrary {
123- ref offsets,
124- ref memory_index,
125- } => FieldsShape :: Arbitrary {
126- offsets : offsets. clone ( ) ,
127- memory_index : memory_index. clone ( ) ,
128- } ,
129- } ,
130- variants : match * variants {
131- Variants :: Empty => Variants :: Empty ,
132- Variants :: Single { index } => Variants :: Single { index } ,
133- Variants :: Multiple {
134- tag,
135- ref tag_encoding,
136- tag_field,
137- ref variants,
138- } => Variants :: Multiple {
139- tag,
140- tag_encoding : match * tag_encoding {
141- TagEncoding :: Direct => TagEncoding :: Direct ,
142- TagEncoding :: Niche {
143- untagged_variant,
144- ref niche_variants,
145- niche_start,
146- } => TagEncoding :: Niche {
147- untagged_variant,
148- niche_variants : niche_variants. clone ( ) ,
149- niche_start,
150- } ,
151- } ,
152- tag_field,
153- variants : variants. clone ( ) ,
154- } ,
155- } ,
156- backend_repr,
157- largest_niche,
158- uninhabited,
159- align,
160- size,
161- max_repr_align,
162- unadjusted_abi_align,
163- randomization_seed,
164- }
165- }
166-
167- 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-
247- let TyAndLayout { ty, mut layout } =
248- ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . layout_of ) ( tcx, key) ?;
249-
250- #[ allow( clippy:: match_like_matches_macro) ]
251- let hide_niche = match ty. kind ( ) {
252- ty:: Bool => {
253- // HACK(eddyb) we can't bypass e.g. `Option<bool>` being a byte,
254- // due to `core` PR https://github.com/rust-lang/rust/pull/138881
255- // (which adds a new `transmute`, from `ControlFlow<bool>` to `u8`).
256- let libcore_needs_bool_niche = true ;
257-
258- !libcore_needs_bool_niche
259- }
260- _ => false ,
261- } ;
262-
263- if hide_niche {
264- layout = tcx. mk_layout ( LayoutData {
265- largest_niche : None ,
266- ..clone_layout ( layout. 0 . 0 )
267- } ) ;
268- }
269-
270- Ok ( TyAndLayout { ty, layout } )
271- } ;
272-
273- // HACK(eddyb) work around https://github.com/rust-lang/rust/pull/129403
274- // banning "struct-style" `#[repr(simd)]` (in favor of "array-newtype-style"),
275- // by simply bypassing "type definition WF checks" for affected types, which:
276- // - can only really be sound for types with trivial field types, that are
277- // either completely non-generic (covering most `#[repr(simd)]` `struct`s),
278- // or *at most* one generic type parameter with no bounds/where clause
279- // - relies on upstream `layout_of` not having had the non-array logic removed
280- //
281- // FIXME(eddyb) remove this once migrating beyond `#[repr(simd)]` becomes
282- // an option (may require Rust-GPU distinguishing between "SPIR-V interface"
283- // and "Rust-facing" types, which is even worse when the `OpTypeVector`s
284- // may be e.g. nested in `struct`s/arrays/etc. - at least buffers are easy).
285- //
286- // FIXME(eddyb) maybe using `#[spirv(vector)]` and `BackendRepr::Memory`,
287- // no claims at `rustc`-understood SIMD whatsoever, would be enough?
288- // (i.e. only SPIR-V caring about such a type vs a struct/array)
289- providers. check_well_formed = |tcx, def_id| {
290- let trivial_struct = match tcx. hir_node_by_def_id ( def_id) {
291- rustc_hir:: Node :: Item ( item) => match item. kind {
292- rustc_hir:: ItemKind :: Struct (
293- _,
294- & rustc_hir:: Generics {
295- params :
296- & [ ]
297- | & [
298- rustc_hir:: GenericParam {
299- kind :
300- rustc_hir:: GenericParamKind :: Type {
301- default : None ,
302- synthetic : false ,
303- } ,
304- ..
305- } ,
306- ] ,
307- predicates : & [ ] ,
308- has_where_clause_predicates : false ,
309- where_clause_span : _,
310- span : _,
311- } ,
312- _,
313- ) => Some ( tcx. adt_def ( def_id) ) ,
314- _ => None ,
315- } ,
316- _ => None ,
317- } ;
318- let valid_non_array_simd_struct = trivial_struct. is_some_and ( |adt_def| {
319- let ReprOptions {
320- int : None ,
321- align : None ,
322- pack : None ,
323- flags : ReprFlags :: IS_SIMD ,
324- field_shuffle_seed : _,
325- } = adt_def. repr ( )
326- else {
327- return false ;
328- } ;
329- if adt_def. destructor ( tcx) . is_some ( ) {
330- return false ;
331- }
332-
333- let field_types = adt_def
334- . non_enum_variant ( )
335- . fields
336- . iter ( )
337- . map ( |f| tcx. type_of ( f. did ) . instantiate_identity ( ) ) ;
338- field_types. dedup ( ) . exactly_one ( ) . is_ok_and ( |elem_ty| {
339- matches ! (
340- elem_ty. kind( ) ,
341- ty:: Bool | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) | ty:: Param ( _)
342- )
343- } )
344- } ) ;
345-
346- if valid_non_array_simd_struct {
347- tcx. dcx ( )
348- . struct_span_warn (
349- tcx. def_span ( def_id) ,
350- "[Rust-GPU] temporarily re-allowing old-style `#[repr(simd)]` (with fields)" ,
351- )
352- . with_note ( "removed upstream by https://github.com/rust-lang/rust/pull/129403" )
353- . with_note ( "in favor of the new `#[repr(simd)] struct TxN([T; N]);` style" )
354- . with_note ( "(taking effect since `nightly-2024-09-12` / `1.83.0` stable)" )
355- . emit ( ) ;
356- return Ok ( ( ) ) ;
357- }
358-
359- ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . check_well_formed ) ( tcx, def_id)
360- } ;
361-
36299 // HACK(eddyb) work around https://github.com/rust-lang/rust/pull/132173
363100 // (and further changes from https://github.com/rust-lang/rust/pull/132843)
364101 // starting to ban SIMD ABI misuse (or at least starting to warn about it).
0 commit comments