about summary refs log tree commit diff
diff options
context:
space:
mode:
authorErik Desjardins <erikdesjardins@users.noreply.github.com>2023-06-14 22:39:11 -0400
committerErik Desjardins <erikdesjardins@users.noreply.github.com>2023-07-10 19:19:40 -0400
commitd1e764cb3bc961a4395164a36c4e0cfd57e681a1 (patch)
treef66ba35a8bc3c21616bb0845a74583147c918718
parent7e933b4e26947b04da70589110dacbdb2461e27d (diff)
downloadrust-d1e764cb3bc961a4395164a36c4e0cfd57e681a1.tar.gz
rust-d1e764cb3bc961a4395164a36c4e0cfd57e681a1.zip
aarch64-linux: properly handle 128bit aligned aggregates
-rw-r--r--compiler/rustc_abi/src/layout.rs57
-rw-r--r--compiler/rustc_abi/src/lib.rs22
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs1
-rw-r--r--compiler/rustc_target/src/abi/call/aarch64.rs70
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs10
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs5
-rw-r--r--tests/codegen/aarch64-struct-align-128.rs150
-rw-r--r--tests/run-make/extern-fn-explicit-align/test.c15
-rw-r--r--tests/run-make/extern-fn-explicit-align/test.rs14
-rw-r--r--tests/ui/layout/debug.stderr18
-rw-r--r--tests/ui/layout/hexagon-enum.stderr10
-rw-r--r--tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr17
-rw-r--r--tests/ui/layout/issue-96185-overaligned-enum.stderr6
-rw-r--r--tests/ui/layout/thumb-enum.stderr10
-rw-r--r--tests/ui/layout/zero-sized-array-enum-niche.stderr13
15 files changed, 370 insertions, 48 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index ff811be3c81..75c64aabfbb 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -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,
     })
 }
 
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index b1577add4d0..b2138dcefae 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -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,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index ffebbab04a6..843ea64fc29 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -756,6 +756,7 @@ where
                     align: tcx.data_layout.i8_align,
                     size: Size::ZERO,
                     repr_align: None,
+                    unadjusted_abi_align: tcx.data_layout.i8_align.abi,
                 })
             }
 
diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs
index a84988fa75c..b4c7b0f120f 100644
--- a/compiler/rustc_target/src/abi/call/aarch64.rs
+++ b/compiler/rustc_target/src/abi/call/aarch64.rs
@@ -1,25 +1,15 @@
 use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
 use crate::abi::{HasDataLayout, TyAbiInterface};
 
-/// Given integer-types M and register width N (e.g. M=u16 and N=32 bits), the
-/// `ParamExtension` policy specifies how a uM value should be treated when
-/// passed via register or stack-slot of width N. See also rust-lang/rust#97463.
+/// Indicates the variant of the AArch64 ABI we are compiling for.
+/// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI.
+///
+/// Corresponds to Clang's `AArch64ABIInfo::ABIKind`.
 #[derive(Copy, Clone, PartialEq)]
-pub enum ParamExtension {
-    /// Indicates that when passing an i8/i16, either as a function argument or
-    /// as a return value, it must be sign-extended to 32 bits, and likewise a
-    /// u8/u16 must be zero-extended to 32-bits. (This variant is here to
-    /// accommodate Apple's deviation from the usual AArch64 ABI as defined by
-    /// ARM.)
-    ///
-    /// See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
-    ExtendTo32Bits,
-
-    /// Indicates that no sign- nor zero-extension is performed: if a value of
-    /// type with bitwidth M is passed as function argument or return value,
-    /// then M bits are copied into the least significant M bits, and the
-    /// remaining bits of the register (or word of memory) are untouched.
-    NoExtension,
+pub enum AbiKind {
+    AAPCS,
+    DarwinPCS,
+    Win64,
 }
 
 fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
@@ -45,15 +35,17 @@ where
     })
 }
 
-fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension)
+fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout,
 {
     if !ret.layout.is_aggregate() {
-        match param_policy {
-            ParamExtension::ExtendTo32Bits => ret.extend_integer_width_to(32),
-            ParamExtension::NoExtension => {}
+        if kind == AbiKind::DarwinPCS {
+            // On Darwin, when returning an i8/i16, it must be sign-extended to 32 bits,
+            // and likewise a u8/u16 must be zero-extended to 32-bits.
+            // See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
+            ret.extend_integer_width_to(32)
         }
         return;
     }
@@ -70,15 +62,17 @@ where
     ret.make_indirect();
 }
 
-fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension)
+fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, kind: AbiKind)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout,
 {
     if !arg.layout.is_aggregate() {
-        match param_policy {
-            ParamExtension::ExtendTo32Bits => arg.extend_integer_width_to(32),
-            ParamExtension::NoExtension => {}
+        if kind == AbiKind::DarwinPCS {
+            // On Darwin, when passing an i8/i16, it must be sign-extended to 32 bits,
+            // and likewise a u8/u16 must be zero-extended to 32-bits.
+            // See also: <https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly>
+            arg.extend_integer_width_to(32);
         }
         return;
     }
@@ -87,27 +81,39 @@ where
         return;
     }
     let size = arg.layout.size;
-    let bits = size.bits();
-    if bits <= 128 {
-        arg.cast_to(Uniform { unit: Reg::i64(), total: size });
+    let align = if kind == AbiKind::AAPCS {
+        // When passing small aggregates by value, the AAPCS ABI mandates using the unadjusted
+        // alignment of the type (not including `repr(align)`).
+        // This matches behavior of `AArch64ABIInfo::classifyArgumentType` in Clang.
+        // See: <https://github.com/llvm/llvm-project/blob/5e691a1c9b0ad22689d4a434ddf4fed940e58dec/clang/lib/CodeGen/TargetInfo.cpp#L5816-L5823>
+        arg.layout.unadjusted_abi_align
+    } else {
+        arg.layout.align.abi
+    };
+    if size.bits() <= 128 {
+        if align.bits() == 128 {
+            arg.cast_to(Uniform { unit: Reg::i128(), total: size });
+        } else {
+            arg.cast_to(Uniform { unit: Reg::i64(), total: size });
+        }
         return;
     }
     arg.make_indirect();
 }
 
-pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, param_policy: ParamExtension)
+pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, kind: AbiKind)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout,
 {
     if !fn_abi.ret.is_ignore() {
-        classify_ret(cx, &mut fn_abi.ret, param_policy);
+        classify_ret(cx, &mut fn_abi.ret, kind);
     }
 
     for arg in fn_abi.args.iter_mut() {
         if arg.is_ignore() {
             continue;
         }
-        classify_arg(cx, arg, param_policy);
+        classify_arg(cx, arg, kind);
     }
 }
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index c4984936cac..03e7b3e7b40 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -679,12 +679,14 @@ impl<'a, Ty> FnAbi<'a, Ty> {
                 }
             },
             "aarch64" => {
-                let param_policy = if cx.target_spec().is_like_osx {
-                    aarch64::ParamExtension::ExtendTo32Bits
+                let kind = if cx.target_spec().is_like_osx {
+                    aarch64::AbiKind::DarwinPCS
+                } else if cx.target_spec().is_like_windows {
+                    aarch64::AbiKind::Win64
                 } else {
-                    aarch64::ParamExtension::NoExtension
+                    aarch64::AbiKind::AAPCS
                 };
-                aarch64::compute_abi_info(cx, self, param_policy)
+                aarch64::compute_abi_info(cx, self, kind)
             }
             "amdgpu" => amdgpu::compute_abi_info(cx, self),
             "arm" => arm::compute_abi_info(cx, self),
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 4fbc6b9400f..b8ab8baeedd 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -259,6 +259,7 @@ fn layout_of_uncached<'tcx>(
                 align: element.align,
                 size,
                 repr_align: None,
+                unadjusted_abi_align: element.align.abi,
             })
         }
         ty::Slice(element) => {
@@ -271,6 +272,7 @@ fn layout_of_uncached<'tcx>(
                 align: element.align,
                 size: Size::ZERO,
                 repr_align: None,
+                unadjusted_abi_align: element.align.abi,
             })
         }
         ty::Str => tcx.mk_layout(LayoutS {
@@ -281,6 +283,7 @@ fn layout_of_uncached<'tcx>(
             align: dl.i8_align,
             size: Size::ZERO,
             repr_align: None,
+            unadjusted_abi_align: dl.i8_align.abi,
         }),
 
         // Odd unit types.
