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.
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.
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
14 #![allow(non_upper_case_globals)]
15 use self::RegClass
::*;
17 use llvm
::{Integer, Pointer, Float, Double}
;
18 use llvm
::{Struct, Array, Attribute, Vector}
;
19 use trans
::cabi
::{ArgType, FnType}
;
20 use trans
::context
::CrateContext
;
21 use trans
::type_
::Type
;
25 #[derive(Clone, Copy, PartialEq)]
33 SSEInt(/* bitwidth */ u64),
34 /// Data that can appear in the upper half of an SSE register.
43 fn is_reg_ty(&self) -> bool
;
46 impl TypeMethods
for Type
{
47 fn is_reg_ty(&self) -> bool
{
49 Integer
| Pointer
| Float
| Double
=> true,
56 fn is_sse(&self) -> bool
{
58 SSEFs
| SSEFv
| SSEDs
| SSEDv
| SSEInt(_
) => true,
65 fn is_pass_byval(&self) -> bool
;
66 fn is_ret_bysret(&self) -> bool
;
69 impl ClassList
for [RegClass
] {
70 fn is_pass_byval(&self) -> bool
{
71 if self.is_empty() { return false; }
76 || class
== ComplexX87
79 fn is_ret_bysret(&self) -> bool
{
80 if self.is_empty() { return false; }
86 fn classify_ty(ty
: Type
) -> Vec
<RegClass
> {
87 fn align(off
: usize, ty
: Type
) -> usize {
89 return (off
+ a
- 1) / a
* a
;
92 fn ty_align(ty
: Type
) -> usize {
94 Integer
=> ((ty
.int_width() as usize) + 7) / 8,
102 let str_tys
= ty
.field_types();
103 str_tys
.iter().fold(1, |a
, t
| cmp
::max(a
, ty_align(*t
)))
107 let elt
= ty
.element_type();
111 let len
= ty
.vector_length();
112 let elt
= ty
.element_type();
115 _
=> panic
!("ty_align: unhandled type")
119 fn ty_size(ty
: Type
) -> usize {
121 Integer
=> (ty
.int_width() as usize + 7) / 8,
126 let str_tys
= ty
.field_types();
128 str_tys
.iter().fold(0, |s
, t
| s
+ ty_size(*t
))
130 let size
= str_tys
.iter().fold(0, |s
, t
| align(s
, *t
) + ty_size(*t
));
135 let len
= ty
.array_length();
136 let elt
= ty
.element_type();
137 let eltsz
= ty_size(elt
);
141 let len
= ty
.vector_length();
142 let elt
= ty
.element_type();
143 let eltsz
= ty_size(elt
);
147 _
=> panic
!("ty_size: unhandled type")
151 fn all_mem(cls
: &mut [RegClass
]) {
157 fn unify(cls
: &mut [RegClass
],
160 if cls
[i
] == newv { return }
162 let to_write
= match (cls
[i
], newv
) {
163 (NoClass
, _
) => newv
,
164 (_
, NoClass
) => return,
167 (_
, Memory
) => Memory
,
177 (_
, ComplexX87
) => Memory
,
183 (SSEInt(_
), SSEUp
) => return,
190 fn classify_struct(tys
: &[Type
],
191 cls
: &mut [RegClass
],
195 let mut field_off
= off
;
198 field_off
= align(field_off
, *ty
);
200 classify(*ty
, cls
, i
, field_off
);
201 field_off
+= ty_size(*ty
);
205 fn classify(ty
: Type
,
206 cls
: &mut [RegClass
], ix
: usize,
208 let t_align
= ty_align(ty
);
209 let t_size
= ty_size(ty
);
211 let misalign
= off
% t_align
;
214 let e
= (off
+ t_size
+ 7) / 8;
216 unify(cls
, ix
+ i
, Memory
);
225 unify(cls
, ix
+ off
/ 8, Int
);
229 unify(cls
, ix
+ off
/ 8, SSEFv
);
231 unify(cls
, ix
+ off
/ 8, SSEFs
);
235 unify(cls
, ix
+ off
/ 8, SSEDs
);
238 classify_struct(&ty
.field_types(), cls
, ix
, off
, ty
.is_packed());
241 let len
= ty
.array_length();
242 let elt
= ty
.element_type();
243 let eltsz
= ty_size(elt
);
246 classify(elt
, cls
, ix
, off
+ i
* eltsz
);
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()),
258 _
=> panic
!("classify: unhandled vector element type")
263 unify(cls
, ix
+ (off
+ i
* eltsz
) / 8, reg
);
265 // everything after the first one is the upper
266 // half of a register.
271 _
=> panic
!("classify: unhandled type")
275 fn fixup(ty
: Type
, cls
: &mut [RegClass
]) {
277 let ty_kind
= ty
.kind();
279 if cls
.len() > 2 && (ty_kind
== Struct
|| ty_kind
== Array
|| ty_kind
== Vector
) {
295 if cls
[i
] == Memory
{
307 } else if cls
[i
].is_sse() {
309 while i
!= e
&& cls
[i
] == SSEUp { i += 1; }
310 } else if cls
[i
] == X87
{
312 while i
!= e
&& cls
[i
] == X87Up { i += 1; }
320 let words
= (ty_size(ty
) + 7) / 8;
321 let mut cls
= vec
![NoClass
; words
];
326 classify(ty
, &mut cls
, 0, 0);
331 fn llreg_ty(ccx
: &CrateContext
, cls
: &[RegClass
]) -> Type
{
332 fn llvec_len(cls
: &[RegClass
]) -> usize {
343 let mut tys
= Vec
::new();
349 tys
.push(Type
::i64(ccx
));
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
)),
356 assert
!(bits
== 8 || bits
== 16 || bits
== 32 || bits
== 64,
357 "llreg_ty: unsupported SSEInt width {}", bits
);
358 (64 / bits
, Type
::ix(ccx
, bits
))
362 let vec_len
= llvec_len(&cls
[i
+ 1..]);
363 let vec_ty
= Type
::vector(&elt_ty
, vec_len
as u64 * elts_per_word
);
369 tys
.push(Type
::f32(ccx
));
372 tys
.push(Type
::f64(ccx
));
374 _
=> panic
!("llregtype: unhandled class")
378 if tys
.len() == 1 && tys
[0].kind() == Vector
{
379 // if the type contains only a vector, pass it as that vector.
382 Type
::struct_(ccx
, &tys
, false)
386 pub fn compute_abi_info(ccx
: &CrateContext
,
389 ret_def
: bool
) -> FnType
{
390 fn x86_64_ty
<F
>(ccx
: &CrateContext
,
395 F
: FnOnce(&[RegClass
]) -> bool
,
398 let cls
= classify_ty(ty
);
399 if is_mem_cls(&cls
) {
400 ArgType
::indirect(ty
, Some(ind_attr
))
403 Some(llreg_ty(ccx
, &cls
)),
408 let attr
= if ty
== Type
::i1(ccx
) { Some(Attribute::ZExt) }
else { None }
;
409 ArgType
::direct(ty
, None
, None
, attr
)
413 let mut int_regs
= 6; // RDI, RSI, RDX, RCX, R8, R9
414 let mut sse_regs
= 8; // XMM0-7
416 let ret_ty
= if ret_def
{
417 x86_64_ty(ccx
, rty
, |cls
| {
418 if cls
.is_ret_bysret() {
419 // `sret` parameter thus one less register available
425 }, Attribute
::StructRet
)
427 ArgType
::direct(Type
::void(ccx
), None
, None
, None
)
430 let mut arg_tys
= Vec
::new();
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
;
439 // `byval` parameter thus one less integer register available
442 // split into sized chunks passed individually
443 int_regs
-= needed_int
;
444 sse_regs
-= needed_sse
;
447 }, Attribute
::ByVal
);
450 // An integer, pointer, double or float parameter
451 // thus the above closure passed to `x86_64_ty` won't
453 if t
.kind() == Integer
|| t
.kind() == Pointer
{
455 } else if t
.kind() == Double
|| t
.kind() == Float
{