From c461cdfdf686caec2b93fe9e41efaa79b7a5c292 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Wed, 21 Dec 2016 21:42:10 +0300 Subject: [PATCH] Fixed fastcall not applying inreg attributes to arguments like the C/C++ fastcall. --- src/librustc_llvm/ffi.rs | 1 + src/librustc_trans/abi.rs | 14 +++++++-- src/librustc_trans/cabi_x86.rs | 55 +++++++++++++++++++++++++++++++++- src/rustllvm/RustWrapper.cpp | 2 ++ src/rustllvm/rustllvm.h | 1 + 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(&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 @@ pub fn adjust_for_abi<'a, 'tcx>(&mut self, } 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 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;