]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/cabi_x86_64.rs
980a70256e9369fb1514f7fffa5ad48d9bac88d3
[rust.git] / src / librustc_trans / 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, Attribute, Vector};
19 use llvm::{StructRetAttribute, ByValAttribute, ZExtAttribute};
20 use trans::cabi::{ArgType, FnType};
21 use trans::context::CrateContext;
22 use trans::type_::Type;
23
24 use std::cmp;
25 use std::iter::repeat;
26
27 #[derive(Clone, Copy, PartialEq)]
28 enum RegClass {
29     NoClass,
30     Int,
31     SSEFs,
32     SSEFv,
33     SSEDs,
34     SSEDv,
35     SSEInt(/* bitwidth */ u64),
36     /// Data that can appear in the upper half of an SSE register.
37     SSEUp,
38     X87,
39     X87Up,
40     ComplexX87,
41     Memory
42 }
43
44 trait TypeMethods {
45     fn is_reg_ty(&self) -> bool;
46 }
47
48 impl TypeMethods for Type {
49     fn is_reg_ty(&self) -> bool {
50         match self.kind() {
51             Integer | Pointer | Float | Double => true,
52             _ => false
53         }
54     }
55 }
56
57 impl RegClass {
58     fn is_sse(&self) -> bool {
59         match *self {
60             SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true,
61             _ => false
62         }
63     }
64 }
65
66 trait ClassList {
67     fn is_pass_byval(&self) -> bool;
68     fn is_ret_bysret(&self) -> bool;
69 }
70
71 impl ClassList for [RegClass] {
72     fn is_pass_byval(&self) -> bool {
73         if self.len() == 0 { return false; }
74
75         let class = self[0];
76            class == Memory
77         || class == X87
78         || class == ComplexX87
79     }
80
81     fn is_ret_bysret(&self) -> bool {
82         if self.len() == 0 { return false; }
83
84         self[0] == Memory
85     }
86 }
87
88 fn classify_ty(ty: Type) -> Vec<RegClass> {
89     fn align(off: uint, ty: Type) -> uint {
90         let a = ty_align(ty);
91         return (off + a - 1u) / a * a;
92     }
93
94     fn ty_align(ty: Type) -> uint {
95         match ty.kind() {
96             Integer => ((ty.int_width() as uint) + 7) / 8,
97             Pointer => 8,
98             Float => 4,
99             Double => 8,
100             Struct => {
101               if ty.is_packed() {
102                 1
103               } else {
104                 let str_tys = ty.field_types();
105                 str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
106               }
107             }
108             Array => {
109                 let elt = ty.element_type();
110                 ty_align(elt)
111             }
112             Vector => {
113                 let len = ty.vector_length();
114                 let elt = ty.element_type();
115                 ty_align(elt) * len
116             }
117             _ => panic!("ty_align: unhandled type")
118         }
119     }
120
121     fn ty_size(ty: Type) -> uint {
122         match ty.kind() {
123             Integer => (ty.int_width() as uint + 7) / 8,
124             Pointer => 8,
125             Float => 4,
126             Double => 8,
127             Struct => {
128                 let str_tys = ty.field_types();
129                 if ty.is_packed() {
130                     str_tys.iter().fold(0, |s, t| s + ty_size(*t))
131                 } else {
132                     let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
133                     align(size, ty)
134                 }
135             }
136             Array => {
137                 let len = ty.array_length();
138                 let elt = ty.element_type();
139                 let eltsz = ty_size(elt);
140                 len * eltsz
141             }
142             Vector => {
143                 let len = ty.vector_length();
144                 let elt = ty.element_type();
145                 let eltsz = ty_size(elt);
146                 len * eltsz
147             }
148
149             _ => panic!("ty_size: unhandled type")
150         }
151     }
152
153     fn all_mem(cls: &mut [RegClass]) {
154         for elt in cls.iter_mut() {
155             *elt = Memory;
156         }
157     }
158
159     fn unify(cls: &mut [RegClass],
160              i: uint,
161              newv: RegClass) {
162         if cls[i] == newv { return }
163
164         let to_write = match (cls[i], newv) {
165             (NoClass,     _) => newv,
166             (_,           NoClass) => return,
167
168             (Memory,      _) |
169             (_,           Memory) => Memory,
170
171             (Int,         _) |
172             (_,           Int) => Int,
173
174             (X87,         _) |
175             (X87Up,       _) |
176             (ComplexX87,  _) |
177             (_,           X87) |
178             (_,           X87Up) |
179             (_,           ComplexX87) => Memory,
180
181             (SSEFv,       SSEUp) |
182             (SSEFs,       SSEUp) |
183             (SSEDv,       SSEUp) |
184             (SSEDs,       SSEUp) |
185             (SSEInt(_),   SSEUp) => return,
186
187             (_,           _) => newv
188         };
189         cls[i] = to_write;
190     }
191
192     fn classify_struct(tys: &[Type],
193                        cls: &mut [RegClass],
194                        i: uint,
195                        off: uint,
196                        packed: bool) {
197         let mut field_off = off;
198         for ty in tys.iter() {
199             if !packed {
200                 field_off = align(field_off, *ty);
201             }
202             classify(*ty, cls, i, field_off);
203             field_off += ty_size(*ty);
204         }
205     }
206
207     fn classify(ty: Type,
208                 cls: &mut [RegClass], ix: uint,
209                 off: uint) {
210         let t_align = ty_align(ty);
211         let t_size = ty_size(ty);
212
213         let misalign = off % t_align;
214         if misalign != 0u {
215             let mut i = off / 8u;
216             let e = (off + t_size + 7u) / 8u;
217             while i < e {
218                 unify(cls, ix + i, Memory);
219                 i += 1u;
220             }
221             return;
222         }
223
224         match ty.kind() {
225             Integer |
226             Pointer => {
227                 unify(cls, ix + off / 8u, Int);
228             }
229             Float => {
230                 if off % 8u == 4u {
231                     unify(cls, ix + off / 8u, SSEFv);
232                 } else {
233                     unify(cls, ix + off / 8u, SSEFs);
234                 }
235             }
236             Double => {
237                 unify(cls, ix + off / 8u, SSEDs);
238             }
239             Struct => {
240                 classify_struct(ty.field_types().as_slice(), cls, ix, off, ty.is_packed());
241             }
242             Array => {
243                 let len = ty.array_length();
244                 let elt = ty.element_type();
245                 let eltsz = ty_size(elt);
246                 let mut i = 0u;
247                 while i < len {
248                     classify(elt, cls, ix, off + i * eltsz);
249                     i += 1u;
250                 }
251             }
252             Vector => {
253                 let len = ty.vector_length();
254                 let elt = ty.element_type();
255                 let eltsz = ty_size(elt);
256                 let mut reg = match elt.kind() {
257                     Integer => SSEInt(elt.int_width()),
258                     Float => SSEFv,
259                     Double => SSEDv,
260                     _ => panic!("classify: unhandled vector element type")
261                 };
262
263                 let mut i = 0u;
264                 while i < len {
265                     unify(cls, ix + (off + i * eltsz) / 8, reg);
266
267                     // everything after the first one is the upper
268                     // half of a register.
269                     reg = SSEUp;
270                     i += 1u;
271                 }
272             }
273             _ => panic!("classify: unhandled type")
274         }
275     }
276
277     fn fixup(ty: Type, cls: &mut [RegClass]) {
278         let mut i = 0u;
279         let ty_kind = ty.kind();
280         let e = cls.len();
281         if cls.len() > 2u && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) {
282             if cls[i].is_sse() {
283                 i += 1u;
284                 while i < e {
285                     if cls[i] != SSEUp {
286                         all_mem(cls);
287                         return;
288                     }
289                     i += 1u;
290                 }
291             } else {
292                 all_mem(cls);
293                 return
294             }
295         } else {
296             while i < e {
297                 if cls[i] == Memory {
298                     all_mem(cls);
299                     return;
300                 }
301                 if cls[i] == X87Up {
302                     // for darwin
303                     // cls[i] = SSEDs;
304                     all_mem(cls);
305                     return;
306                 }
307                 if cls[i] == SSEUp {
308                     cls[i] = SSEDv;
309                 } else if cls[i].is_sse() {
310                     i += 1;
311                     while i != e && cls[i] == SSEUp { i += 1u; }
312                 } else if cls[i] == X87 {
313                     i += 1;
314                     while i != e && cls[i] == X87Up { i += 1u; }
315                 } else {
316                     i += 1;
317                 }
318             }
319         }
320     }
321
322     let words = (ty_size(ty) + 7) / 8;
323     let mut cls: Vec<_> = repeat(NoClass).take(words).collect();
324     if words > 4 {
325         all_mem(cls.as_mut_slice());
326         return cls;
327     }
328     classify(ty, cls.as_mut_slice(), 0, 0);
329     fixup(ty, cls.as_mut_slice());
330     return cls;
331 }
332
333 fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
334     fn llvec_len(cls: &[RegClass]) -> uint {
335         let mut len = 1u;
336         for c in cls.iter() {
337             if *c != SSEUp {
338                 break;
339             }
340             len += 1u;
341         }
342         return len;
343     }
344
345     let mut tys = Vec::new();
346     let mut i = 0u;
347     let e = cls.len();
348     while i < e {
349         match cls[i] {
350             Int => {
351                 tys.push(Type::i64(ccx));
352             }
353             SSEFv | SSEDv | SSEInt(_) => {
354                 let (elts_per_word, elt_ty) = match cls[i] {
355                     SSEFv => (2, Type::f32(ccx)),
356                     SSEDv => (1, Type::f64(ccx)),
357                     SSEInt(bits) => {
358                         assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64,
359                                 "llreg_ty: unsupported SSEInt width {}", bits);
360                         (64 / bits, Type::ix(ccx, bits))
361                     }
362                     _ => unreachable!(),
363                 };
364                 let vec_len = llvec_len(&cls[(i + 1u)..]);
365                 let vec_ty = Type::vector(&elt_ty, vec_len as u64 * elts_per_word);
366                 tys.push(vec_ty);
367                 i += vec_len;
368                 continue;
369             }
370             SSEFs => {
371                 tys.push(Type::f32(ccx));
372             }
373             SSEDs => {
374                 tys.push(Type::f64(ccx));
375             }
376             _ => panic!("llregtype: unhandled class")
377         }
378         i += 1u;
379     }
380     if tys.len() == 1 && tys[0].kind() == Vector {
381         // if the type contains only a vector, pass it as that vector.
382         tys[0]
383     } else {
384         Type::struct_(ccx, tys.as_slice(), false)
385     }
386 }
387
388 pub fn compute_abi_info(ccx: &CrateContext,
389                         atys: &[Type],
390                         rty: Type,
391                         ret_def: bool) -> FnType {
392     fn x86_64_ty<F>(ccx: &CrateContext,
393                     ty: Type,
394                     is_mem_cls: F,
395                     ind_attr: Attribute)
396                     -> ArgType where
397         F: FnOnce(&[RegClass]) -> bool,
398     {
399         if !ty.is_reg_ty() {
400             let cls = classify_ty(ty);
401             if is_mem_cls(cls.as_slice()) {
402                 ArgType::indirect(ty, Some(ind_attr))
403             } else {
404                 ArgType::direct(ty,
405                                 Some(llreg_ty(ccx, cls.as_slice())),
406                                 None,
407                                 None)
408             }
409         } else {
410             let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
411             ArgType::direct(ty, None, None, attr)
412         }
413     }
414
415     let mut arg_tys = Vec::new();
416     for t in atys.iter() {
417         let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), ByValAttribute);
418         arg_tys.push(ty);
419     }
420
421     let ret_ty = if ret_def {
422         x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), StructRetAttribute)
423     } else {
424         ArgType::direct(Type::void(ccx), None, None, None)
425     };
426
427     return FnType {
428         arg_tys: arg_tys,
429         ret_ty: ret_ty,
430     };
431 }