@@ -435,6 +438,7 @@ fn layout_of_uncached<'tcx>(
                 size,
                 align,
                 repr_align: None,
+                unadjusted_abi_align: align.abi,
             })
         }
 
@@ -884,6 +888,7 @@ fn generator_layout<'tcx>(
         size,
         align,
         repr_align: None,
+        unadjusted_abi_align: align.abi,
     });
     debug!("generator layout ({:?}): {:#?}", ty, layout);
     Ok(layout)
diff --git a/tests/codegen/aarch64-struct-align-128.rs b/tests/codegen/aarch64-struct-align-128.rs
new file mode 100644
index 00000000000..bf34717786d
--- /dev/null
+++ b/tests/codegen/aarch64-struct-align-128.rs
@@ -0,0 +1,150 @@
+// Test that structs aligned to 128 bits are passed with the correct ABI on aarch64.
+
+// revisions:linux darwin windows
+//[linux] compile-flags: --target aarch64-unknown-linux-gnu
+//[darwin] compile-flags: --target aarch64-apple-darwin
+//[windows] compile-flags: --target aarch64-pc-windows-msvc
+//[linux] needs-llvm-components: aarch64
+//[darwin] needs-llvm-components: aarch64
+//[windows] needs-llvm-components: aarch64
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang="sized"]
+trait Sized { }
+#[lang="freeze"]
+trait Freeze { }
+#[lang="copy"]
+trait Copy { }
+
+
+
+// Passed as `[i64 x 2]`, since it's an aggregate with size <= 128 bits, align < 128 bits.
+#[repr(C)]
+pub struct Align8 {
+    pub a: u64,
+    pub b: u64,
+}
+
+// repr(transparent), so same as above.
+#[repr(transparent)]
+pub struct Transparent8 {
+    a: Align8
+}
+
+// Passed as `[i64 x 2]`, since it's an aggregate with size <= 128 bits, align < 128 bits.
+#[repr(C)]
+pub struct Wrapped8 {
+    a: Align8,
+}
+
+extern "C" {
+    // linux:   declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    // darwin:  declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    // windows: declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    fn test_8(a: Align8, b: Transparent8, c: Wrapped8);
+}
+
+
+
+// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits.
+// EXCEPT on Linux, where there's a special case to use its unadjusted alignment,
+// making it the same as `Align8`, so it's be passed as `[i64 x 2]`.
+#[repr(C)]
+#[repr(align(16))]
+pub struct Align16 {
+    pub a: u64,
+    pub b: u64,
+}
+
+// repr(transparent), so same as above.
+#[repr(transparent)]
+pub struct Transparent16 {
+    a: Align16
+}
+
+// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits.
+// On Linux, the "unadjustedness" doesn't recurse into fields, so this is passed as `i128`.
+#[repr(C)]
+pub struct Wrapped16 {
+    pub a: Align16,
+}
+
+extern "C" {
+    // linux:   declare void @test_16([2 x i64], [2 x i64], i128)
+    // darwin:  declare void @test_16(i128, i128, i128)
+    // windows: declare void @test_16(i128, i128, i128)
+    fn test_16(a: Align16, b: Transparent16, c: Wrapped16);
+}
+
+
+
+// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits.
+#[repr(C)]
+pub struct I128 {
+    pub a: i128,
+}
+
+// repr(transparent), so same as above.
+#[repr(transparent)]
+pub struct TransparentI128 {
+    a: I128
+}
+
+// Passed as `i128`, since it's an aggregate with size <= 128 bits, align = 128 bits.
+#[repr(C)]
+pub struct WrappedI128 {
+    pub a: I128
+}
+
+extern "C" {
+    // linux:   declare void @test_i128(i128, i128, i128)
+    // darwin:  declare void @test_i128(i128, i128, i128)
+    // windows: declare void @test_i128(i128, i128, i128)
+    fn test_i128(a: I128, b: TransparentI128, c: WrappedI128);
+}
+
+
+
+// Passed as `[2 x i64]`, since it's an aggregate with size <= 128 bits, align < 128 bits.
+// Note that the Linux special case does not apply, because packing is not considered "adjustment".
+#[repr(C)]
+#[repr(packed)]
+pub struct Packed {
+    pub a: i128,
+}
+
+// repr(transparent), so same as above.
+#[repr(transparent)]
+pub struct TransparentPacked {
+    a: Packed
+}
+
+// Passed as `[2 x i64]`, since it's an aggregate with size <= 128 bits, align < 128 bits.
+#[repr(C)]
+pub struct WrappedPacked {
+    pub a: Packed
+}
+
+extern "C" {
+    // linux:   declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
+    // darwin:  declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
+    // windows: declare void @test_packed([2 x i64], [2 x i64], [2 x i64])
+    fn test_packed(a: Packed, b: TransparentPacked, c: WrappedPacked);
+}
+
+
+
+pub unsafe fn main(
+    a1: Align8, a2: Transparent8, a3: Wrapped8,
+    b1: Align16, b2: Transparent16, b3: Wrapped16,
+    c1: I128, c2: TransparentI128, c3: WrappedI128,
+    d1: Packed, d2: TransparentPacked, d3: WrappedPacked,
+) {
+    test_8(a1, a2, a3);
+    test_16(b1, b2, b3);
+    test_i128(c1, c2, c3);
+    test_packed(d1, d2, d3);
+}
diff --git a/tests/run-make/extern-fn-explicit-align/test.c b/tests/run-make/extern-fn-explicit-align/test.c
index 292e7a822b5..8d20864326b 100644
--- a/tests/run-make/extern-fn-explicit-align/test.c
+++ b/tests/run-make/extern-fn-explicit-align/test.c
@@ -44,7 +44,12 @@ struct __attribute__((aligned(1))) LowerAlign
 };
 #endif
 
