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 abi
::{ArgType, FnType}
;
20 use context
::CrateContext
;
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 _
=> bug
!("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 _
=> bug
!("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 _
=> bug
!("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 _
=> bug
!("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 _
=> bug
!("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
, fty
: &mut FnType
) {
387 fn x86_64_ty
<F
>(ccx
: &CrateContext
,
390 ind_attr
: Option
<Attribute
>)
391 where F
: FnOnce(&[RegClass
]) -> bool
393 if !arg
.ty
.is_reg_ty() {
394 let cls
= classify_ty(arg
.ty
);
395 if is_mem_cls(&cls
) {
396 arg
.make_indirect(ccx
);
397 if let Some(attr
) = ind_attr
{
401 arg
.cast
= Some(llreg_ty(ccx
, &cls
));
404 arg
.extend_integer_width_to(32);
408 let mut int_regs
= 6; // RDI, RSI, RDX, RCX, R8, R9
409 let mut sse_regs
= 8; // XMM0-7
411 if !fty
.ret
.is_ignore() {
412 x86_64_ty(ccx
, &mut fty
.ret
, |cls
| {
413 if cls
.is_ret_bysret() {
414 // `sret` parameter thus one less register available
423 for arg
in &mut fty
.args
{
424 if arg
.is_ignore() { continue; }
425 x86_64_ty(ccx
, arg
, |cls
| {
426 let needed_int
= cls
.iter().filter(|&&c
| c
== Int
).count() as isize;
427 let needed_sse
= cls
.iter().filter(|c
| c
.is_sse()).count() as isize;
428 let in_mem
= cls
.is_pass_byval() ||
429 int_regs
< needed_int
||
430 sse_regs
< needed_sse
;
432 // `byval` parameter thus one less integer register available
435 // split into sized chunks passed individually
436 int_regs
-= needed_int
;
437 sse_regs
-= needed_sse
;
440 }, Some(Attribute
::ByVal
));
442 // An integer, pointer, double or float parameter
443 // thus the above closure passed to `x86_64_ty` won't
445 match arg
.ty
.kind() {
446 Integer
| Pointer
=> int_regs
-= 1,
447 Double
| Float
=> sse_regs
-= 1,