Skip to content

Commit 5c474fd

Browse files
compiler: BackendRepr::inherent_{size,align} -> scalar_{size,align}
This pair of fn was introduced to perform invariant checks for scalars. Their current behavior doesn't mesh as well with checking SIMD types, so change the name of the fn to reflect their actual use-case and refactor the corresponding checks. Also simplify the returns from Option<AbiAndPrefAlign> to Option<Align>, because every site was mapping away the "preferred" alignment anyways.
1 parent efff15a commit 5c474fd

File tree

3 files changed

+78
-63
lines changed

3 files changed

+78
-63
lines changed

compiler/rustc_abi/src/layout.rs

+23-14
Original file line numberDiff line numberDiff line change
@@ -310,10 +310,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
310310
let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
311311
let mut max_repr_align = repr.align;
312312

313-
// If all the non-ZST fields have the same ABI and union ABI optimizations aren't
314-
// disabled, we can use that common ABI for the union as a whole.
313+
// If all the non-ZST fields have the same repr and union repr optimizations aren't
314+
// disabled, we can use that common repr for the union as a whole.
315315
struct AbiMismatch;
316-
let mut common_non_zst_abi_and_align = if repr.inhibits_union_abi_opt() {
316+
let mut common_non_zst_repr_and_align = if repr.inhibits_union_abi_opt() {
317317
// Can't optimize
318318
Err(AbiMismatch)
319319
} else {
@@ -337,14 +337,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
337337
continue;
338338
}
339339

340-
if let Ok(common) = common_non_zst_abi_and_align {
340+
if let Ok(common) = common_non_zst_repr_and_align {
341341
// Discard valid range information and allow undef
342342
let field_abi = field.backend_repr.to_union();
343343

344344
if let Some((common_abi, common_align)) = common {
345345
if common_abi != field_abi {
346346
// Different fields have different ABI: disable opt
347-
common_non_zst_abi_and_align = Err(AbiMismatch);
347+
common_non_zst_repr_and_align = Err(AbiMismatch);
348348
} else {
349349
// Fields with the same non-Aggregate ABI should also
350350
// have the same alignment
@@ -357,7 +357,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
357357
}
358358
} else {
359359
// First non-ZST field: record its ABI and alignment
360-
common_non_zst_abi_and_align = Ok(Some((field_abi, field.align.abi)));
360+
common_non_zst_repr_and_align = Ok(Some((field_abi, field.align.abi)));
361361
}
362362
}
363363
}
@@ -376,16 +376,25 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
376376

377377
// If all non-ZST fields have the same ABI, we may forward that ABI
378378
// for the union as a whole, unless otherwise inhibited.
379-
let abi = match common_non_zst_abi_and_align {
379+
let backend_repr = match common_non_zst_repr_and_align {
380380
Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true },
381-
Ok(Some((abi, _))) => {
382-
if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) {
383-
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
381+
Ok(Some((repr, _))) => match repr {
382+
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
383+
BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _)
384+
if repr.scalar_align(dl).unwrap() != align.abi =>
385+
{
384386
BackendRepr::Memory { sized: true }
385-
} else {
386-
abi
387387
}
388-
}
388+
// Vectors require at least element alignment, else disable the opt
389+
BackendRepr::Vector { element, count: _ } if element.align(dl).abi > align.abi => {
390+
BackendRepr::Memory { sized: true }
391+
}
392+
// the alignment tests passed and we can use this
393+
BackendRepr::Scalar(..)
394+
| BackendRepr::ScalarPair(..)
395+
| BackendRepr::Vector { .. }
396+
| BackendRepr::Memory { .. } => repr,
397+
},
389398
};
390399

391400
let Some(union_field_count) = NonZeroUsize::new(only_variant.len()) else {
@@ -400,7 +409,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
400409
Ok(LayoutData {
401410
variants: Variants::Single { index: only_variant_idx },
402411
fields: FieldsShape::Union(union_field_count),
403-
backend_repr: abi,
412+
backend_repr,
404413
largest_niche: None,
405414
uninhabited: false,
406415
align,

compiler/rustc_abi/src/lib.rs

+27-26
Original file line numberDiff line numberDiff line change
@@ -1454,37 +1454,38 @@ impl BackendRepr {
14541454
matches!(*self, BackendRepr::Scalar(s) if s.is_bool())
14551455
}
14561456

1457-
/// Returns the fixed alignment of this ABI, if any is mandated.
1458-
pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
1459-
Some(match *self {
1460-
BackendRepr::Scalar(s) => s.align(cx),
1461-
BackendRepr::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)),
1462-
BackendRepr::Vector { element, count } => {
1463-
cx.data_layout().vector_align(element.size(cx) * count)
1464-
}
1465-
BackendRepr::Memory { .. } => return None,
1466-
})
1457+
/// The psABI alignment for a `Scalar` or `ScalarPair`
1458+
///
1459+
/// `None` for other variants.
1460+
pub fn scalar_align<C: HasDataLayout>(&self, cx: &C) -> Option<Align> {
1461+
match *self {
1462+
BackendRepr::Scalar(s) => Some(s.align(cx).abi),
1463+
BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi),
1464+
// The align of a Vector can vary in surprising ways
1465+
BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => None,
1466+
}
14671467
}
14681468

