about summary refs log tree commit diff
path: root/tests/codegen
diff options
context:
space:
mode:
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
-rw-r--r--tests/codegen/iter-repeat-n-trivial-drop.rs2
-rw-r--r--tests/codegen/simd-wide-sum.rs12
-rw-r--r--tests/codegen/slice-init.rs16
-rw-r--r--tests/codegen/slice-ref-equality.rs32
11 files changed, 592 insertions, 35 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 {
diff --git a/tests/codegen/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs
index 24059f190ac..65a0f7e7ffb 100644
--- a/tests/codegen/iter-repeat-n-trivial-drop.rs
+++ b/tests/codegen/iter-repeat-n-trivial-drop.rs
@@ -33,7 +33,7 @@ pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN<NotCopy>) -> Option<NotCop
 
     // CHECK: [[EMPTY]]:
     // CHECK-NOT: br
-    // CHECK: phi i16 [ undef, %start ], [ %[[VAL]], %[[NOT_EMPTY]] ]
+    // CHECK: phi i16 [ %[[VAL]], %[[NOT_EMPTY]] ], [ undef, %start ]
     // CHECK-NOT: br
     // CHECK: ret
 
diff --git a/tests/codegen/simd-wide-sum.rs b/tests/codegen/simd-wide-sum.rs
index db2aa20bde7..3116f9597bc 100644
--- a/tests/codegen/simd-wide-sum.rs
+++ b/tests/codegen/simd-wide-sum.rs
@@ -1,6 +1,11 @@
+// revisions: llvm mir-opt3
 // compile-flags: -C opt-level=3 -Z merge-functions=disabled --edition=2021
 // only-x86_64
 // ignore-debug: the debug assertions get in the way
+// [mir-opt3]compile-flags: -Zmir-opt-level=3
+// [mir-opt3]build-pass
+
+// mir-opt3 is a regression test for https://github.com/rust-lang/rust/issues/98016
 
 #![crate_type = "lib"]
 #![feature(portable_simd)]
