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