]> git.proxmox.com Git - rustc.git/blame - src/librustc_target/abi/call/x86.rs
New upstream version 1.28.0~beta.14+dfsg1
[rustc.git] / src / librustc_target / abi / call / x86.rs
CommitLineData
54a0048b
SL
1// Copyright 2013 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
83c7162d
XL
11use abi::call::{ArgAttribute, FnType, PassMode, Reg, RegKind};
12use abi::{self, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
13use spec::HasTargetSpec;
ea8adc8c 14
32a655c1
SL
15#[derive(PartialEq)]
16pub enum Flavor {
17 General,
18 Fastcall
19}
20
83c7162d
XL
21fn is_single_fp_element<'a, Ty, C>(cx: C, layout: TyLayout<'a, Ty>) -> bool
22 where Ty: TyLayoutMethods<'a, C> + Copy,
23 C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
24{
ff7c6d11 25 match layout.abi {
94b46f34 26 abi::Abi::Scalar(ref scalar) => scalar.value.is_float(),
83c7162d 27 abi::Abi::Aggregate { .. } => {
ff7c6d11 28 if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 {
2c00a5a8 29 is_single_fp_element(cx, layout.field(cx, 0))
ea8adc8c
XL
30 } else {
31 false
32 }
33 }
34 _ => false
35 }
36}
37
83c7162d
XL
38pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>, flavor: Flavor)
39 where Ty: TyLayoutMethods<'a, C> + Copy,
40 C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec
41{
54a0048b 42 if !fty.ret.is_ignore() {
cc61c64b 43 if fty.ret.layout.is_aggregate() {
54a0048b
SL
44 // Returning a structure. Most often, this will use
45 // a hidden first argument. On some platforms, though,
46 // small structs are returned as integers.
47 //
48 // Some links:
49 // http://www.angelcode.com/dev/callconv/callconv.html
50 // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
83c7162d 51 let t = cx.target_spec();
0531ce1d 52 if t.options.abi_return_struct_as_int {
ea8adc8c
XL
53 // According to Clang, everyone but MSVC returns single-element
54 // float aggregates directly in a floating-point register.
2c00a5a8 55 if !t.options.is_like_msvc && is_single_fp_element(cx, fty.ret.layout) {
ff7c6d11
XL
56 match fty.ret.layout.size.bytes() {
57 4 => fty.ret.cast_to(Reg::f32()),
58 8 => fty.ret.cast_to(Reg::f64()),
59 _ => fty.ret.make_indirect()
ea8adc8c
XL
60 }
61 } else {
ff7c6d11
XL
62 match fty.ret.layout.size.bytes() {
63 1 => fty.ret.cast_to(Reg::i8()),
64 2 => fty.ret.cast_to(Reg::i16()),
65 4 => fty.ret.cast_to(Reg::i32()),
66 8 => fty.ret.cast_to(Reg::i64()),
67 _ => fty.ret.make_indirect()
ea8adc8c 68 }
54a0048b
SL
69 }
70 } else {
ff7c6d11 71 fty.ret.make_indirect();
54a0048b
SL
72 }
73 } else {
74 fty.ret.extend_integer_width_to(32);
75 }
76 }
77
78 for arg in &mut fty.args {
79 if arg.is_ignore() { continue; }
cc61c64b 80 if arg.layout.is_aggregate() {
ff7c6d11 81 arg.make_indirect_byval();
54a0048b
SL
82 } else {
83 arg.extend_integer_width_to(32);
84 }
85 }
32a655c1
SL
86
87 if flavor == Flavor::Fastcall {
88 // Mark arguments as InReg like clang does it,
89 // so our fastcall is compatible with C/C++ fastcall.
90
91 // Clang reference: lib/CodeGen/TargetInfo.cpp
92 // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
93
94 // IsSoftFloatABI is only set to true on ARM platforms,
95 // which in turn can't be x86?
96
97 let mut free_regs = 2;
98
99 for arg in &mut fty.args {
ff7c6d11
XL
100 let attrs = match arg.mode {
101 PassMode::Ignore |
102 PassMode::Indirect(_) => continue,
103 PassMode::Direct(ref mut attrs) => attrs,
104 PassMode::Pair(..) |
105 PassMode::Cast(_) => {
83c7162d 106 unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
ff7c6d11
XL
107 }
108 };
32a655c1 109
cc61c64b 110 // At this point we know this must be a primitive of sorts.
2c00a5a8 111 let unit = arg.layout.homogeneous_aggregate(cx).unwrap();
ff7c6d11 112 assert_eq!(unit.size, arg.layout.size);
cc61c64b 113 if unit.kind == RegKind::Float {
32a655c1
SL
114 continue;
115 }
116
ff7c6d11 117 let size_in_regs = (arg.layout.size.bits() + 31) / 32;
32a655c1
SL
118
119 if size_in_regs == 0 {
120 continue;
121 }
122
123 if size_in_regs > free_regs {
124 break;
125 }
126
127 free_regs -= size_in_regs;
128
ff7c6d11
XL
129 if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
130 attrs.set(ArgAttribute::InReg);
32a655c1
SL
131 }
132
133 if free_regs == 0 {
134 break;
135 }
136 }
137 }
54a0048b 138}