blob: 92f10267e01d2c896146f64aeb241cee731bc21b [file] [edit]
// Tests that MIPS targets return structs that are up to 128 bits large, only
// consist of 1 or 2 floating point fields and have a first field with offset 0
// in FPRs rather than GPRs.
//
//@ add-minicore
//@ assembly-output: emit-asm
//@ compile-flags: -Copt-level=3
//
//@ revisions: LE
//@[LE] compile-flags: --target=mips64el-unknown-linux-gnuabi64
//@[LE] needs-llvm-components: mips
//@ revisions: BE
//@[BE] compile-flags: --target=mips64-unknown-linux-gnuabi64
//@[BE] needs-llvm-components: mips
#![crate_type = "lib"]
#![feature(no_core, f128)]
#![no_core]
extern crate minicore;
// 128-bit large struct with one floating point field, should be returned in
// $f0 and $f1 to match the de-facto GCC ABI.
#[repr(C)]
struct SingleF128 {
x: f128,
}
// 64-bit large struct with one floating point field, should be returned in $f0.
#[repr(C)]
struct SingleF64 {
x: f64,
}
// 32-bit large struct with one floating point field, should be returned in $f0.
#[repr(C)]
struct SingleF32 {
x: f32,
}
// 128-bit large struct with two floating point fields, should be returned in
// $f0 and $f2.
#[repr(C)]
struct TwoF64 {
x: f64,
y: f64,
}
// 64-bit large struct with two floating point fields, should be returned in
// $f0 and $f2.
#[repr(C)]
struct TwoF32 {
x: f32,
y: f32,
}
// 96-bit large struct with two floating point fields, should be returned in
// $f0 and $f2.
#[repr(C)]
struct F32AndF64 {
x: f32,
y: f64,
}
// 96-bit large struct with two floating-point fields, should be returned in
// $f0 and $f2.
#[repr(C)]
struct F64AndF32 {
x: f64,
y: f32,
}
// CHECK-LABEL: single_f128
// CHECK: dmtc1 $4, $f0
// CHECK-NEXT: jr $ra
// CHECK-NEXT: dmtc1 $5, $f1
#[unsafe(no_mangle)]
pub extern "C" fn single_f128(a: SingleF128) -> SingleF128 {
a
}
// CHECK-LABEL: single_f64
// CHECK: jr $ra
// CHECK-NEXT: mov.d $f0, $f12
#[unsafe(no_mangle)]
pub extern "C" fn single_f64(a: SingleF64) -> SingleF64 {
a
}
// CHECK-LABEL: single_f32
// BE: dsrl $1, $4, 32
// LE: sll $1, $4, 0
// BE-NEXT: sll $1, $1, 0
// CHECK-NEXT: jr $ra
// CHECK-NEXT: mtc1 $1, $f0
#[unsafe(no_mangle)]
pub extern "C" fn single_f32(a: SingleF32) -> SingleF32 {
a
}
// CHECK-LABEL: two_f64
// CHECK: mov.d $f2, $f13
// CHECK-NEXT: jr $ra
// CHECK-NEXT: mov.d $f0, $f12
#[unsafe(no_mangle)]
pub extern "C" fn two_f64(a: TwoF64) -> TwoF64 {
a
}
// CHECK-LABEL: two_f32
// CHECK: sll $1, $4, 0
// LE-NEXT: mtc1 $1, $f0
// BE-NEXT: mtc1 $1, $f2
// CHECK-NEXT: dsrl $1, $4, 32
// CHECK-NEXT: sll $1, $1, 0
// CHECK-NEXT: jr $ra
// LE-NEXT: mtc1 $1, $f2
// BE-NEXT: mtc1 $1, $f0
#[unsafe(no_mangle)]
pub extern "C" fn two_f32(a: TwoF32) -> TwoF32 {
a
}
// We deviate from Clang in the order of instructions in the next two functions
// but that's okay
// CHECK-LABEL: f32_and_f64
// BE: dsrl $1, $4, 32
// LE: mov.d $f2, $f13
// BE-NEXT: mov.d $f2, $f13
// LE-NEXT: sll $1, $4, 0
// BE-NEXT: sll $1, $1, 0
// CHECK-NEXT: jr $ra
// CHECK-NEXT: mtc1 $1, $f0
#[unsafe(no_mangle)]
pub extern "C" fn f32_and_f64(a: F32AndF64) -> F32AndF64 {
a
}
// CHECK-LABEL: f64_and_f32
// BE: dsrl $1, $5, 32
// LE: mov.d $f0, $f12
// BE-NEXT: mov.d $f0, $f12
// LE-NEXT: sll $1, $5, 0
// BE-NEXT: sll $1, $1, 0
// CHECK-NEXT: jr $ra
// CHECK-NEXT: mtc1 $1, $f2
#[unsafe(no_mangle)]
pub extern "C" fn f64_and_f32(a: F64AndF32) -> F64AndF32 {
a
}