]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/cabi_x86_64.rs
7f2fdbf000b651fd62acfab2cb256881e55375a5
[rust.git] / src / librustc_trans / cabi_x86_64.rs
1 // Copyright 2012-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 // The classification code for the x86_64 ABI is taken from the clay language
12 // https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
13
14 #![allow(non_upper_case_globals)]
15 use self::RegClass::*;
16
17 use llvm::{Integer, Pointer, Float, Double};
18 use llvm::{Struct, Array, Vector};
19 use abi::{self, ArgType, ArgAttribute, FnType};
20 use context::CrateContext;
21 use type_::Type;
22
23 #[derive(Clone, Copy, PartialEq)]
24 enum RegClass {
25     NoClass,
26     Int,
27     SSEFs,
28     SSEFv,
29     SSEDs,
30     SSEDv,
31     SSEInt(/* bitwidth */ u64),
32     /// Data that can appear in the upper half of an SSE register.
33     SSEUp,
34     X87,
35     X87Up,
36     ComplexX87,
37     Memory
38 }
39
40 trait TypeMethods {
41     fn is_reg_ty(&self) -> bool;
42 }
43
44 impl TypeMethods for Type {
45     fn is_reg_ty(&self) -> bool {
46         match self.kind() {
47             Integer | Pointer | Float | Double => true,
48             _ => false
49         }
50     }
51 }
52
53 impl RegClass {
54     fn is_sse(&self) -> bool {
55         match *self {
56             SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true,
57             _ => false
58         }
59     }
60 }
61
62 trait ClassList {
63     fn is_pass_byval(&self) -> bool;
64     fn is_ret_bysret(&self) -> bool;
65 }
66
67 impl ClassList for [RegClass] {
68     fn is_pass_byval(&self) -> bool {
69         if self.is_empty() { return false; }
70
71         let class = self[0];
72            class == Memory
73         || class == X87
74         || class == ComplexX87
75     }
76
77     fn is_ret_bysret(&self) -> bool {
78         if self.is_empty() { return false; }
79
80         self[0] == Memory
81     }
82 }
83
84 fn classify_ty(ty: Type) -> Vec<RegClass> {
85     fn align(off: usize, ty: Type) -> usize {
86         let a = ty_align(ty);
87         return (off + a - 1) / a * a;
88     }
89
90     fn ty_align(ty: Type) -> usize {
91         abi::ty_align(ty, 8)
92     }
93
94     fn ty_size(ty: Type) -> usize {
95         abi::ty_size(ty, 8)
96     }
97
98     fn all_mem(cls: &mut [RegClass]) {
99         for elt in cls {
100             *elt = Memory;
101         }
102     }
103
104     fn unify(cls: &mut [RegClass],
105              i: usize,
106              newv: RegClass) {
107         if cls[i] == newv { return }
108
109         let to_write = match (cls[i], newv) {
110             (NoClass,     _) => newv,
111             (_,           NoClass) => return,
112
113             (Memory,      _) |
114             (_,           Memory) => Memory,
115
116             (Int,         _) |
117             (_,           Int) => Int,
118
119             (X87,         _) |
120             (X87Up,       _) |
121             (ComplexX87,  _) |
122             (_,           X87) |
123             (_,           X87Up) |
124             (_,           ComplexX87) => Memory,
125
126             (SSEFv,       SSEUp) |
127             (SSEFs,       SSEUp) |
128             (SSEDv,       SSEUp) |
129             (SSEDs,       SSEUp) |
130             (SSEInt(_),   SSEUp) => return,
131
132             (..) => newv
133         };
134         cls[i] = to_write;
135     }
136
137     fn classify_struct(tys: &[Type],
138                        cls: &mut [RegClass],
139                        i: usize,
140                        off: usize,
141                        packed: bool) {
142         let mut field_off = off;
143         for ty in tys {
144             if !packed {
145                 field_off = align(field_off, *ty);
146             }
147             classify(*ty, cls, i, field_off);
148             field_off += ty_size(*ty);
149         }
150     }
151
152     fn classify(ty: Type,
153                 cls: &mut [RegClass], ix: usize,
154                 off: usize) {
155         let t_align = ty_align(ty);
156         let t_size = ty_size(ty);
157
158         let misalign = off % t_align;
159         if misalign != 0 {
160             let mut i = off / 8;
161             let e = (off + t_size + 7) / 8;
162             while i < e {
163                 unify(cls, ix + i, Memory);
164                 i += 1;
165             }
166             return;
167         }
168
169         match ty.kind() {
170             Integer |
171             Pointer => {
172                 unify(cls, ix + off / 8, Int);
173             }
174             Float => {
175                 if off % 8 == 4 {
176                     unify(cls, ix + off / 8, SSEFv);
177                 } else {
178                     unify(cls, ix + off / 8, SSEFs);
179                 }
180             }
181             Double => {
182                 unify(cls, ix + off / 8, SSEDs);
183             }
184             Struct => {
185                 classify_struct(&ty.field_types(), cls, ix, off, ty.is_packed());
186             }
187             Array => {
188                 let len = ty.array_length();
189                 let elt = ty.element_type();
190                 let eltsz = ty_size(elt);
191                 let mut i = 0;
192                 while i < len {
193                     classify(elt, cls, ix, off + i * eltsz);
194                     i += 1;
195                 }
196             }
197             Vector => {
198                 let len = ty.vector_length();
199                 let elt = ty.element_type();
200                 let eltsz = ty_size(elt);
201                 let mut reg = match elt.kind() {
202                     Integer => SSEInt(elt.int_width()),
203                     Float => SSEFv,
204                     Double => SSEDv,
205                     _ => bug!("classify: unhandled vector element type")
206                 };
207
208                 let mut i = 0;
209                 while i < len {
210                     unify(cls, ix + (off + i * eltsz) / 8, reg);
211
212                     // everything after the first one is the upper
213                     // half of a register.
214                     reg = SSEUp;
215                     i += 1;
216                 }
217             }
218             _ => bug!("classify: unhandled type")
219         }
220     }
221
222     fn fixup(ty: Type, cls: &mut [RegClass]) {
223         let mut i = 0;
224         let ty_kind = ty.kind();
225         let e = cls.len();
226         if cls.len() > 2 && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) {
227             if cls[i].is_sse() {
228                 i += 1;
229                 while i < e {
230                     if cls[i] != SSEUp {
231                         all_mem(cls);
232                         return;
233                     }
234                     i += 1;
235                 }
236             } else {
237                 all_mem(cls);
238                 return
239             }
240         } else {
241             while i < e {
242                 if cls[i] == Memory {
243                     all_mem(cls);
244                     return;
245                 }
246                 if cls[i] == X87Up {
247                     // for darwin
248                     // cls[i] = SSEDs;
249                     all_mem(cls);
250                     return;
251                 }
252                 if cls[i] == SSEUp {
253                     cls[i] = SSEDv;
254                 } else if cls[i].is_sse() {
255                     i += 1;
256                     while i != e && cls[i] == SSEUp { i += 1; }
257                 } else if cls[i] == X87 {
258                     i += 1;
259                     while i != e && cls[i] == X87Up { i += 1; }
260                 } else {
261                     i += 1;
262                 }
263             }
264         }
265     }
266
267     let words = (ty_size(ty) + 7) / 8;
268     let mut cls = vec![NoClass; words];
269     if words > 4 {
270         all_mem(&mut cls);
271         return cls;
272     }
273     classify(ty, &mut cls, 0, 0);
274     fixup(ty, &mut cls);
275     return cls;
276 }
277
278 fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
279     fn llvec_len(cls: &[RegClass]) -> usize {
280         let mut len = 1;
281         for c in cls {
282             if *c != SSEUp {
283                 break;
284             }
285             len += 1;
286         }
287         return len;
288     }
289
290     let mut tys = Vec::new();
291     let mut i = 0;
292     let e = cls.len();
293     while i < e {
294         match cls[i] {
295             Int => {
296                 tys.push(Type::i64(ccx));
297             }
298             SSEFv | SSEDv | SSEInt(_) => {
299                 let (elts_per_word, elt_ty) = match cls[i] {
300                     SSEFv => (2, Type::f32(ccx)),
301                     SSEDv => (1, Type::f64(ccx)),
302                     SSEInt(bits) => {
303                         assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64,
304                                 "llreg_ty: unsupported SSEInt width {}", bits);
305                         (64 / bits, Type::ix(ccx, bits))
306                     }
307                     _ => bug!(),
308                 };
309                 let vec_len = llvec_len(&cls[i + 1..]);
310                 let vec_ty = Type::vector(&elt_ty, vec_len as u64 * elts_per_word);
311                 tys.push(vec_ty);
312                 i += vec_len;
313                 continue;
314             }
315             SSEFs => {
316                 tys.push(Type::f32(ccx));
317             }
318             SSEDs => {
319                 tys.push(Type::f64(ccx));
320             }
321             _ => bug!("llregtype: unhandled class")
322         }
323         i += 1;
324     }
325     if tys.len() == 1 && tys[0].kind() == Vector {
326         // if the type contains only a vector, pass it as that vector.
327         tys[0]
328     } else {
329         Type::struct_(ccx, &tys, false)
330     }
331 }
332
333 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
334     fn x86_64_ty<F>(ccx: &CrateContext,
335                     arg: &mut ArgType,
336                     is_mem_cls: F,
337                     ind_attr: Option<ArgAttribute>)
338         where F: FnOnce(&[RegClass]) -> bool
339     {
340         if !arg.ty.is_reg_ty() {
341             let cls = classify_ty(arg.ty);
342             if is_mem_cls(&cls) {
343                 arg.make_indirect(ccx);
344                 if let Some(attr) = ind_attr {
345                     arg.attrs.set(attr);
346                 }
347             } else {
348                 arg.cast = Some(llreg_ty(ccx, &cls));
349             }
350         } else {
351             arg.extend_integer_width_to(32);
352         }
353     }
354
355     let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
356     let mut sse_regs = 8; // XMM0-7
357
358     if !fty.ret.is_ignore() {
359         x86_64_ty(ccx, &mut fty.ret, |cls| {
360             if cls.is_ret_bysret() {
361                 // `sret` parameter thus one less register available
362                 int_regs -= 1;
363                 true
364             } else {
365                 false
366             }
367         }, None);
368     }
369
370     for arg in &mut fty.args {
371         if arg.is_ignore() { continue; }
372         x86_64_ty(ccx, arg, |cls| {
373             let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize;
374             let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize;
375             let in_mem = cls.is_pass_byval() ||
376                          int_regs < needed_int ||
377                          sse_regs < needed_sse;
378             if in_mem {
379                 // `byval` parameter thus one less integer register available
380                 int_regs -= 1;
381             } else {
382                 // split into sized chunks passed individually
383                 int_regs -= needed_int;
384                 sse_regs -= needed_sse;
385             }
386             in_mem
387         }, Some(ArgAttribute::ByVal));
388
389         // An integer, pointer, double or float parameter
390         // thus the above closure passed to `x86_64_ty` won't
391         // get called.
392         match arg.ty.kind() {
393             Integer | Pointer => int_regs -= 1,
394             Double | Float => sse_regs -= 1,
395             _ => {}
396         }
397     }
398 }