Fixed fastcall not applying inreg attributes to arguments like the C/C++ fastcall.

This commit is contained in:
Ivan Molodetskikh 2016-12-21 21:42:10 +03:00
parent 1b38776c1f
commit c461cdfdf6
No known key found for this signature in database
GPG key ID: 02CE38DA47E9D691
5 changed files with 69 additions and 4 deletions

View file

@ -117,6 +117,7 @@ pub enum Attribute {
StructRet = 16, StructRet = 16,
UWTable = 17, UWTable = 17,
ZExt = 18, ZExt = 18,
InReg = 19,
} }
/// LLVMIntPredicate /// LLVMIntPredicate

View file

@ -58,7 +58,7 @@ mod attr_impl {
// The subset of llvm::Attribute needed for arguments, packed into a bitfield. // The subset of llvm::Attribute needed for arguments, packed into a bitfield.
bitflags! { bitflags! {
#[derive(Default, Debug)] #[derive(Default, Debug)]
flags ArgAttribute : u8 { flags ArgAttribute : u16 {
const ByVal = 1 << 0, const ByVal = 1 << 0,
const NoAlias = 1 << 1, const NoAlias = 1 << 1,
const NoCapture = 1 << 2, const NoCapture = 1 << 2,
@ -67,6 +67,7 @@ mod attr_impl {
const SExt = 1 << 5, const SExt = 1 << 5,
const StructRet = 1 << 6, const StructRet = 1 << 6,
const ZExt = 1 << 7, const ZExt = 1 << 7,
const InReg = 1 << 8,
} }
} }
} }
@ -80,7 +81,7 @@ macro_rules! for_each_kind {
impl ArgAttribute { impl ArgAttribute {
fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) { fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) {
for_each_kind!(self, f, 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[..] { 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 { "x86_64" => if abi == Abi::SysV64 {
cabi_x86_64::compute_abi_info(ccx, self); cabi_x86_64::compute_abi_info(ccx, self);
} else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows { } else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows {

View file

@ -14,7 +14,13 @@ use type_::Type;
use super::common::*; use super::common::*;
use super::machine::*; 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.is_ignore() {
if fty.ret.ty.kind() == Struct { if fty.ret.ty.kind() == Struct {
// Returning a structure. Most often, this will use // 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); 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;
}
}
}
}
} }

View file

@ -150,6 +150,8 @@ from_rust(LLVMRustAttribute kind) {
return Attribute::UWTable; return Attribute::UWTable;
case ZExt: case ZExt:
return Attribute::ZExt; return Attribute::ZExt;
case InReg:
return Attribute::InReg;
default: default:
llvm_unreachable("bad AttributeKind"); llvm_unreachable("bad AttributeKind");
} }

View file

@ -98,6 +98,7 @@ enum LLVMRustAttribute {
StructRet = 16, StructRet = 16,
UWTable = 17, UWTable = 17,
ZExt = 18, ZExt = 18,
InReg = 19,
}; };
typedef struct OpaqueRustString *RustStringRef; typedef struct OpaqueRustString *RustStringRef;