1 use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
2 use crate::abi::{self, HasDataLayout, LayoutOf, TyAbiInterface, TyAndLayout};
3 use crate::spec::HasTargetSpec;
11 fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
13 Ty: TyAbiInterface<'a, C> + Copy,
14 C: LayoutOf<'a, Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
17 abi::Abi::Scalar(ref scalar) => scalar.value.is_float(),
18 abi::Abi::Aggregate { .. } => {
19 if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
20 is_single_fp_element(cx, layout.field(cx, 0))
29 pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor)
31 Ty: TyAbiInterface<'a, C> + Copy,
32 C: LayoutOf<'a, Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
34 if !fn_abi.ret.is_ignore() {
35 if fn_abi.ret.layout.is_aggregate() {
36 // Returning a structure. Most often, this will use
37 // a hidden first argument. On some platforms, though,
38 // small structs are returned as integers.
41 // https://www.angelcode.com/dev/callconv/callconv.html
42 // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
43 let t = cx.target_spec();
44 if t.abi_return_struct_as_int {
45 // According to Clang, everyone but MSVC returns single-element
46 // float aggregates directly in a floating-point register.
47 if !t.is_like_msvc && is_single_fp_element(cx, fn_abi.ret.layout) {
48 match fn_abi.ret.layout.size.bytes() {
49 4 => fn_abi.ret.cast_to(Reg::f32()),
50 8 => fn_abi.ret.cast_to(Reg::f64()),
51 _ => fn_abi.ret.make_indirect(),
54 match fn_abi.ret.layout.size.bytes() {
55 1 => fn_abi.ret.cast_to(Reg::i8()),
56 2 => fn_abi.ret.cast_to(Reg::i16()),
57 4 => fn_abi.ret.cast_to(Reg::i32()),
58 8 => fn_abi.ret.cast_to(Reg::i64()),
59 _ => fn_abi.ret.make_indirect(),
63 fn_abi.ret.make_indirect();
66 fn_abi.ret.extend_integer_width_to(32);
70 for arg in &mut fn_abi.args {
74 if arg.layout.is_aggregate() {
75 arg.make_indirect_byval();
77 arg.extend_integer_width_to(32);
81 if flavor == Flavor::Fastcall {
82 // Mark arguments as InReg like clang does it,
83 // so our fastcall is compatible with C/C++ fastcall.
85 // Clang reference: lib/CodeGen/TargetInfo.cpp
86 // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
88 // IsSoftFloatABI is only set to true on ARM platforms,
89 // which in turn can't be x86?
91 let mut free_regs = 2;
93 for arg in &mut fn_abi.args {
94 let attrs = match arg.mode {
96 | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
99 PassMode::Direct(ref mut attrs) => attrs,
101 | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }
102 | PassMode::Cast(_) => {
103 unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
107 // At this point we know this must be a primitive of sorts.
108 let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
109 assert_eq!(unit.size, arg.layout.size);
110 if unit.kind == RegKind::Float {
114 let size_in_regs = (arg.layout.size.bits() + 31) / 32;
116 if size_in_regs == 0 {
120 if size_in_regs > free_regs {
124 free_regs -= size_in_regs;
126 if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
127 attrs.set(ArgAttribute::InReg);