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:
Josh Stone 2017-09-01 16:05:19 -07:00
parent f7c9704024
commit 40b14736a0

View File

@ -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);