@@ -47,9 +52,8 @@ pub fn wider_reduce_iter(x: Simd<u8, N>) -> u16 {
 #[no_mangle]
 // CHECK-LABEL: @wider_reduce_into_iter
 pub fn wider_reduce_into_iter(x: Simd<u8, N>) -> u16 {
-    // FIXME MIR inlining messes up LLVM optimizations.
-    // WOULD-CHECK: zext <8 x i8>
-    // WOULD-CHECK-SAME: to <8 x i16>
-    // WOULD-CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16>
+    // CHECK: zext <8 x i8>
+    // CHECK-SAME: to <8 x i16>
+    // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16>
     x.to_array().into_iter().map(u16::from).sum()
 }
diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs
index 794b773a776..d80628cb1d4 100644
--- a/tests/codegen/slice-init.rs
+++ b/tests/codegen/slice-init.rs
@@ -8,7 +8,7 @@ pub fn zero_sized_elem() {
     // CHECK-NOT: br label %repeat_loop_header{{.*}}
     // CHECK-NOT: call void @llvm.memset.p0
     let x = [(); 4];
-    drop(&x);
+    opaque(&x);
 }
 
 // CHECK-LABEL: @zero_len_array
@@ -17,7 +17,7 @@ pub fn zero_len_array() {
     // CHECK-NOT: br label %repeat_loop_header{{.*}}
     // CHECK-NOT: call void @llvm.memset.p0
     let x = [4; 0];
-    drop(&x);
+    opaque(&x);
 }
 
 // CHECK-LABEL: @byte_array
@@ -26,7 +26,7 @@ pub fn byte_array() {
     // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 7, i{{[0-9]+}} 4
     // CHECK-NOT: br label %repeat_loop_header{{.*}}
     let x = [7u8; 4];
-    drop(&x);
+    opaque(&x);
 }
 
 #[allow(dead_code)]
@@ -42,7 +42,7 @@ pub fn byte_enum_array() {
     // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 {{.*}}, i{{[0-9]+}} 4
     // CHECK-NOT: br label %repeat_loop_header{{.*}}
     let x = [Init::Memset; 4];
-    drop(&x);
+    opaque(&x);
 }
 
 // CHECK-LABEL: @zeroed_integer_array
@@ -51,7 +51,7 @@ pub fn zeroed_integer_array() {
     // CHECK: call void @llvm.memset.{{.+}}({{i8\*|ptr}} {{.*}}, i8 0, i{{[0-9]+}} 16
     // CHECK-NOT: br label %repeat_loop_header{{.*}}
     let x = [0u32; 4];
-    drop(&x);
+    opaque(&x);
 }
 
 // CHECK-LABEL: @nonzero_integer_array
@@ -60,5 +60,9 @@ pub fn nonzero_integer_array() {
     // CHECK: br label %repeat_loop_header{{.*}}
     // CHECK-NOT: call void @llvm.memset.p0
     let x = [0x1a_2b_3c_4d_u32; 4];
-    drop(&x);
+    opaque(&x);
 }
+
+// Use an opaque function to prevent rustc from removing useless drops.
+#[inline(never)]
+pub fn opaque(_: impl Sized) {}
diff --git a/tests/codegen/slice-ref-equality.rs b/tests/codegen/slice-ref-equality.rs
index 8f0adab35e7..c91e5bc3cd0 100644
--- a/tests/codegen/slice-ref-equality.rs
+++ b/tests/codegen/slice-ref-equality.rs
@@ -44,48 +44,48 @@ pub fn is_zero_array(data: &[u8; 4]) -> bool {
 // equality for non-byte types also just emit a `bcmp`, not a loop.
 
 // CHECK-LABEL: @eq_slice_of_nested_u8(
-// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1
-// CHECK-SAME: [[USIZE]] noundef %3
+// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
+// CHECK-SAME: [[USIZE]] noundef %y.1
 #[no_mangle]
 fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool {
-    // CHECK: icmp eq [[USIZE]] %1, %3
-    // CHECK: %[[BYTES:.+]] = mul nsw [[USIZE]] %1, 3
+    // CHECK: icmp eq [[USIZE]] %x.1, %y.1
+    // CHECK: %[[BYTES:.+]] = mul nsw [[USIZE]] %x.1, 3
     // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i8\*|ptr}}
     // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
     x == y
 }
 
 // CHECK-LABEL: @eq_slice_of_i32(
-// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1
-// CHECK-SAME: [[USIZE]] noundef %3
+// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
+// CHECK-SAME: [[USIZE]] noundef %y.1
 #[no_mangle]
 fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool {
-    // CHECK: icmp eq [[USIZE]] %1, %3
-    // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2
+    // CHECK: icmp eq [[USIZE]] %x.1, %y.1
+    // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 2
     // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i32\*|ptr}}
     // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
     x == y
 }
 
 // CHECK-LABEL: @eq_slice_of_nonzero(
-// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1
-// CHECK-SAME: [[USIZE]] noundef %3
+// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
+// CHECK-SAME: [[USIZE]] noundef %y.1
 #[no_mangle]
 fn eq_slice_of_nonzero(x: &[NonZeroU32], y: &[NonZeroU32]) -> bool {
-    // CHECK: icmp eq [[USIZE]] %1, %3
-    // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2
+    // CHECK: icmp eq [[USIZE]] %x.1, %y.1
+    // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 2
     // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i32\*|ptr}}
     // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
     x == y
 }
 
 // CHECK-LABEL: @eq_slice_of_option_of_nonzero(
-// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1
-// CHECK-SAME: [[USIZE]] noundef %3
+// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %x.1
+// CHECK-SAME: [[USIZE]] noundef %y.1
 #[no_mangle]
 fn eq_slice_of_option_of_nonzero(x: &[Option<NonZeroI16>], y: &[Option<NonZeroI16>]) -> bool {
-    // CHECK: icmp eq [[USIZE]] %1, %3
-    // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 1
+    // CHECK: icmp eq [[USIZE]] %x.1, %y.1
+    // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %x.1, 1
     // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i16\*|ptr}}
     // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]])
     x == y