1
Fork 0

Rollup merge of #137256 - workingjubilee:untangle-vector-abi-assumptions, r=bjorn3,RalfJung

compiler: untangle SIMD alignment assumptions

There were a number of puzzling assumptions being made about SIMD types and their layout that I have corrected in this diff. These are mostly no-op edits in actual fact, but they do subtly alter a pair of checks in our invariant-checking and union layout computation that rested on those peculiar assumptions. Those unfortunately stand in the way of any further actual fixes. I submit this for review, even though it's not clearly motivated without its followups, because it should still be possible to independently conclude whether this is correct.
This commit is contained in:
Matthias Krüger 2025-02-23 00:16:19 +01:00 committed by GitHub
commit 86008eaeac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 108 additions and 86 deletions

View file

@ -547,12 +547,15 @@ fn layout_of_uncached<'tcx>(
(
BackendRepr::Memory { sized: true },
AbiAndPrefAlign {
abi: Align::max_for_offset(size),
pref: dl.vector_align(size).pref,
abi: Align::max_aligned_factor(size),
pref: dl.llvmlike_vector_align(size).pref,
},
)
} else {
(BackendRepr::Vector { element: e_abi, count: e_len }, dl.vector_align(size))
(
BackendRepr::Vector { element: e_abi, count: e_len },
dl.llvmlike_vector_align(size),
)
};
let size = size.align_to(align.abi);

View file

@ -69,31 +69,30 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
}
fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
// Verify the ABI mandated alignment and size.
let align = layout.backend_repr.inherent_align(cx).map(|align| align.abi);
let size = layout.backend_repr.inherent_size(cx);
let Some((align, size)) = align.zip(size) else {
assert_matches!(
layout.layout.backend_repr(),
BackendRepr::Memory { .. },
"ABI unexpectedly missing alignment and/or size in {layout:#?}"
// Verify the ABI-mandated alignment and size for scalars.
let align = layout.backend_repr.scalar_align(cx);
let size = layout.backend_repr.scalar_size(cx);
if let Some(align) = align {
assert_eq!(
layout.layout.align().abi,
align,
"alignment mismatch between ABI and layout in {layout:#?}"
);
return;
};
assert_eq!(
layout.layout.align().abi,
align,
"alignment mismatch between ABI and layout in {layout:#?}"
);
assert_eq!(
layout.layout.size(),
size,
"size mismatch between ABI and layout in {layout:#?}"
);
}
if let Some(size) = size {
assert_eq!(
layout.layout.size(),
size,
"size mismatch between ABI and layout in {layout:#?}"
);
}
// Verify per-ABI invariants
match layout.layout.backend_repr() {
BackendRepr::Scalar(_) => {
// These must always be present for `Scalar` types.
let align = align.unwrap();
let size = size.unwrap();
// Check that this matches the underlying field.
let inner = skip_newtypes(cx, layout);
assert!(
@ -235,9 +234,15 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
"`ScalarPair` second field with bad ABI in {inner:#?}",
);
}
BackendRepr::Vector { element, .. } => {
assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`.
// FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair.
BackendRepr::Vector { element, count } => {
let align = layout.align.abi;
let size = layout.size;
let element_align = element.align(cx).abi;
let element_size = element.size(cx);
// Currently, vectors must always be aligned to at least their elements:
assert!(align >= element_align);
// And the size has to be element * count plus alignment padding, of course
assert!(size == (element_size * count).align_to(align));
}
BackendRepr::Memory { .. } => {} // Nothing to check.
}