mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #38542 - YaLTeR:fastcall-fix, r=pnkfelix
Fix fastcall not applying inreg attributes to arguments Fixes https://github.com/rust-lang/rust/issues/18086
This commit is contained in:
commit
f536d90c78
@ -117,6 +117,7 @@ pub enum Attribute {
|
|||||||
StructRet = 16,
|
StructRet = 16,
|
||||||
UWTable = 17,
|
UWTable = 17,
|
||||||
ZExt = 18,
|
ZExt = 18,
|
||||||
|
InReg = 19,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// LLVMIntPredicate
|
/// LLVMIntPredicate
|
||||||
|
@ -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 {
|
||||||
|
@ -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,46 @@ 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: lib/CodeGen/TargetInfo.cpp
|
||||||
|
// See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
|
||||||
|
|
||||||
|
// IsSoftFloatABI is only set to true on ARM platforms,
|
||||||
|
// which in turn can't be x86?
|
||||||
|
|
||||||
|
let mut free_regs = 2;
|
||||||
|
|
||||||
|
for arg in &mut fty.args {
|
||||||
|
if arg.is_ignore() || arg.is_indirect() { continue; }
|
||||||
|
|
||||||
|
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 size_in_regs > free_regs {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_regs -= size_in_regs;
|
||||||
|
|
||||||
|
if size <= 32 && (arg.ty.kind() == Pointer || arg.ty.kind() == Integer) {
|
||||||
|
arg.attrs.set(ArgAttribute::InReg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if free_regs == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
85
src/test/codegen/fastcall-inreg.rs
Normal file
85
src/test/codegen/fastcall-inreg.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Checks if the "fastcall" calling convention marks function arguments
|
||||||
|
// as "inreg" like the C/C++ compilers for the platforms.
|
||||||
|
// x86 only.
|
||||||
|
|
||||||
|
// ignore-aarch64
|
||||||
|
// ignore-aarch64_be
|
||||||
|
// ignore-arm
|
||||||
|
// ignore-armeb
|
||||||
|
// ignore-avr
|
||||||
|
// ignore-bpfel
|
||||||
|
// ignore-bpfeb
|
||||||
|
// ignore-hexagon
|
||||||
|
// ignore-mips
|
||||||
|
// ignore-mipsel
|
||||||
|
// ignore-mips64
|
||||||
|
// ignore-mips64el
|
||||||
|
// ignore-msp430
|
||||||
|
// ignore-powerpc64
|
||||||
|
// ignore-powerpc64le
|
||||||
|
// ignore-powerpc
|
||||||
|
// ignore-r600
|
||||||
|
// ignore-amdgcn
|
||||||
|
// ignore-sparc
|
||||||
|
// ignore-sparcv9
|
||||||
|
// ignore-sparcel
|
||||||
|
// ignore-s390x
|
||||||
|
// ignore-tce
|
||||||
|
// ignore-thumb
|
||||||
|
// ignore-thumbeb
|
||||||
|
// ignore-x86_64 no-ignore-x86
|
||||||
|
// ignore-xcore
|
||||||
|
// ignore-nvptx
|
||||||
|
// ignore-nvptx64
|
||||||
|
// ignore-le32
|
||||||
|
// ignore-le64
|
||||||
|
// ignore-amdil
|
||||||
|
// ignore-amdil64
|
||||||
|
// ignore-hsail
|
||||||
|
// ignore-hsail64
|
||||||
|
// ignore-spir
|
||||||
|
// ignore-spir64
|
||||||
|
// ignore-kalimba
|
||||||
|
// ignore-shave
|
||||||
|
// ignore-wasm32
|
||||||
|
// ignore-wasm64
|
||||||
|
|
||||||
|
// compile-flags: -C no-prepopulate-passes
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
mod tests {
|
||||||
|
// CHECK: @f1(i32 inreg, i32 inreg, i32)
|
||||||
|
#[no_mangle]
|
||||||
|
extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
|
||||||
|
|
||||||
|
// CHECK: @f2(i32* inreg, i32* inreg, i32*)
|
||||||
|
#[no_mangle]
|
||||||
|
extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {}
|
||||||
|
|
||||||
|
// CHECK: @f3(float, i32 inreg, i32 inreg, i32)
|
||||||
|
#[no_mangle]
|
||||||
|
extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {}
|
||||||
|
|
||||||
|
// CHECK: @f4(i32 inreg, float, i32 inreg, i32)
|
||||||
|
#[no_mangle]
|
||||||
|
extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {}
|
||||||
|
|
||||||
|
// CHECK: @f5(i64, i32)
|
||||||
|
#[no_mangle]
|
||||||
|
extern "fastcall" fn f5(_: i64, _: i32) {}
|
||||||
|
|
||||||
|
// CHECK: @f6(i1 inreg zeroext, i32 inreg, i32)
|
||||||
|
#[no_mangle]
|
||||||
|
extern "fastcall" fn f6(_: bool, _: i32, _: i32) {}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user