]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/trans/cabi_x86_64.rs
Imported Upstream version 1.0.0~beta.3
[rustc.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.is_empty() { 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.is_empty() { return false; }
83
84 self[0] == Memory
85 }
86 }
87
88 fn classify_ty(ty: Type) -> Vec<RegClass> {
89 fn align(off: usize, ty: Type) -> usize {
90 let a = ty_align(ty);
91 return (off + a - 1) / a * a;
92 }
93
94 fn ty_align(ty: Type) -> usize {
95 match ty.kind() {
96 Integer => ((ty.int_width() as usize) + 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) -> usize {
122 match ty.kind() {
123 Integer => (ty.int_width() as usize + 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 {
155 *elt = Memory;
156 }
157 }
158
159 fn unify(cls: &mut [RegClass],
160 i: usize,
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: usize,
195 off: usize,
196 packed: bool) {
197 let mut field_off = off;
198 for ty in tys {
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: usize,
209 off: usize) {
210 let t_align = ty_align(ty);
211 let t_size = ty_size(ty);
212
213 let misalign = off % t_align;
214 if misalign != 0 {
215 let mut i = off / 8;
216 let e = (off + t_size + 7) / 8;
217 while i < e {
218 unify(cls, ix + i, Memory);
219 i += 1;
220 }
221 return;
222 }
223
224 match ty.kind() {
225 Integer |
226 Pointer => {
227 unify(cls, ix + off / 8, Int);
228 }
229 Float => {
230 if off % 8 == 4 {
231 unify(cls, ix + off / 8, SSEFv);
232 } else {
233 unify(cls, ix + off / 8, SSEFs);
234 }
235 }
236 Double => {
237 unify(cls, ix + off / 8, SSEDs);
238 }
239 Struct => {
240 classify_struct(&ty.field_types(), 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 = 0;
247 while i < len {
248 classify(elt, cls, ix, off + i * eltsz);
249 i += 1;
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 = 0;
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 += 1;
271 }
272 }
273 _ => panic!("classify: unhandled type")
274 }
275 }
276
277 fn fixup(ty: Type, cls: &mut [RegClass]) {
278 let mut i = 0;
279 let ty_kind = ty.kind();
280 let e = cls.len();
281 if cls.len() > 2 && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) {
282 if cls[i].is_sse() {
283 i += 1;
284 while i < e {
285 if cls[i] != SSEUp {
286 all_mem(cls);
287 return;
288 }
289 i += 1;
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 += 1; }
312 } else if cls[i] == X87 {
313 i += 1;
314 while i != e && cls[i] == X87Up { i += 1; }
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(&mut cls);
326 return cls;
327 }
328 classify(ty, &mut cls, 0, 0);
329 fixup(ty, &mut cls);
330 return cls;
331 }
332
333 fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
334 fn llvec_len(cls: &[RegClass]) -> usize {
335 let mut len = 1;
336 for c in cls {
337 if *c != SSEUp {
338 break;
339 }
340 len += 1;
341 }
342 return len;
343 }
344
345 let mut tys = Vec::new();
346 let mut i = 0;
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 + 1..]);
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 += 1;
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, 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) {
402 ArgType::indirect(ty, Some(ind_attr))
403 } else {
404 ArgType::direct(ty,
405 Some(llreg_ty(ccx, &cls)),
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 {
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 }