]> git.lizzy.rs Git - rust.git/commitdiff
x86: return single-float aggregates in a float register
authorJosh Stone <jistone@redhat.com>
Fri, 1 Sep 2017 23:05:19 +0000 (16:05 -0700)
committerJosh Stone <jistone@redhat.com>
Sat, 2 Sep 2017 01:21:29 +0000 (18:21 -0700)
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.

src/librustc_trans/cabi_x86.rs

index 8b024b8c97fa0940cc9ede65456dd3dab0ba74d8..49634d6e78ce9a589eb68d9e68c5833aa7558bbc 100644 (file)
 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);