about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2016-12-21 21:42:10 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2016-12-21 21:44:40 +0300
commitc461cdfdf686caec2b93fe9e41efaa79b7a5c292 (patch)
treefe11548bfadb41480ec69130bdd86393e515905a /src
parent1b38776c1f68c6fd47c1b2f7b7974efc7dd64901 (diff)
downloadrust-c461cdfdf686caec2b93fe9e41efaa79b7a5c292.tar.gz
rust-c461cdfdf686caec2b93fe9e41efaa79b7a5c292.zip
Fixed fastcall not applying inreg attributes to arguments like the C/C++ fastcall.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_llvm/ffi.rs1
-rw-r--r--src/librustc_trans/abi.rs14
-rw-r--r--src/librustc_trans/cabi_x86.rs55
-rw-r--r--src/rustllvm/RustWrapper.cpp2
-rw-r--r--src/rustllvm/rustllvm.h1
5 files changed, 69 insertions, 4 deletions
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index d2b86ade7a2..f3dbac7ce68 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -117,6 +117,7 @@ pub enum Attribute {
     StructRet       = 16,
     UWTable         = 17,
     ZExt            = 18,
+    InReg           = 19,
 }
 
 /// LLVMIntPredicate
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 8b4343af199..f0f25118990 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -58,7 +58,7 @@ mod attr_impl {
     // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
     bitflags! {
         #[derive(Default, Debug)]
-        flags ArgAttribute : u8 {
+        flags ArgAttribute : u16 {
             const ByVal     = 1 << 0,
             const NoAlias   = 1 << 1,
             const NoCapture = 1 << 2,
@@ -67,6 +67,7 @@ mod attr_impl {
             const SExt      = 1 << 5,
             const StructRet = 1 << 6,
             const ZExt      = 1 << 7,
+            const InReg     = 1 << 8,
         }
     }
 }
@@ -80,7 +81,7 @@ macro_rules! for_each_kind {
 impl ArgAttribute {
     fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) {
         for_each_kind!(self, f,
-                       ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt)
+                       ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
     }
 }
 
@@ -573,7 +574,14 @@ impl FnType {
         }
 
         match &ccx.sess().target.target.arch[..] {
-            "x86" => cabi_x86::compute_abi_info(ccx, self),
+            "x86" => {
+                let flavor = if abi == Abi::Fastcall {
+                    cabi_x86::Flavor::Fastcall
+                } else {
+                    cabi_x86::Flavor::General
+                };
+                cabi_x86::compute_abi_info(ccx, self, flavor);
+            },
             "x86_64" => if abi == Abi::SysV64 {
                 cabi_x86_64::compute_abi_info(ccx, self);
             } else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows {
diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_trans/cabi_x86.rs
index ce85234f203..ae8b610882b 100644
--- a/src/librustc_trans/cabi_x86.rs
+++ b/src/librustc_trans/cabi_x86.rs
@@ -14,7 +14,13 @@ use type_::Type;
 use super::common::*;
 use super::machine::*;
 
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+#[derive(PartialEq)]
+pub enum Flavor {
+    General,
+    Fastcall
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
     if !fty.ret.is_ignore() {
         if fty.ret.ty.kind() == Struct {
             // Returning a structure. Most often, this will use
@@ -51,4 +57,51 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
             arg.extend_integer_width_to(32);
         }
     }
+
+    if flavor == Flavor::Fastcall {
+        // Mark arguments as InReg like clang does it,
+        // so our fastcall is compatible with C/C++ fastcall.
+        // Clang reference: ib/CodeGen/TargetInfo.cpp
+        let is_mcu_abi = ccx.sess().target.target.target_os.eq("elfiamcu");
+        let is_soft_float_abi = ccx.sess().target.target.options.features.contains("+soft-float");
+
+        let mut free_regs = 2;
+
+        for arg in &mut fty.args {
+            if !arg.is_ignore() && !arg.is_indirect() {
+                if !is_soft_float_abi {
+                    if arg.ty.kind() == Float {
+                        continue;
+                    }
+                }
+
+                let size = llbitsize_of_real(ccx, arg.ty);
+                let size_in_regs = (size + 31) / 32;
+
+                if size_in_regs == 0 {
+                    continue;
+                }
+
+                if !is_mcu_abi {
+                    if size_in_regs > free_regs {
+                        break;
+                    }
+                } else {
+                    if size_in_regs > free_regs || size_in_regs > 2 {
+                        continue;
+                    }
+                }
+
+                free_regs -= size_in_regs;
+
+                if !is_mcu_abi && size <= 32 && (arg.ty.kind() == Pointer || arg.ty.kind() == Integer) {
+                    arg.attrs.set(ArgAttribute::InReg);
+                }
+
+                if free_regs == 0 {
+                    break;
+                }
+            }
+        }
+    }
 }
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index f5fa66f1b0e..5d5845213e2 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -150,6 +150,8 @@ from_rust(LLVMRustAttribute kind) {
       return Attribute::UWTable;
     case ZExt:
       return Attribute::ZExt;
+    case InReg:
+      return Attribute::InReg;
     default:
       llvm_unreachable("bad AttributeKind");
   }
diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h
index b8c4076f4ce..8f7e0e3d918 100644
--- a/src/rustllvm/rustllvm.h
+++ b/src/rustllvm/rustllvm.h
@@ -98,6 +98,7 @@ enum LLVMRustAttribute {
     StructRet       = 16,
     UWTable         = 17,
     ZExt            = 18,
+    InReg           = 19,
 };
 
 typedef struct OpaqueRustString *RustStringRef;