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