x86: return single-float aggregates in a float register
Following Clang's lead, and anecdotal evidence from the `float_one` part of `run-make/extern-fn-struct-passing-abi`, use a floating point register to return single-float aggregates, except on MSVC targets.
This commit is contained in:
parent
f7c9704024
commit
40b14736a0
@ -11,12 +11,30 @@
|
||||
use abi::{ArgAttribute, FnType, LayoutExt, Reg, RegKind};
|
||||
use common::CrateContext;
|
||||
|
||||
use rustc::ty::layout::{self, Layout, TyLayout};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum Flavor {
|
||||
General,
|
||||
Fastcall
|
||||
}
|
||||
|
||||
fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
layout: TyLayout<'tcx>) -> bool {
|
||||
match *layout {
|
||||
Layout::Scalar { value: layout::F32, .. } |
|
||||
Layout::Scalar { value: layout::F64, .. } => true,
|
||||
Layout::Univariant { .. } => {
|
||||
if layout.field_count() == 1 {
|
||||
is_single_fp_element(ccx, layout.field(ccx, 0))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
fty: &mut FnType<'tcx>,
|
||||
flavor: Flavor) {
|
||||
@ -33,12 +51,23 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
if t.options.is_like_osx || t.options.is_like_windows
|
||||
|| t.options.is_like_openbsd {
|
||||
let size = fty.ret.layout.size(ccx);
|
||||
match size.bytes() {
|
||||
1 => fty.ret.cast_to(ccx, Reg::i8()),
|
||||
2 => fty.ret.cast_to(ccx, Reg::i16()),
|
||||
4 => fty.ret.cast_to(ccx, Reg::i32()),
|
||||
8 => fty.ret.cast_to(ccx, Reg::i64()),
|
||||
_ => fty.ret.make_indirect(ccx)
|
||||
|
||||
// According to Clang, everyone but MSVC returns single-element
|
||||
// float aggregates directly in a floating-point register.
|
||||
if !t.options.is_like_msvc && is_single_fp_element(ccx, fty.ret.layout) {
|
||||
match size.bytes() {
|
||||
4 => fty.ret.cast_to(ccx, Reg::f32()),
|
||||
8 => fty.ret.cast_to(ccx, Reg::f64()),
|
||||
_ => fty.ret.make_indirect(ccx)
|
||||
}
|
||||
} else {
|
||||
match size.bytes() {
|
||||
1 => fty.ret.cast_to(ccx, Reg::i8()),
|
||||
2 => fty.ret.cast_to(ccx, Reg::i16()),
|
||||
4 => fty.ret.cast_to(ccx, Reg::i32()),
|
||||
8 => fty.ret.cast_to(ccx, Reg::i64()),
|
||||
_ => fty.ret.make_indirect(ccx)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fty.ret.make_indirect(ccx);
|
||||
|
Loading…
Reference in New Issue
Block a user