Skip to content

Commit aa8292c

Browse files
committed
abi layout: remove #[repr(SIMD)] hack
1 parent 3356218 commit aa8292c

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};
@@ -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

Comments
 (0)