-
+#pragma pack(push, 1)
+struct Packed
+{
+    __uint128_t a;
+};
+#pragma pack(pop)
 
 int32_t many_args(
     void *a,
@@ -59,7 +64,9 @@ int32_t many_args(
     struct WrappedU64s j,
     void *k,
     struct LowerAlign l,
-    const char *m)
+    void *m,
+    struct Packed n,
+    const char *o)
 {
     assert(!a);
     assert(!b);
@@ -77,6 +84,8 @@ int32_t many_args(
     assert(!k);
     assert(l.a == 5);
     assert(l.b == 6);
-    assert(strcmp(m, "Hello world") == 0);
+    assert(!m);
+    assert(n.a == 7);
+    assert(strcmp(o, "Hello world") == 0);
     return 0;
 }
diff --git a/tests/run-make/extern-fn-explicit-align/test.rs b/tests/run-make/extern-fn-explicit-align/test.rs
index c5b3e24048e..56c6437dad2 100644
--- a/tests/run-make/extern-fn-explicit-align/test.rs
+++ b/tests/run-make/extern-fn-explicit-align/test.rs
@@ -34,6 +34,13 @@ pub struct LowerAlign {
     pub b: u64,
 }
 
+#[derive(Copy, Clone)]
+#[repr(C)]
+#[repr(packed)]
+pub struct Packed {
+    pub a: u128
+}
+
 #[link(name = "test", kind = "static")]
 extern "C" {
     fn many_args(
@@ -49,7 +56,9 @@ extern "C" {
         j: WrappedU64s,
         k: *mut (),
         l: LowerAlign,
-        m: *const c_char,
+        m: *mut (),
+        n: Packed,
+        o: *const c_char,
     ) -> i32;
 }
 
@@ -60,6 +69,7 @@ fn main() {
     let two_u64s = TwoU64s { a: 1, b: 2 };
     let wrapped = WrappedU64s { a: TwoU64s { a: 3, b: 4 } };
     let lower = LowerAlign { a: 5, b: 6 };
+    let packed = Packed { a: 7 };
     let string = STRING;
     unsafe {
         many_args(
@@ -75,6 +85,8 @@ fn main() {
             wrapped,
             null_mut(),
             lower,
+            null_mut(),
+            packed,
             string.as_ptr(),
         );
     }
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
index 99022fb11b5..1bf89d0dcb3 100644
--- a/tests/ui/layout/debug.stderr
+++ b/tests/ui/layout/debug.stderr
@@ -54,6 +54,7 @@ error: layout_of(E) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                    Layout {
                        size: Size(12 bytes),
@@ -79,10 +80,12 @@ error: layout_of(E) = Layout {
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/debug.rs:7:1
    |
@@ -128,6 +131,7 @@ error: layout_of(S) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/debug.rs:10:1
    |
@@ -151,6 +155,7 @@ error: layout_of(U) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/debug.rs:13:1
    |
@@ -243,6 +248,7 @@ error: layout_of(std::result::Result<i32, i32>) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                    Layout {
                        size: Size(8 bytes),
@@ -279,10 +285,12 @@ error: layout_of(std::result::Result<i32, i32>) = Layout {
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/debug.rs:16:1
    |
@@ -310,6 +318,7 @@ error: layout_of(i32) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/debug.rs:19:1
    |
@@ -333,6 +342,7 @@ error: layout_of(V) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(2 bytes),
        }
   --> $DIR/debug.rs:22:1
    |
@@ -356,6 +366,7 @@ error: layout_of(W) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(2 bytes),
        }
   --> $DIR/debug.rs:28:1
    |
@@ -379,6 +390,7 @@ error: layout_of(Y) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(2 bytes),
        }
   --> $DIR/debug.rs:34:1
    |
@@ -402,6 +414,7 @@ error: layout_of(P1) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/debug.rs:41:1
    |
@@ -425,6 +438,7 @@ error: layout_of(P2) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/debug.rs:45:1
    |
@@ -448,6 +462,7 @@ error: layout_of(P3) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/debug.rs:53:1
    |
@@ -471,6 +486,7 @@ error: layout_of(P4) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/debug.rs:57:1
    |
@@ -499,6 +515,7 @@ error: layout_of(P5) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/debug.rs:61:1
    |
@@ -527,6 +544,7 @@ error: layout_of(std::mem::MaybeUninit<u8>) = Layout {
                index: 0,
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/debug.rs:64:1
    |
diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr
index a907853585d..acc97672d3c 100644
--- a/tests/ui/layout/hexagon-enum.stderr
+++ b/tests/ui/layout/hexagon-enum.stderr
@@ -60,10 +60,12 @@ error: layout_of(A) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/hexagon-enum.rs:16:1
    |
@@ -132,10 +134,12 @@ error: layout_of(B) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/hexagon-enum.rs:20:1
    |
@@ -204,10 +208,12 @@ error: layout_of(C) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(2 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(2 bytes),
        }
   --> $DIR/hexagon-enum.rs:24:1
    |
@@ -276,10 +282,12 @@ error: layout_of(P) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/hexagon-enum.rs:28:1
    |
@@ -348,10 +356,12 @@ error: layout_of(T) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/hexagon-enum.rs:34:1
    |
diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
index 2db6ab9bc89..6e013af199d 100644
--- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
+++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
@@ -82,6 +82,7 @@ error: layout_of(MissingPayloadField) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                    Layout {
                        size: Size(1 bytes),
@@ -101,10 +102,12 @@ error: layout_of(MissingPayloadField) = Layout {
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:16:1
    |
@@ -197,6 +200,7 @@ error: layout_of(CommonPayloadField) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -233,10 +237,12 @@ error: layout_of(CommonPayloadField) = Layout {
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:25:1
    |
@@ -327,6 +333,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -362,10 +369,12 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:33:1
    |
@@ -472,6 +481,7 @@ error: layout_of(NicheFirst) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                    Layout {
                        size: Size(0 bytes),
@@ -491,6 +501,7 @@ error: layout_of(NicheFirst) = Layout {
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                    Layout {
                        size: Size(0 bytes),
@@ -510,10 +521,12 @@ error: layout_of(NicheFirst) = Layout {
                            index: 2,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:41:1
    |
@@ -620,6 +633,7 @@ error: layout_of(NicheSecond) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                    Layout {
                        size: Size(0 bytes),
@@ -639,6 +653,7 @@ error: layout_of(NicheSecond) = Layout {
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                    Layout {
                        size: Size(0 bytes),
@@ -658,10 +673,12 @@ error: layout_of(NicheSecond) = Layout {
                            index: 2,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/issue-96158-scalarpair-payload-might-be-uninit.rs:50:1
    |
diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr
index 3a0ad07347d..ef6cc79eedb 100644
--- a/tests/ui/layout/issue-96185-overaligned-enum.stderr
+++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr
@@ -56,6 +56,7 @@ error: layout_of(Aligned1) = Layout {
                        repr_align: Some(
                            Align(8 bytes),
                        ),
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                    Layout {
                        size: Size(8 bytes),
@@ -77,12 +78,14 @@ error: layout_of(Aligned1) = Layout {
                        repr_align: Some(
                            Align(8 bytes),
                        ),
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: Some(
                Align(8 bytes),
            ),
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/issue-96185-overaligned-enum.rs:8:1
    |
@@ -153,6 +156,7 @@ error: layout_of(Aligned2) = Layout {
                        repr_align: Some(
                            Align(1 bytes),
                        ),
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                    Layout {
                        size: Size(1 bytes),
@@ -174,12 +178,14 @@ error: layout_of(Aligned2) = Layout {
                        repr_align: Some(
                            Align(1 bytes),
                        ),
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: Some(
                Align(1 bytes),
            ),
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/issue-96185-overaligned-enum.rs:16:1
    |
diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr
index 27bba72fcfe..c1837b0e47e 100644
--- a/tests/ui/layout/thumb-enum.stderr
+++ b/tests/ui/layout/thumb-enum.stderr
@@ -60,10 +60,12 @@ error: layout_of(A) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/thumb-enum.rs:16:1
    |
@@ -132,10 +134,12 @@ error: layout_of(B) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(1 bytes),
        }
   --> $DIR/thumb-enum.rs:20:1
    |
@@ -204,10 +208,12 @@ error: layout_of(C) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(2 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(2 bytes),
        }
   --> $DIR/thumb-enum.rs:24:1
    |
@@ -276,10 +282,12 @@ error: layout_of(P) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/thumb-enum.rs:28:1
    |
@@ -348,10 +356,12 @@ error: layout_of(T) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/thumb-enum.rs:34:1
    |
diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr
index a9a242943ba..02bf9d496bc 100644
--- a/tests/ui/layout/zero-sized-array-enum-niche.stderr
+++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr
@@ -58,6 +58,7 @@ error: layout_of(std::result::Result<[u32; 0], bool>) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -90,10 +91,12 @@ error: layout_of(std::result::Result<[u32; 0], bool>) = Layout {
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/zero-sized-array-enum-niche.rs:13:1
    |
@@ -160,6 +163,7 @@ error: layout_of(MultipleAlignments) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(2 bytes),
                    },
                    Layout {
                        size: Size(4 bytes),
@@ -183,6 +187,7 @@ error: layout_of(MultipleAlignments) = Layout {
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -215,10 +220,12 @@ error: layout_of(MultipleAlignments) = Layout {
                            index: 2,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/zero-sized-array-enum-niche.rs:21:1
    |
@@ -285,6 +292,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed<std::num::NonZeroU16>>) =
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                    Layout {
                        size: Size(3 bytes),
@@ -317,10 +325,12 @@ error: layout_of(std::result::Result<[u32; 0], Packed<std::num::NonZeroU16>>) =
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/zero-sized-array-enum-niche.rs:37:1
    |
@@ -391,6 +401,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed<U16IsZero>>) = Layout {
                            index: 0,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
                    },
                    Layout {
                        size: Size(2 bytes),
@@ -423,10 +434,12 @@ error: layout_of(std::result::Result<[u32; 0], Packed<U16IsZero>>) = Layout {
                            index: 1,
                        },
                        repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
                    },
                ],
            },
            repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
        }
   --> $DIR/zero-sized-array-enum-niche.rs:44:1
    |