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 llvm
::{StructRetAttribute, ByValAttribute, ZExtAttribute}
;
20 use trans
::cabi
::{ArgType, FnType}
;
21 use trans
::context
::CrateContext
;
22 use trans
::type_
::Type
;
25 use std
::iter
::repeat
;
27 #[derive(Clone, Copy, PartialEq)]
35 SSEInt(/* bitwidth */ u64),
36 /// Data that can appear in the upper half of an SSE register.
45 fn is_reg_ty(&self) -> bool
;
48 impl TypeMethods
for Type
{
49 fn is_reg_ty(&self) -> bool
{
51 Integer
| Pointer
| Float
| Double
=> true,
58 fn is_sse(&self) -> bool
{
60 SSEFs
| SSEFv
| SSEDs
| SSEDv
| SSEInt(_
) => true,
67 fn is_pass_byval(&self) -> bool
;
68 fn is_ret_bysret(&self) -> bool
;
71 impl ClassList
for [RegClass
] {
72 fn is_pass_byval(&self) -> bool
{
73 if self.is_empty() { return false; }
78 || class
== ComplexX87
81 fn is_ret_bysret(&self) -> bool
{
82 if self.is_empty() { return false; }
88 fn classify_ty(ty
: Type
) -> Vec
<RegClass
> {
89 fn align(off
: usize, ty
: Type
) -> usize {
91 return (off
+ a
- 1) / a
* a
;
94 fn ty_align(ty
: Type
) -> usize {
96 Integer
=> ((ty
.int_width() as usize) + 7) / 8,
104 let str_tys
= ty
.field_types();
105 str_tys
.iter().fold(1, |a
, t
| cmp
::max(a
, ty_align(*t
)))
109 let elt
= ty
.element_type();
113 let len
= ty
.vector_length();
114 let elt
= ty
.element_type();
117 _
=> panic
!("ty_align: unhandled type")
121 fn ty_size(ty
: Type
) -> usize {
123 Integer
=> (ty
.int_width() as usize + 7) / 8,
128 let str_tys
= ty
.field_types();
130 str_tys
.iter().fold(0, |s
, t
| s
+ ty_size(*t
))
132 let size
= str_tys
.iter().fold(0, |s
, t
| align(s
, *t
) + ty_size(*t
));
137 let len
= ty
.array_length();
138 let elt
= ty
.element_type();
139 let eltsz
= ty_size(elt
);
143 let len
= ty
.vector_length();
144 let elt
= ty
.element_type();
145 let eltsz
= ty_size(elt
);
149 _
=> panic
!("ty_size: unhandled type")
153 fn all_mem(cls
: &mut [RegClass
]) {
159 fn unify(cls
: &mut [RegClass
],
162 if cls
[i
] == newv { return }
164 let to_write
= match (cls
[i
], newv
) {
165 (NoClass
, _
) => newv
,
166 (_
, NoClass
) => return,
169 (_
, Memory
) => Memory
,
179 (_
, ComplexX87
) => Memory
,
185 (SSEInt(_
), SSEUp
) => return,
192 fn classify_struct(tys
: &[Type
],
193 cls
: &mut [RegClass
],
197 let mut field_off
= off
;
200 field_off
= align(field_off
, *ty
);
202 classify(*ty
, cls
, i
, field_off
);
203 field_off
+= ty_size(*ty
);
207 fn classify(ty
: Type
,
208 cls
: &mut [RegClass
], ix
: usize,
210 let t_align
= ty_align(ty
);
211 let t_size
= ty_size(ty
);
213 let misalign
= off
% t_align
;
216 let e
= (off
+ t_size
+ 7) / 8;
218 unify(cls
, ix
+ i
, Memory
);
227 unify(cls
, ix
+ off
/ 8, Int
);
231 unify(cls
, ix
+ off
/ 8, SSEFv
);
233 unify(cls
, ix
+ off
/ 8, SSEFs
);
237 unify(cls
, ix
+ off
/ 8, SSEDs
);
240 classify_struct(&ty
.field_types(), cls
, ix
, off
, ty
.is_packed());
243 let len
= ty
.array_length();
244 let elt
= ty
.element_type();
245 let eltsz
= ty_size(elt
);
248 classify(elt
, cls
, ix
, off
+ i
* eltsz
);
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()),
260 _
=> panic
!("classify: unhandled vector element type")
265 unify(cls
, ix
+ (off
+ i
* eltsz
) / 8, reg
);
267 // everything after the first one is the upper
268 // half of a register.
273 _
=> panic
!("classify: unhandled type")
277 fn fixup(ty
: Type
, cls
: &mut [RegClass
]) {
279 let ty_kind
= ty
.kind();
281 if cls
.len() > 2 && (ty_kind
== Struct
|| ty_kind
== Array
|| ty_kind
== Vector
) {
297 if cls
[i
] == Memory
{
309 } else if cls
[i
].is_sse() {
311 while i
!= e
&& cls
[i
] == SSEUp { i += 1; }
312 } else if cls
[i
] == X87
{
314 while i
!= e
&& cls
[i
] == X87Up { i += 1; }
322 let words
= (ty_size(ty
) + 7) / 8;
323 let mut cls
: Vec
<_
> = repeat(NoClass
).take(words
).collect();
328 classify(ty
, &mut cls
, 0, 0);
333 fn llreg_ty(ccx
: &CrateContext
, cls
: &[RegClass
]) -> Type
{
334 fn llvec_len(cls
: &[RegClass
]) -> usize {
345 let mut tys
= Vec
::new();
351 tys
.push(Type
::i64(ccx
));
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
)),
358 assert
!(bits
== 8 || bits
== 16 || bits
== 32 || bits
== 64,
359 "llreg_ty: unsupported SSEInt width {}", bits
);
360 (64 / bits
, Type
::ix(ccx
, bits
))
364 let vec_len
= llvec_len(&cls
[i
+ 1..]);
365 let vec_ty
= Type
::vector(&elt_ty
, vec_len
as u64 * elts_per_word
);
371 tys
.push(Type
::f32(ccx
));
374 tys
.push(Type
::f64(ccx
));
376 _
=> panic
!("llregtype: unhandled class")
380 if tys
.len() == 1 && tys
[0].kind() == Vector
{
381 // if the type contains only a vector, pass it as that vector.
384 Type
::struct_(ccx
, &tys
, false)
388 pub fn compute_abi_info(ccx
: &CrateContext
,
391 ret_def
: bool
) -> FnType
{
392 fn x86_64_ty
<F
>(ccx
: &CrateContext
,
397 F
: FnOnce(&[RegClass
]) -> bool
,
400 let cls
= classify_ty(ty
);
401 if is_mem_cls(&cls
) {
402 ArgType
::indirect(ty
, Some(ind_attr
))
405 Some(llreg_ty(ccx
, &cls
)),
410 let attr
= if ty
== Type
::i1(ccx
) { Some(ZExtAttribute) }
else { None }
;
411 ArgType
::direct(ty
, None
, None
, attr
)
415 let mut arg_tys
= Vec
::new();
417 let ty
= x86_64_ty(ccx
, *t
, |cls
| cls
.is_pass_byval(), ByValAttribute
);
421 let ret_ty
= if ret_def
{
422 x86_64_ty(ccx
, rty
, |cls
| cls
.is_ret_bysret(), StructRetAttribute
)
424 ArgType
::direct(Type
::void(ccx
), None
, None
, None
)