Skip to content

Commit 807ea93

Browse files
committed
abi layout: remove #[repr(SIMD)] hack
1 parent bf899ed commit 807ea93

File tree

1 file changed

+1
-264
lines changed
  • crates/rustc_codegen_spirv/src

1 file changed

+1
-264
lines changed

crates/rustc_codegen_spirv/src/abi.rs

Lines changed: 1 addition & 264 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@ use itertools::Itertools;
88
use rspirv::spirv::{Dim, ImageFormat, StorageClass, Word};
99
use rustc_abi::ExternAbi as Abi;
1010
use 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
};
1413
use rustc_data_structures::fx::FxHashMap;
1514
use rustc_errors::ErrorGuaranteed;
16-
use rustc_hashes::Hash64;
1715
use rustc_index::Idx;
1816
use rustc_middle::query::Providers;
1917
use 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

Comments
 (0)