mirror of
https://github.com/rust-lang/rust.git
synced 2025-10-02 18:27:37 +00:00

This test covers: * The callee side, making sure that the structs are correctly loaded into registers when `-Zreg-struct-return` is enabled * The caller side, making sure that callers do receive returned structs in registers when `-Zreg-struct-return` is enabled Structs of the size of up to 2 registers (8 bytes) can be returned in registers in x86_32. Therefore, the tests are done with 3 different struct sizes: * 2 bytes (register returns should happen) * 8 bytes (last value where register returns should happen) * 12 bytes (register returns should not happen even when `-Zreg-struct-return` is enabled)
144 lines
4.2 KiB
Rust
144 lines
4.2 KiB
Rust
//! Tests that -Zreg-struct-return changes ABI for small struct returns
|
|
//! from hidden-pointer convention to register-return on x86_32.
|
|
//! This test covers:
|
|
//! * Callee side, verifying that the structs are correctly loaded into registers when
|
|
//! `-Zreg-struct-return` is activated
|
|
//! * Caller side, verifying callers do receive returned structs in registers when
|
|
//! `-Zreg-struct-return` is activated
|
|
//@ add-core-stubs
|
|
//@ assembly-output: emit-asm
|
|
//@ compile-flags: -O --target=i686-unknown-linux-gnu -Crelocation-model=static
|
|
//@ revisions: WITH WITHOUT
|
|
//@[WITH] compile-flags: -Zreg-struct-return
|
|
//@ needs-llvm-components: x86
|
|
|
|
#![feature(no_core)]
|
|
#![no_std]
|
|
#![no_core]
|
|
#![crate_type = "lib"]
|
|
|
|
extern crate minicore;
|
|
use minicore::*;
|
|
|
|
// Verifies ABI changes for small structs, where both fields fit into one register.
|
|
// WITH is expected to use register return, WITHOUT should use hidden pointer.
|
|
mod Small {
|
|
struct SmallStruct {
|
|
a: i8,
|
|
b: i8,
|
|
}
|
|
|
|
unsafe extern "C" {
|
|
fn small() -> SmallStruct;
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn small_callee() -> SmallStruct {
|
|
// (42 << 8) | 42 = 10794
|
|
|
|
// WITH-LABEL: small_callee
|
|
// WITH: movw $10794, %ax
|
|
// WITH: retl
|
|
|
|
// WITHOUT-LABEL: small_callee
|
|
// WITHOUT: movl 4(%esp), %e{{.*}}
|
|
// WITHOUT: movw $10794, (%e{{.*}})
|
|
// WITHOUT: retl $4
|
|
SmallStruct { a: 42, b: 42 }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn small_caller(dst: &mut SmallStruct) {
|
|
// WITH-LABEL: small_caller
|
|
// WITH: calll small
|
|
// WITH: movw %ax, (%e{{.*}})
|
|
|
|
// WITHOUT-LABEL: small_caller
|
|
// WITHOUT: calll small
|
|
// WITHOUT: movzwl {{.*}}(%esp), %e[[TMP:..]]
|
|
// WITHOUT: movw %[[TMP]], (%e{{..}})
|
|
*dst = small();
|
|
}
|
|
}
|
|
|
|
// Verifies ABI changes for a struct of size 8, which is the maximum size
|
|
// for reg-struct-return.
|
|
// WITH is expected to still use register return, WITHOUT should use hidden
|
|
// pointer.
|
|
mod Pivot {
|
|
struct PivotStruct {
|
|
a: i32,
|
|
b: i32,
|
|
}
|
|
|
|
unsafe extern "C" {
|
|
fn pivot() -> PivotStruct;
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn pivot_callee() -> PivotStruct {
|
|
// WITH-LABEL: pivot_callee
|
|
// WITH: movl $42, %e{{.*}}
|
|
// WITH: movl $42, %e{{.*}}
|
|
// WITH: retl
|
|
|
|
// WITHOUT-LABEL: pivot_callee
|
|
// WITHOUT: movl 4(%esp), %e{{.*}}
|
|
// WITHOUT-DAG: movl $42, (%e{{.*}})
|
|
// WITHOUT-DAG: movl $42, 4(%e{{.*}})
|
|
// WITHOUT: retl $4
|
|
PivotStruct { a: 42, b: 42 }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn pivot_caller(dst: &mut PivotStruct) {
|
|
// WITH-LABEL: pivot_caller
|
|
// WITH: calll pivot
|
|
// WITH-DAG: movl %e{{.*}}, 4(%e{{.*}})
|
|
// WITH-DAG: movl %e{{.*}}, (%e{{.*}})
|
|
|
|
// WITHOUT-LABEL: pivot_caller
|
|
// WITHOUT: calll pivot
|
|
// WITHOUT: movsd {{.*}}(%esp), %[[TMP:xmm.]]
|
|
// WITHOUT: movsd %[[TMP]], (%e{{..}})
|
|
*dst = pivot();
|
|
}
|
|
}
|
|
|
|
// Verifies ABI changes for a struct of size 12, which is larger than the
|
|
// maximum size for reg-struct-return (8 bytes).
|
|
// Here, the hidden pointer convention should be used even when `-Zreg-struct-return` is set.
|
|
mod Large {
|
|
struct LargeStruct {
|
|
a: i32,
|
|
b: i32,
|
|
c: i32,
|
|
}
|
|
|
|
unsafe extern "C" {
|
|
fn large() -> LargeStruct;
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn large_callee() -> LargeStruct {
|
|
// CHECK-LABEL: large_callee
|
|
// CHECK: movl 4(%esp), %e{{.*}}
|
|
// CHECK-DAG: movl $42, (%e{{.*}})
|
|
// CHECK-DAG: movl $42, 4(%e{{.*}})
|
|
// CHECK-DAG: movl $42, 8(%e{{.*}})
|
|
// CHECK: retl $4
|
|
LargeStruct { a: 42, b: 42, c: 42 }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn large_caller(dst: &mut LargeStruct) {
|
|
// CHECK-LABEL: large_caller
|
|
// CHECK: calll large
|
|
// CHECK-DAG: movl {{.*}}(%esp), %[[TMP1:e..]]
|
|
// CHECK-DAG: movl %[[TMP1]], {{.*}}(%e{{..}})
|
|
// CHECK-DAG: movsd {{.*}}(%esp), %[[TMP2:xmm.]]
|
|
// CHECK-DAG: movsd %[[TMP2]], {{.*}}(%e{{..}})
|
|
*dst = large();
|
|
}
|
|
}
|