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