Skip to content

Commit 40b1473

Browse files
committed
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.
1 parent f7c9704 commit 40b1473

File tree

1 file changed

+35
-6
lines changed

1 file changed

+35
-6
lines changed

src/librustc_trans/cabi_x86.rs

+35-6
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,30 @@
1111
use abi::{ArgAttribute, FnType, LayoutExt, Reg, RegKind};
1212
use common::CrateContext;
1313

14+
use rustc::ty::layout::{self, Layout, TyLayout};
15+
1416
#[derive(PartialEq)]
1517
pub enum Flavor {
1618
General,
1719
Fastcall
1820
}
1921

22+
fn is_single_fp_element<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
23+
layout: TyLayout<'tcx>) -> bool {
24+
match *layout {
25+
Layout::Scalar { value: layout::F32, .. } |
26+
Layout::Scalar { value: layout::F64, .. } => true,
27+
Layout::Univariant { .. } => {
28+
if layout.field_count() == 1 {
29+
is_single_fp_element(ccx, layout.field(ccx, 0))
30+
} else {
31+
false
32+
}
33+
}
34+
_ => false
35+
}
36+
}
37+
2038
pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
2139
fty: &mut FnType<'tcx>,
2240
flavor: Flavor) {
@@ -33,12 +51,23 @@ pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
3351
if t.options.is_like_osx || t.options.is_like_windows
3452
|| t.options.is_like_openbsd {
3553
let size = fty.ret.layout.size(ccx);
36-
match size.bytes() {
37-
1 => fty.ret.cast_to(ccx, Reg::i8()),
38-
2 => fty.ret.cast_to(ccx, Reg::i16()),
39-
4 => fty.ret.cast_to(ccx, Reg::i32()),
40-
8 => fty.ret.cast_to(ccx, Reg::i64()),
41-
_ => fty.ret.make_indirect(ccx)
54+
55+
// According to Clang, everyone but MSVC returns single-element
56+
// float aggregates directly in a floating-point register.
57+
if !t.options.is_like_msvc && is_single_fp_element(ccx, fty.ret.layout) {
58+
match size.bytes() {
59+
4 => fty.ret.cast_to(ccx, Reg::f32()),
60+
8 => fty.ret.cast_to(ccx, Reg::f64()),
61+
_ => fty.ret.make_indirect(ccx)
62+
}
63+
} else {
64+
match size.bytes() {
65+
1 => fty.ret.cast_to(ccx, Reg::i8()),
66+
2 => fty.ret.cast_to(ccx, Reg::i16()),
67+
4 => fty.ret.cast_to(ccx, Reg::i32()),
68+
8 => fty.ret.cast_to(ccx, Reg::i64()),
69+
_ => fty.ret.make_indirect(ccx)
70+
}
4271
}
4372
} else {
4473
fty.ret.make_indirect(ccx);

0 commit comments

Comments
 (0)