0
0
mirror of https://github.com/rust-lang/rust.git synced 2024-12-01 13:18:54 +01:00
rust/tests/codegen/align-byval.rs
Nikita Popov c2fd26a115 Separate immediate and in-memory ScalarPair representation
Currently, we assume that ScalarPair is always represented using
a two-element struct, both as an immediate value and when stored
in memory.

This currently works fairly well, but runs into problems with
https://github.com/rust-lang/rust/pull/116672, where a ScalarPair
involving an i128 type can no longer be represented as a two-element
struct in memory. For example, the tuple `(i32, i128)` needs to be
represented in-memory as `{ i32, [3 x i32], i128 }` to satisfy
alignment requirement. Using `{ i32, i128 }` instead will result in
the second element being stored at the wrong offset (prior to
LLVM 18).

Resolve this issue by no longer requiring that the immediate and
in-memory type for ScalarPair are the same. The in-memory type
will now look the same as for normal struct types (and will include
padding filler and similar), while the immediate type stays a
simple two-element struct type. This also means that booleans in
immediate ScalarPair are now represented as i1 rather than i8,
just like we do everywhere else.

The core change here is to llvm_type (which now treats ScalarPair
as a normal struct) and immediate_llvm_type (which returns the
two-element struct that llvm_type used to produce). The rest is
fixing things up to no longer assume these are the same. In
particular, this switches places that try to get pointers to the
ScalarPair elements to use byte-geps instead of struct-geps.
2023-12-15 17:42:05 +01:00

343 lines
11 KiB
Rust

// 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 %NaturalAlign1, align 1
// m68k: call void @natural_align_1({{.*}}byval(%NaturalAlign1) align 1{{.*}} [[ALLOCA]])
// wasm: [[ALLOCA:%[a-z0-9+]]] = alloca %NaturalAlign1, align 1
// wasm: call void @natural_align_1({{.*}}byval(%NaturalAlign1) 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 %NaturalAlign1, align 4
// i686-linux: call void @natural_align_1({{.*}}byval(%NaturalAlign1) align 4{{.*}} [[ALLOCA]])
// i686-windows: [[ALLOCA:%[a-z0-9+]]] = alloca %NaturalAlign1, align 4
// i686-windows: call void @natural_align_1({{.*}}byval(%NaturalAlign1) 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(%NaturalAlign1) align 1{{.*}})
// wasm: declare void @natural_align_1({{.*}}byval(%NaturalAlign1) 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(%NaturalAlign1) align 4{{.*}})
// i686-windows: declare void @natural_align_1({{.*}}byval(%NaturalAlign1) 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);
}