about summary refs log tree commit diff
path: root/tests/codegen
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-07-15 15:39:53 +0000
committerbors <bors@rust-lang.org>2023-07-15 15:39:53 +0000
commit7a17f577b3d437179cad254e299b2ace972487c5 (patch)
tree6c1565afdbbe5f37d83baa68351a9cf6982f0148 /tests/codegen
parent4d6e4260b2de66a356a2536320f339467dff0d2b (diff)
parent2daacf5af965090b885287f1d40e13ff5db724cf (diff)
downloadrust-7a17f577b3d437179cad254e299b2ace972487c5.tar.gz
rust-7a17f577b3d437179cad254e299b2ace972487c5.zip
Auto merge of #112157 - erikdesjardins:align, r=nikic
Resurrect: rustc_target: Add alignment to indirectly-passed by-value types, correcting the alignment of byval on x86 in the process.

Same as #111551, which I [accidentally closed](https://github.com/rust-lang/rust/pull/111551#issuecomment-1571222612) :/

---

This resurrects PR #103830, which has sat idle for a while.

Beyond #103830, this also:
- fixes byval alignment for types containing vectors on Darwin (see `tests/codegen/align-byval-vector.rs`)
- fixes byval alignment for overaligned types on x86 Windows (see `tests/codegen/align-byval.rs`)
- fixes ABI for types with 128bit requested alignment on ARM64 Linux (see `tests/codegen/aarch64-struct-align-128.rs`)

r? `@nikic`

---

`@pcwalton's` original PR description is reproduced below:

Commit 88e4d2c from five years ago removed
support for alignment on indirectly-passed arguments because of problems with
the `i686-pc-windows-msvc` target. Unfortunately, the `memcpy` optimizations I
recently added to LLVM 16 depend on this to forward `memcpy`s. This commit
attempts to fix the problems with `byval` parameters on that target and now
correctly adds the `align` attribute.

The problem is summarized in [this comment] by `@eddyb.` Briefly, 32-bit x86 has
special alignment rules for `byval` parameters: for the most part, their
alignment is forced to 4. This is not well-documented anywhere but in the Clang
source. I looked at the logic in Clang `TargetInfo.cpp` and tried to replicate
it here. The relevant methods in that file are
`X86_32ABIInfo::getIndirectResult()` and
`X86_32ABIInfo::getTypeStackAlignInBytes()`. The `align` parameter attribute
for `byval` parameters in LLVM must match the platform ABI, or miscompilations
will occur. Note that this doesn't use the approach suggested by eddyb, because
I felt it was overkill to store the alignment in `on_stack` when special
handling is really only needed for 32-bit x86.

As a side effect, this should fix #80127, because it will make the `align`
parameter attribute for `byval` parameters match the platform ABI on LLVM
x86-64.

[this comment]: #80822 (comment)
Diffstat (limited to 'tests/codegen')
-rw-r--r--tests/codegen/aarch64-struct-align-128.rs150
-rw-r--r--tests/codegen/addr-of-mutate.rs6
-rw-r--r--tests/codegen/align-byval-vector.rs58
-rw-r--r--tests/codegen/align-byval.rs342
-rw-r--r--tests/codegen/array-map.rs1
-rw-r--r--tests/codegen/function-arguments-noopt.rs4
-rw-r--r--tests/codegen/function-arguments.rs4
7 files changed, 557 insertions, 8 deletions
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/codegen/addr-of-mutate.rs b/tests/codegen/addr-of-mutate.rs
index bea1aad2352..6dfc1825015 100644
--- a/tests/codegen/addr-of-mutate.rs
+++ b/tests/codegen/addr-of-mutate.rs
@@ -6,7 +6,7 @@
 // Test for the absence of `readonly` on the argument when it is mutated via `&raw const`.
 // See <https://github.com/rust-lang/rust/issues/111502>.
 