1469-
/// Returns the fixed size of this ABI, if any is mandated.
1470-
pub fn inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
1471-
Some(match *self {
1472-
BackendRepr::Scalar(s) => {
1473-
// No padding in scalars.
1474-
s.size(cx)
1475-
}
1469+
/// The psABI size for a `Scalar` or `ScalarPair`
1470+
///
1471+
/// `None` for other variants
1472+
pub fn scalar_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
1473+
match *self {
1474+
// No padding in scalars.
1475+
BackendRepr::Scalar(s) => Some(s.size(cx)),
1476+
// May have some padding between the pair.
14761477
BackendRepr::ScalarPair(s1, s2) => {
1477-
// May have some padding between the pair.
14781478
let field2_offset = s1.size(cx).align_to(s2.align(cx).abi);
1479-
(field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi)
1480-
}
1481-
BackendRepr::Vector { element, count } => {
1482-
// No padding in vectors, except possibly for trailing padding
1483-
// to make the size a multiple of align (e.g. for vectors of size 3).
1484-
(element.size(cx) * count).align_to(self.inherent_align(cx)?.abi)
1479+
let size = (field2_offset + s2.size(cx)).align_to(
1480+
self.scalar_align(cx)
1481+
// We absolutely must have an answer here or everything is FUBAR.
1482+
.unwrap(),
1483+
);
1484+
Some(size)
14851485
}
1486-
BackendRepr::Memory { .. } => return None,
1487-
})
1486+
// The size of a Vector can vary in surprising ways
1487+
BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => None,
1488+
}
14881489
}
14891490

14901491
/// Discard validity range information and allow undef.

compiler/rustc_ty_utils/src/layout/invariant.rs

+28-23
Original file line numberDiff line numberDiff line change
@@ -69,31 +69,30 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
6969
}
7070

7171
fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) {
72-
// Verify the ABI mandated alignment and size.
73-
let align = layout.backend_repr.inherent_align(cx).map(|align| align.abi);
74-
let size = layout.backend_repr.inherent_size(cx);
75-
let Some((align, size)) = align.zip(size) else {
76-
assert_matches!(
77-
layout.layout.backend_repr(),
78-
BackendRepr::Memory { .. },
79-
"ABI unexpectedly missing alignment and/or size in {layout:#?}"
72+
// Verify the ABI-mandated alignment and size for scalars.
73+
let align = layout.backend_repr.scalar_align(cx);
74+
let size = layout.backend_repr.scalar_size(cx);
75+
if let Some(align) = align {
76+
assert_eq!(
77+
layout.layout.align().abi,
78+
align,
79+
"alignment mismatch between ABI and layout in {layout:#?}"
8080
);
81-
return;
82-
};
83-
assert_eq!(
84-
layout.layout.align().abi,
85-
align,
86-
"alignment mismatch between ABI and layout in {layout:#?}"
87-
);
88-
assert_eq!(
89-
layout.layout.size(),
90-
size,
91-
"size mismatch between ABI and layout in {layout:#?}"
92-
);
81+
}
82+
if let Some(size) = size {
83+
assert_eq!(
84+
layout.layout.size(),
85+
size,
86+
"size mismatch between ABI and layout in {layout:#?}"
87+
);
88+
}
9389

9490
// Verify per-ABI invariants
9591
match layout.layout.backend_repr() {
9692
BackendRepr::Scalar(_) => {
93+
// These must always be present for `Scalar` types.
94+
let align = align.unwrap();
95+
let size = size.unwrap();
9796
// Check that this matches the underlying field.
9897
let inner = skip_newtypes(cx, layout);
9998
assert!(
@@ -235,9 +234,15 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
235234
"`ScalarPair` second field with bad ABI in {inner:#?}",
236235
);
237236
}
238-
BackendRepr::Vector { element, .. } => {
239-
assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`.
240-
// FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair.
237+
BackendRepr::Vector { element, count } => {
238+
let align = layout.align.abi;
239+
let size = layout.size;
240+
let element_align = element.align(cx).abi;
241+
let element_size = element.size(cx);
242+
// Currently, vectors must always be aligned to at least their elements:
243+
assert!(align >= element_align);
244+
// And the size has to be element * count plus alignment padding, of course
245+
assert!(size == (element_size * count).align_to(align));
241246
}
242247
BackendRepr::Memory { .. } => {} // Nothing to check.
243248
}

0 commit comments

Comments
 (0)