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