-// CHECK: i8 @foo(ptr noalias nocapture noundef dereferenceable(128) %x)
+// CHECK: i8 @foo(ptr noalias nocapture noundef align 1 dereferenceable(128) %x)
 #[no_mangle]
 pub fn foo(x: [u8; 128]) -> u8 {
     let ptr = core::ptr::addr_of!(x).cast_mut();
@@ -16,7 +16,7 @@ pub fn foo(x: [u8; 128]) -> u8 {
     x[0]
 }
 
-// CHECK: i1 @second(ptr noalias nocapture noundef dereferenceable({{[0-9]+}}) %a_ptr_and_b)
+// CHECK: i1 @second(ptr noalias nocapture noundef align {{[0-9]+}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
 #[no_mangle]
 pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
     let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut();
@@ -25,7 +25,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
 }
 
 // If going through a deref (and there are no other mutating accesses), then `readonly` is fine.
-// CHECK: i1 @third(ptr noalias nocapture noundef readonly dereferenceable({{[0-9]+}}) %a_ptr_and_b)
+// CHECK: i1 @third(ptr noalias nocapture noundef readonly align {{[0-9]+}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
 #[no_mangle]
 pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
     let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut();
diff --git a/tests/codegen/align-byval-vector.rs b/tests/codegen/align-byval-vector.rs
new file mode 100644
index 00000000000..3c8be659671
--- /dev/null
+++ b/tests/codegen/align-byval-vector.rs
@@ -0,0 +1,58 @@
+// revisions:x86-linux x86-darwin
+
+//[x86-linux] compile-flags: --target i686-unknown-linux-gnu
+//[x86-linux] needs-llvm-components: x86
+//[x86-darwin] compile-flags: --target i686-apple-darwin
+//[x86-darwin] needs-llvm-components: x86
+
+// Tests that aggregates containing vector types get their alignment increased to 16 on Darwin.
+
+#![feature(no_core, lang_items, repr_simd, simd_ffi)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+#![allow(non_camel_case_types)]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "freeze"]
+trait Freeze {}
+#[lang = "copy"]
+trait Copy {}
+
+#[repr(simd)]
+pub struct i32x4(i32, i32, i32, i32);
+
+#[repr(C)]
+pub struct Foo {
+    a: i32x4,
+    b: i8,
+}
+
+// This tests that we recursively check for vector types, not just at the top level.
+#[repr(C)]
+pub struct DoubleFoo {
+    one: Foo,
+    two: Foo,
+}
+
+extern "C" {
+    // x86-linux: declare void @f({{.*}}byval(%Foo) align 4{{.*}})
+    // x86-darwin: declare void @f({{.*}}byval(%Foo) align 16{{.*}})
+    fn f(foo: Foo);
+
+    // x86-linux: declare void @g({{.*}}byval(%DoubleFoo) align 4{{.*}})
+    // x86-darwin: declare void @g({{.*}}byval(%DoubleFoo) align 16{{.*}})
+    fn g(foo: DoubleFoo);
+}
+
+pub fn main() {
+    unsafe { f(Foo { a: i32x4(1, 2, 3, 4), b: 0 }) }
+
+    unsafe {
+        g(DoubleFoo {
+            one: Foo { a: i32x4(1, 2, 3, 4), b: 0 },
+            two: Foo { a: i32x4(1, 2, 3, 4), b: 0 },
+        })
+    }
+}
diff --git a/tests/codegen/align-byval.rs b/tests/codegen/align-byval.rs
new file mode 100644
index 00000000000..e2446e02ef4
--- /dev/null
+++ b/tests/codegen/align-byval.rs
@@ -0,0 +1,342 @@
+// ignore-tidy-linelength
+// revisions:m68k wasm x86_64-linux x86_64-windows i686-linux i686-windows
+
+//[m68k] compile-flags: --target m68k-unknown-linux-gnu
+//[m68k] needs-llvm-components: m68k
+//[wasm] compile-flags: --target wasm32-unknown-emscripten
+//[wasm] needs-llvm-components: webassembly
+//[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu
+//[x86_64-linux] needs-llvm-components: x86
+//[x86_64-windows] compile-flags: --target x86_64-pc-windows-msvc
+//[x86_64-windows] needs-llvm-components: x86
+//[i686-linux] compile-flags: --target i686-unknown-linux-gnu
+//[i686-linux] needs-llvm-components: x86
+//[i686-windows] compile-flags: --target i686-pc-windows-msvc
+//[i686-windows] needs-llvm-components: x86
+
+// Tests that `byval` alignment is properly specified (#80127).
+// The only targets that use `byval` are m68k, wasm, x86-64, and x86.
+// Note also that Windows mandates a by-ref ABI here, so it does not use byval.
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang="sized"] trait Sized { }
+#[lang="freeze"] trait Freeze { }
+#[lang="copy"] trait Copy { }
+
+impl Copy for i32 {}
+impl Copy for i64 {}
+
+// This struct can be represented as a pair, so it exercises the OperandValue::Pair
+// codepath in `codegen_argument`.
+#[repr(C)]
+pub struct NaturalAlign1 {
+    a: i8,
+    b: i8,
+}
+
+// This struct cannot be represented as an immediate, so it exercises the OperandValue::Ref
+// codepath in `codegen_argument`.
+#[repr(C)]
+pub struct NaturalAlign2 {
+    a: [i16; 16],
+    b: i16,
+}
+
+#[repr(C)]
+#[repr(align(4))]
+pub struct ForceAlign4 {
+    a: [i8; 16],
+    b: i8,
+}
+
+// On i686-windows, this is passed on stack using `byval`
+#[repr(C)]
+pub struct NaturalAlign8 {
+    a: i64,
+    b: i64,
+    c: i64
+}
+
+// On i686-windows, this is passed by reference (because alignment is >4 and requested/forced),
+// even though it has the exact same layout as `NaturalAlign8`!
+#[repr(C)]
+#[repr(align(8))]
+pub struct ForceAlign8 {
+    a: i64,
+    b: i64,
+    c: i64
+}
+
+// On i686-windows, this is passed on stack, because requested alignment is <=4.
+#[repr(C)]
+#[repr(align(4))]
+pub struct LowerFA8 {
+    a: i64,
+    b: i64,
+    c: i64
+}
+
+// On i686-windows, this is passed by reference, because it contains a field with
+// requested/forced alignment.
+#[repr(C)]
+pub struct WrappedFA8 {
+    a: ForceAlign8
+}
+
+// On i686-windows, this has the same ABI as ForceAlign8, i.e. passed by reference.
+#[repr(transparent)]
+pub struct TransparentFA8 {
+    _0: (),
+    a: ForceAlign8
+}
+
+#[repr(C)]
+#[repr(align(16))]
+pub struct ForceAlign16 {
+    a: [i32; 16],
+    b: i8
+}
+
+// CHECK-LABEL: @call_na1
+#[no_mangle]
+pub unsafe fn call_na1(x: NaturalAlign1) {
+    // CHECK: start:
+
+    // m68k: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 1
+    // m68k: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}} [[ALLOCA]])
+
+    // wasm: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 1
+    // wasm: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}} [[ALLOCA]])
+
+    // x86_64-linux: call void @natural_align_1(i16
+
+    // x86_64-windows: call void @natural_align_1(i16
+
+    // i686-linux: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 4
+    // i686-linux: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}} [[ALLOCA]])
+
+    // i686-windows: [[ALLOCA:%[a-z0-9+]]] = alloca { i8, i8 }, align 4
+    // i686-windows: call void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}} [[ALLOCA]])
+    natural_align_1(x);
+}
+
+// CHECK-LABEL: @call_na2
+#[no_mangle]
+pub unsafe fn call_na2(x: NaturalAlign2) {
+    // CHECK: start:
+
+    // m68k-NEXT: call void @natural_align_2
+    // wasm-NEXT: call void @natural_align_2
+    // x86_64-linux-NEXT: call void @natural_align_2
+    // x86_64-windows-NEXT: call void @natural_align_2
+
+    // i686-linux: [[ALLOCA:%[0-9]+]] = alloca %NaturalAlign2, align 4
+    // i686-linux: call void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}} [[ALLOCA]])
+
+    // i686-windows: [[ALLOCA:%[0-9]+]] = alloca %NaturalAlign2, align 4
+    // i686-windows: call void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}} [[ALLOCA]])
+    natural_align_2(x);
+}
+
+// CHECK-LABEL: @call_fa4
+#[no_mangle]
+pub unsafe fn call_fa4(x: ForceAlign4) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @force_align_4
+    force_align_4(x);
+}
+
+// CHECK-LABEL: @call_na8
+#[no_mangle]
+pub unsafe fn call_na8(x: NaturalAlign8) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @natural_align_8
+    natural_align_8(x);
+}
+
+// CHECK-LABEL: @call_fa8
+#[no_mangle]
+pub unsafe fn call_fa8(x: ForceAlign8) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @force_align_8
+    force_align_8(x);
+}
+
+// CHECK-LABEL: @call_lfa8
+#[no_mangle]
+pub unsafe fn call_lfa8(x: LowerFA8) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @lower_fa8
+    lower_fa8(x);
+}
+
+// CHECK-LABEL: @call_wfa8
+#[no_mangle]
+pub unsafe fn call_wfa8(x: WrappedFA8) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @wrapped_fa8
+    wrapped_fa8(x);
+}
+
+// CHECK-LABEL: @call_tfa8
+#[no_mangle]
+pub unsafe fn call_tfa8(x: TransparentFA8) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @transparent_fa8
+    transparent_fa8(x);
+}
+
+// CHECK-LABEL: @call_fa16
+#[no_mangle]
+pub unsafe fn call_fa16(x: ForceAlign16) {
+    // CHECK: start:
+    // CHECK-NEXT: call void @force_align_16
+    force_align_16(x);
+}
+
+extern "C" {
+    // m68k: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}})
+
+    // wasm: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 1{{.*}})
+
+    // x86_64-linux: declare void @natural_align_1(i16)
+
+    // x86_64-windows: declare void @natural_align_1(i16)
+
+    // i686-linux: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}})
+
+    // i686-windows: declare void @natural_align_1({{.*}}byval({ i8, i8 }) align 4{{.*}})
+    fn natural_align_1(x: NaturalAlign1);
+
+    // m68k: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}})
+
+    // wasm: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}})
+
+    // x86_64-linux: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 2{{.*}})
+
+    // x86_64-windows: declare void @natural_align_2(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 2{{.*}})
+
+    // i686-linux: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}})
+
+    // i686-windows: declare void @natural_align_2({{.*}}byval(%NaturalAlign2) align 4{{.*}})
+    fn natural_align_2(x: NaturalAlign2);
+
+    // m68k: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}})
+
+    // wasm: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}})
+
+    // x86_64-linux: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}})
+
+    // x86_64-windows: declare void @force_align_4(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 4{{.*}})
+
+    // i686-linux: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}})
+
+    // i686-windows: declare void @force_align_4({{.*}}byval(%ForceAlign4) align 4{{.*}})
+    fn force_align_4(x: ForceAlign4);
+
+    // m68k: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}})
+
+    // wasm: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 8{{.*}})
+
+    // x86_64-linux: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 8{{.*}})
+
+    // x86_64-windows: declare void @natural_align_8(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 8{{.*}})
+
+    // i686-linux: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}})
+
+    // i686-windows: declare void @natural_align_8({{.*}}byval(%NaturalAlign8) align 4{{.*}})
+    fn natural_align_8(x: NaturalAlign8);
+
+    // m68k: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 8{{.*}})
+
+    // wasm: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 8{{.*}})
+
+    // x86_64-linux: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 8{{.*}})
+
+    // x86_64-windows: declare void @force_align_8(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 8{{.*}})
+
+    // i686-linux: declare void @force_align_8({{.*}}byval(%ForceAlign8) align 4{{.*}})
+
+    // i686-windows: declare void @force_align_8(
+    // i686-windows-NOT: byval
+    // i686-windows-SAME: align 8{{.*}})
+    fn force_align_8(x: ForceAlign8);
+
+    // m68k: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 4{{.*}})
+
+    // wasm: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 8{{.*}})
+
+    // x86_64-linux: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 8{{.*}})
+
+    // x86_64-windows: declare void @lower_fa8(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 8{{.*}})
+
+    // i686-linux: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 4{{.*}})
+
+    // i686-windows: declare void @lower_fa8({{.*}}byval(%LowerFA8) align 4{{.*}})
+    fn lower_fa8(x: LowerFA8);
+
+    // m68k: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 8{{.*}})
+
+    // wasm: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 8{{.*}})
+
+    // x86_64-linux: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 8{{.*}})
+
+    // x86_64-windows: declare void @wrapped_fa8(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 8{{.*}})
+
+    // i686-linux: declare void @wrapped_fa8({{.*}}byval(%WrappedFA8) align 4{{.*}})
+
+    // i686-windows: declare void @wrapped_fa8(
+    // i686-windows-NOT: byval
+    // i686-windows-SAME: align 8{{.*}})
+    fn wrapped_fa8(x: WrappedFA8);
+
+    // m68k: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 8{{.*}})
+
+    // wasm: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 8{{.*}})
+
+    // x86_64-linux: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 8{{.*}})
+
+    // x86_64-windows: declare void @transparent_fa8(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 8{{.*}})
+
+    // i686-linux: declare void @transparent_fa8({{.*}}byval(%TransparentFA8) align 4{{.*}})
+
+    // i686-windows: declare void @transparent_fa8(
+    // i686-windows-NOT: byval
+    // i686-windows-SAME: align 8{{.*}})
+    fn transparent_fa8(x: TransparentFA8);
+
+    // m68k: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}})
+
+    // wasm: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}})
+
+    // x86_64-linux: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 16{{.*}})
+
+    // x86_64-windows: declare void @force_align_16(
+    // x86_64-windows-NOT: byval
+    // x86_64-windows-SAME: align 16{{.*}})
+
+    // i686-linux: declare void @force_align_16({{.*}}byval(%ForceAlign16) align 4{{.*}})
+
+    // i686-windows: declare void @force_align_16(
+    // i686-windows-NOT: byval
+    // i686-windows-SAME: align 16{{.*}})
+    fn force_align_16(x: ForceAlign16);
+}
diff --git a/tests/codegen/array-map.rs b/tests/codegen/array-map.rs
index 24f3f43d078..4d218e6a951 100644
--- a/tests/codegen/array-map.rs
+++ b/tests/codegen/array-map.rs
@@ -30,7 +30,6 @@ pub fn short_integer_map(x: [u32; 8]) -> [u32; 8] {
 pub fn long_integer_map(x: [u32; 512]) -> [u32; 512] {
     // CHECK: start:
     // CHECK-NEXT: alloca [512 x i32]
-    // CHECK-NEXT: alloca %"core::mem::manually_drop::ManuallyDrop<[u32; 512]>"
     // CHECK-NOT: alloca
     // CHECK: mul <{{[0-9]+}} x i32>
     // CHECK: add <{{[0-9]+}} x i32>
diff --git a/tests/codegen/function-arguments-noopt.rs b/tests/codegen/function-arguments-noopt.rs
index 35f31eba3b1..f99cc8fb415 100644
--- a/tests/codegen/function-arguments-noopt.rs
+++ b/tests/codegen/function-arguments-noopt.rs
@@ -42,7 +42,7 @@ pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {
   f(x)
 }
 
-// CHECK: void @struct_({{%S\*|ptr}} sret(%S){{( %_0)?}}, {{%S\*|ptr}} %x)
+// CHECK: void @struct_({{%S\*|ptr}} sret(%S) align 4{{( %_0)?}}, {{%S\*|ptr}} align 4 %x)
 #[no_mangle]
 pub fn struct_(x: S) -> S {
   x
@@ -51,7 +51,7 @@ pub fn struct_(x: S) -> S {
 // CHECK-LABEL: @struct_call
 #[no_mangle]
 pub fn struct_call(x: S, f: fn(S) -> S) -> S {
-  // CHECK: call void %f({{%S\*|ptr}} sret(%S){{( %_0)?}}, {{%S\*|ptr}} %{{.+}})
+  // CHECK: call void %f({{%S\*|ptr}} sret(%S) align 4{{( %_0)?}}, {{%S\*|ptr}} align 4 %{{.+}})
   f(x)
 }
 
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
index ccf4a5de327..2f047f10311 100644
--- a/tests/codegen/function-arguments.rs
+++ b/tests/codegen/function-arguments.rs
@@ -142,7 +142,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {
 pub fn notunpin_borrow(_: &NotUnpin) {
 }
 
-// CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef readonly dereferenceable(32) %_1)
+// CHECK: @indirect_struct({{%S\*|ptr}} noalias nocapture noundef readonly align 4 dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {
 }
@@ -188,7 +188,7 @@ pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
   x
 }
 
-// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %_0)?}})
+// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) align 4 dereferenceable(32){{( %_0)?}})
 #[no_mangle]
 pub fn struct_return() -> S {
   S {