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