Skip to content

Commit f536d90

Browse files
committed
Auto merge of #38542 - YaLTeR:fastcall-fix, r=pnkfelix
Fix fastcall not applying inreg attributes to arguments Fixes #18086
2 parents 65c043f + 5e2cea9 commit f536d90

File tree

6 files changed

+149
-4
lines changed

6 files changed

+149
-4
lines changed

src/librustc_llvm/ffi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ pub enum Attribute {
117117
StructRet = 16,
118118
UWTable = 17,
119119
ZExt = 18,
120+
InReg = 19,
120121
}
121122

122123
/// LLVMIntPredicate

src/librustc_trans/abi.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ mod attr_impl {
5858
// The subset of llvm::Attribute needed for arguments, packed into a bitfield.
5959
bitflags! {
6060
#[derive(Default, Debug)]
61-
flags ArgAttribute : u8 {
61+
flags ArgAttribute : u16 {
6262
const ByVal = 1 << 0,
6363
const NoAlias = 1 << 1,
6464
const NoCapture = 1 << 2,
@@ -67,6 +67,7 @@ mod attr_impl {
6767
const SExt = 1 << 5,
6868
const StructRet = 1 << 6,
6969
const ZExt = 1 << 7,
70+
const InReg = 1 << 8,
7071
}
7172
}
7273
}
@@ -80,7 +81,7 @@ macro_rules! for_each_kind {
8081
impl ArgAttribute {
8182
fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) {
8283
for_each_kind!(self, f,
83-
ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt)
84+
ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
8485
}
8586
}
8687

@@ -573,7 +574,14 @@ impl FnType {
573574
}
574575

575576
match &ccx.sess().target.target.arch[..] {
576-
"x86" => cabi_x86::compute_abi_info(ccx, self),
577+
"x86" => {
578+
let flavor = if abi == Abi::Fastcall {
579+
cabi_x86::Flavor::Fastcall
580+
} else {
581+
cabi_x86::Flavor::General
582+
};
583+
cabi_x86::compute_abi_info(ccx, self, flavor);
584+
},
577585
"x86_64" => if abi == Abi::SysV64 {
578586
cabi_x86_64::compute_abi_info(ccx, self);
579587
} else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows {

src/librustc_trans/cabi_x86.rs

+49-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ use type_::Type;
1414
use super::common::*;
1515
use super::machine::*;
1616

17-
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
17+
#[derive(PartialEq)]
18+
pub enum Flavor {
19+
General,
20+
Fastcall
21+
}
22+
23+
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
1824
if !fty.ret.is_ignore() {
1925
if fty.ret.ty.kind() == Struct {
2026
// Returning a structure. Most often, this will use
@@ -51,4 +57,46 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
5157
arg.extend_integer_width_to(32);
5258
}
5359
}
60+
61+
if flavor == Flavor::Fastcall {
62+
// Mark arguments as InReg like clang does it,
63+
// so our fastcall is compatible with C/C++ fastcall.
64+
65+
// Clang reference: lib/CodeGen/TargetInfo.cpp
66+
// See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
67+
68+
// IsSoftFloatABI is only set to true on ARM platforms,
69+
// which in turn can't be x86?
70+
71+
let mut free_regs = 2;
72+
73+
for arg in &mut fty.args {
74+
if arg.is_ignore() || arg.is_indirect() { continue; }
75+
76+
if arg.ty.kind() == Float {
77+
continue;
78+
}
79+
80+
let size = llbitsize_of_real(ccx, arg.ty);
81+
let size_in_regs = (size + 31) / 32;
82+
83+
if size_in_regs == 0 {
84+
continue;
85+
}
86+
87+
if size_in_regs > free_regs {
88+
break;
89+
}
90+
91+
free_regs -= size_in_regs;
92+
93+
if size <= 32 && (arg.ty.kind() == Pointer || arg.ty.kind() == Integer) {
94+
arg.attrs.set(ArgAttribute::InReg);
95+
}
96+
97+
if free_regs == 0 {
98+
break;
99+
}
100+
}
101+
}
54102
}

src/rustllvm/RustWrapper.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ from_rust(LLVMRustAttribute kind) {
150150
return Attribute::UWTable;
151151
case ZExt:
152152
return Attribute::ZExt;
153+
case InReg:
154+
return Attribute::InReg;
153155
default:
154156
llvm_unreachable("bad AttributeKind");
155157
}

src/rustllvm/rustllvm.h

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ enum LLVMRustAttribute {
9898
StructRet = 16,
9999
UWTable = 17,
100100
ZExt = 18,
101+
InReg = 19,
101102
};
102103

103104
typedef struct OpaqueRustString *RustStringRef;

src/test/codegen/fastcall-inreg.rs

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Checks if the "fastcall" calling convention marks function arguments
12+
// as "inreg" like the C/C++ compilers for the platforms.
13+
// x86 only.
14+
15+
// ignore-aarch64
16+
// ignore-aarch64_be
17+
// ignore-arm
18+
// ignore-armeb
19+
// ignore-avr
20+
// ignore-bpfel
21+
// ignore-bpfeb
22+
// ignore-hexagon
23+
// ignore-mips
24+
// ignore-mipsel
25+
// ignore-mips64
26+
// ignore-mips64el
27+
// ignore-msp430
28+
// ignore-powerpc64
29+
// ignore-powerpc64le
30+
// ignore-powerpc
31+
// ignore-r600
32+
// ignore-amdgcn
33+
// ignore-sparc
34+
// ignore-sparcv9
35+
// ignore-sparcel
36+
// ignore-s390x
37+
// ignore-tce
38+
// ignore-thumb
39+
// ignore-thumbeb
40+
// ignore-x86_64 no-ignore-x86
41+
// ignore-xcore
42+
// ignore-nvptx
43+
// ignore-nvptx64
44+
// ignore-le32
45+
// ignore-le64
46+
// ignore-amdil
47+
// ignore-amdil64
48+
// ignore-hsail
49+
// ignore-hsail64
50+
// ignore-spir
51+
// ignore-spir64
52+
// ignore-kalimba
53+
// ignore-shave
54+
// ignore-wasm32
55+
// ignore-wasm64
56+
57+
// compile-flags: -C no-prepopulate-passes
58+
59+
#![crate_type = "lib"]
60+
61+
mod tests {
62+
// CHECK: @f1(i32 inreg, i32 inreg, i32)
63+
#[no_mangle]
64+
extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
65+
66+
// CHECK: @f2(i32* inreg, i32* inreg, i32*)
67+
#[no_mangle]
68+
extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {}
69+
70+
// CHECK: @f3(float, i32 inreg, i32 inreg, i32)
71+
#[no_mangle]
72+
extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {}
73+
74+
// CHECK: @f4(i32 inreg, float, i32 inreg, i32)
75+
#[no_mangle]
76+
extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {}
77+
78+
// CHECK: @f5(i64, i32)
79+
#[no_mangle]
80+
extern "fastcall" fn f5(_: i64, _: i32) {}
81+
82+
// CHECK: @f6(i1 inreg zeroext, i32 inreg, i32)
83+
#[no_mangle]
84+
extern "fastcall" fn f6(_: bool, _: i32, _: i32) {}
85+
}

0 commit comments

Comments
 (0)