c2fd26a115
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.
343 lines
11 KiB
Rust
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);
|
|
}
|