1
Fork 0

aarch64-linux: properly handle 128bit aligned aggregates

This commit is contained in:
Erik Desjardins 2023-06-14 22:39:11 -04:00
parent 7e933b4e26
commit d1e764cb3b
15 changed files with 370 additions and 48 deletions

View file

@ -41,6 +41,7 @@ pub trait LayoutCalculator {
align,
size,
repr_align: None,
unadjusted_abi_align: align.abi,
}
}
@ -124,6 +125,7 @@ pub trait LayoutCalculator {
align: dl.i8_align,
size: Size::ZERO,
repr_align: None,
unadjusted_abi_align: dl.i8_align.abi,
}
}
@ -291,6 +293,8 @@ pub trait LayoutCalculator {
}
let mut align = dl.aggregate_align;
let mut unadjusted_abi_align = align.abi;
let mut variant_layouts = variants
.iter_enumerated()
.map(|(j, v)| {
@ -298,6 +302,7 @@ pub trait LayoutCalculator {
st.variants = Variants::Single { index: j };
align = align.max(st.align);
unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align);
Some(st)
})
@ -425,6 +430,7 @@ pub trait LayoutCalculator {
size,
align,
repr_align: repr.align,
unadjusted_abi_align,
};
Some(TmpLayout { layout, variants: variant_layouts })
@ -459,6 +465,8 @@ pub trait LayoutCalculator {
let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max);
let mut align = dl.aggregate_align;
let mut unadjusted_abi_align = align.abi;
let mut size = Size::ZERO;
// We're interested in the smallest alignment, so start large.
@ -501,6 +509,7 @@ pub trait LayoutCalculator {
}
size = cmp::max(size, st.size);
align = align.max(st.align);
unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align);
Some(st)
})
.collect::<Option<IndexVec<VariantIdx, _>>>()?;
@ -695,6 +704,7 @@ pub trait LayoutCalculator {
align,
size,
repr_align: repr.align,
unadjusted_abi_align,
};
let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants };
@ -735,10 +745,6 @@ pub trait LayoutCalculator {
let dl = dl.borrow();
let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
if let Some(repr_align) = repr.align {
align = align.max(AbiAndPrefAlign::new(repr_align));
}
// If all the non-ZST fields have the same ABI and union ABI optimizations aren't
// disabled, we can use that common ABI for the union as a whole.
struct AbiMismatch;
@ -791,6 +797,14 @@ pub trait LayoutCalculator {
if let Some(pack) = repr.pack {
align = align.min(AbiAndPrefAlign::new(pack));
}
// The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
// See documentation on `LayoutS::unadjusted_abi_align`.
let unadjusted_abi_align = align.abi;
if let Some(repr_align) = repr.align {
align = align.max(AbiAndPrefAlign::new(repr_align));
}
// `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate.
let align = align;
// If all non-ZST fields have the same ABI, we may forward that ABI
// for the union as a whole, unless otherwise inhibited.
@ -814,6 +828,7 @@ pub trait LayoutCalculator {
align,
size: size.align_to(align.abi),
repr_align: repr.align,
unadjusted_abi_align,
})
}
}
@ -1023,9 +1038,16 @@ fn univariant(
offset = offset.checked_add(field.size(), dl)?;
}
// The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
// See documentation on `LayoutS::unadjusted_abi_align`.
let unadjusted_abi_align = align.abi;
if let Some(repr_align) = repr.align {
align = align.max(AbiAndPrefAlign::new(repr_align));
}
// `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate.
let align = align;
debug!("univariant min_size: {:?}", offset);
let min_size = offset;
// As stated above, inverse_memory_index holds field indices by increasing offset.
@ -1111,9 +1133,29 @@ fn univariant(
abi = Abi::Uninhabited;
}
let repr_align = repr.align.or_else(|| {
if repr.transparent() { layout_of_single_non_zst_field?.repr_align() } else { None }
});
let (repr_align, unadjusted_abi_align) = if repr.transparent() {
match layout_of_single_non_zst_field {
Some(l) => (l.repr_align(), l.unadjusted_abi_align()),
None => {
// `repr(transparent)` with all ZST fields.
//
// Using `None` for `repr_align` here is technically incorrect, since one of
// the ZSTs could have `repr(align(1))`. It's an interesting question, if you have
// `#{repr(transparent)] struct Foo((), ZstWithReprAlign1)`, which of those ZSTs'
// ABIs is forwarded by `repr(transparent)`? The answer to that question determines
// whether we should use `None` or `Some(align 1)` here. Thanksfully, two things
// together mean this doesn't matter:
// - You're not allowed to have a `repr(transparent)` struct that contains
// `repr(align)` > 1 ZSTs. See error E0691.
// - MSVC never treats requested align 1 differently from natural align 1.
// (And the `repr_align` field is only used on i686-windows, see `LayoutS` docs.)
// So just use `None` for now.
(None, align.abi)
}
}
} else {
(repr.align, unadjusted_abi_align)
};
Some(LayoutS {
variants: Variants::Single { index: FIRST_VARIANT },
@ -1123,6 +1165,7 @@ fn univariant(
align,
size,
repr_align,
unadjusted_abi_align,
})
}

View file

@ -1536,6 +1536,11 @@ pub struct LayoutS {
/// Only used on i686-windows, where the argument passing ABI is different when alignment is
/// requested, even if the requested alignment is equal to the natural alignment.
pub repr_align: Option<Align>,
/// The alignment the type would have, ignoring any `repr(align)` but including `repr(packed)`.
/// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment
/// in some cases.
pub unadjusted_abi_align: Align,
}
impl LayoutS {
@ -1551,6 +1556,7 @@ impl LayoutS {
size,
align,
repr_align: None,
unadjusted_abi_align: align.abi,
}
}
}
@ -1560,7 +1566,16 @@ impl fmt::Debug for LayoutS {
// This is how `Layout` used to print before it become
// `Interned<LayoutS>`. We print it like this to avoid having to update
// expected output in a lot of tests.
let LayoutS { size, align, abi, fields, largest_niche, variants, repr_align } = self;
let LayoutS {
size,
align,
abi,
fields,
largest_niche,
variants,
repr_align,
unadjusted_abi_align,
} = self;
f.debug_struct("Layout")
.field("size", size)
.field("align", align)
@ -1569,6 +1584,7 @@ impl fmt::Debug for LayoutS {
.field("largest_niche", largest_niche)
.field("variants", variants)
.field("repr_align", repr_align)
.field("unadjusted_abi_align", unadjusted_abi_align)
.finish()
}
}
@ -1613,6 +1629,10 @@ impl<'a> Layout<'a> {
self.0.0.repr_align
}
pub fn unadjusted_abi_align(self) -> Align {
self.0.0.unadjusted_abi_align
}
/// Whether the layout is from a type that implements [`std::marker::PointerLike`].
///
/// Currently, that means that the type is pointer-sized, pointer-aligned,