1 use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
2 use crate::abi::{self, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
3 use crate::spec::HasTargetSpec;
11 fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyLayout<'a, Ty>) -> bool
13 Ty: TyLayoutMethods<'a, C> + Copy,
14 C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'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: TyLayoutMethods<'a, C> + Copy,
32 C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'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 // http://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.options.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.options.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 {
95 PassMode::Ignore | PassMode::Indirect(_, None) => continue,
96 PassMode::Direct(ref mut attrs) => attrs,
97 PassMode::Pair(..) | PassMode::Indirect(_, Some(_)) | PassMode::Cast(_) => {
98 unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
102 // At this point we know this must be a primitive of sorts.
103 let unit = arg.layout.homogeneous_aggregate(cx).unit().unwrap();
104 assert_eq!(unit.size, arg.layout.size);
105 if unit.kind == RegKind::Float {
109 let size_in_regs = (arg.layout.size.bits() + 31) / 32;
111 if size_in_regs == 0 {
115 if size_in_regs > free_regs {
119 free_regs -= size_in_regs;
121 if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
122 attrs.set(ArgAttribute::InReg);