Skip to content

Commit 7526678

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 8cf4c76 commit 7526678

File tree

3 files changed

+73
-64
lines changed

3 files changed

+73
-64
lines changed

compiler/rustc_abi/src/layout.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -308,10 +308,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
308308
let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
309309
let mut max_repr_align = repr.align;
310310

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

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

342342
if let Some((common_abi, common_align)) = common {
343343
if common_abi != field_abi {
344344
// Different fields have different ABI: disable opt
345-
common_non_zst_abi_and_align = Err(AbiMismatch);
345+
common_non_zst_repr_and_align = Err(AbiMismatch);
346346
} else {
347347
// Fields with the same non-Aggregate ABI should also
348348
// have the same alignment
@@ -355,7 +355,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
355355
}
356356
} else {
357357
// First non-ZST field: record its ABI and alignment
358-
common_non_zst_abi_and_align = Ok(Some((field_abi, field.align.abi)));
358+
common_non_zst_repr_and_align = Ok(Some((field_abi, field.align.abi)));
359359
}
360360
}
361361
}
@@ -374,16 +374,15 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
374374

375375
// If all non-ZST fields have the same ABI, we may forward that ABI
376376
// for the union as a whole, unless otherwise inhibited.
377-
let abi = match common_non_zst_abi_and_align {
377+
let backend_repr = match common_non_zst_repr_and_align {
378378
Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true },
379-
Ok(Some((abi, _))) => {
380-
if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) {
381-
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
382-
BackendRepr::Memory { sized: true }
383-
} else {
384-
abi
385-
}
379+
Ok(Some((repr, _)))
380+
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
381+
if repr.scalar_align(dl).is_some_and(|scalar_align| scalar_align != align.abi) =>
382+
{
383+
BackendRepr::Memory { sized: true }
386384
}
385+
Ok(Some((repr, _))) => repr,
387386
};
388387

389388
let Some(union_field_count) = NonZeroUsize::new(only_variant.len()) else {
@@ -398,7 +397,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
398397
Ok(LayoutData {
399398
variants: Variants::Single { index: only_variant_idx },
400399
fields: FieldsShape::Union(union_field_count),
401-
backend_repr: abi,
400+
backend_repr,
402401
largest_niche: None,
403402
align,
404403
size: size.align_to(align.abi),

compiler/rustc_abi/src/lib.rs

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,37 +1462,42 @@ impl BackendRepr {
14621462
matches!(*self, BackendRepr::Scalar(s) if s.is_bool())
14631463
}
14641464

1465-
/// Returns the fixed alignment of this ABI, if any is mandated.
1466-
pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
1467-
Some(match *self {
1468-
BackendRepr::Scalar(s) => s.align(cx),
1469-
BackendRepr::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)),
1470-
BackendRepr::Vector { element, count } => {
1471-
cx.data_layout().vector_align(element.size(cx) * count)
1472-
}
1473-
BackendRepr::Uninhabited | BackendRepr::Memory { .. } => return None,
1474-
})
1465+
/// The psABI alignment for a `Scalar` or `ScalarPair`
1466+
///
1467+
/// `None` for other variants.
1468+
pub fn scalar_align<C: HasDataLayout>(&self, cx: &C) -> Option<Align> {
1469+
match *self {
1470+
BackendRepr::Scalar(s) => Some(s.align(cx).abi),
1471+
BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi),
1472+
// The align of a Vector can vary in surprising ways
1473+
BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => None,
1474+
// FIXME: rebased away soon
1475+
BackendRepr::Uninhabited => None,
1476+
}
14751477
}
14761478

1477-
/// Returns the fixed size of this ABI, if any is mandated.
1478-
pub fn inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
1479-
Some(match *self {
1480-
BackendRepr::Scalar(s) => {
1481-
// No padding in scalars.
1482-
s.size(cx)
1483-
}
1479+
/// The psABI size for a `Scalar` or `ScalarPair`
1480+
///
1481+
/// `None` for other variants
1482+
pub fn scalar_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
1483+
match *self {
1484+
// No padding in scalars.
1485+
BackendRepr::Scalar(s) => Some(s.size(cx)),
1486+
// May have some padding between the pair.
14841487
BackendRepr::ScalarPair(s1, s2) => {
1485-
// May have some padding between the pair.
14861488
let field2_offset = s1.size(cx).align_to(s2.align(cx).abi);
1487-
(field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi)
1488-
}
1489-
BackendRepr::Vector { element, count } => {
1490-
// No padding in vectors, except possibly for trailing padding
1491-
// to make the size a multiple of align (e.g. for vectors of size 3).
1492-
(element.size(cx) * count).align_to(self.inherent_align(cx)?.abi)
1489+
let size = (field2_offset + s2.size(cx)).align_to(
1490+
self.scalar_align(cx)
1491+
// We absolutely must have an answer here or everything is FUBAR.
1492+
.unwrap(),
1493+
);
1494+
Some(size)
14931495
}
1494-
BackendRepr::Uninhabited | BackendRepr::Memory { .. } => return None,
1495-
})
1496+
// The size of a Vector can vary in surprising ways
1497+
BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => None,
1498+
// FIXME: rebased away soon
1499+
BackendRepr::Uninhabited => None,
1500+
}
14961501
}
14971502

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

compiler/rustc_ty_utils/src/layout/invariant.rs

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -65,31 +65,30 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
6565
}
6666

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

9086
// Verify per-ABI invariants
9187
match layout.layout.backend_repr() {
9288
BackendRepr::Scalar(_) => {
89+
// we already asserted this
90+
let align = align.unwrap();
91+
let size = size.unwrap();
9392
// Check that this matches the underlying field.
9493
let inner = skip_newtypes(cx, layout);
9594
assert!(
@@ -231,9 +230,15 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou
231230
"`ScalarPair` second field with bad ABI in {inner:#?}",
232231
);
233232
}
234-
BackendRepr::Vector { element, .. } => {
235-
assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`.
236-
// FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair.
233+
BackendRepr::Vector { element, count } => {
234+
let align = layout.align.abi;
235+
let size = layout.size;
236+
let element_align = element.align(cx).abi;
237+
let element_size = element.size(cx);
238+
// Currently, vectors must always be aligned to at least their elements:
239+
assert!(align >= element_align);
240+
// And the size has to be element * count, of course
241+
assert!(size >= (element_size * count).align_to(align));
237242
}
238243
BackendRepr::Uninhabited | BackendRepr::Memory { .. } => {} // Nothing to check.
239244
}

0 commit comments

Comments
 (0)