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 use abi
::call
::{ArgType, CastTarget, FnType, Reg, RegKind}
;
15 use abi
::{self, Abi, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods}
;
17 /// Classification of "eightbyte" components.
18 // NB: the order of the variants is from general to specific,
19 // such that `unify(a, b)` is the "smaller" of `a` and `b`.
20 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
27 #[derive(Clone, Copy, Debug)]
30 // Currently supported vector size (AVX-512).
31 const LARGEST_VECTOR_SIZE
: usize = 512;
32 const MAX_EIGHTBYTES
: usize = LARGEST_VECTOR_SIZE
/ 64;
34 fn classify_arg
<'a
, Ty
, C
>(cx
: C
, arg
: &ArgType
<'a
, Ty
>)
35 -> Result
<[Option
<Class
>; MAX_EIGHTBYTES
], Memory
>
36 where Ty
: TyLayoutMethods
<'a
, C
> + Copy
,
37 C
: LayoutOf
<Ty
= Ty
, TyLayout
= TyLayout
<'a
, Ty
>> + HasDataLayout
39 fn classify
<'a
, Ty
, C
>(cx
: C
, layout
: TyLayout
<'a
, Ty
>,
40 cls
: &mut [Option
<Class
>], off
: Size
) -> Result
<(), Memory
>
41 where Ty
: TyLayoutMethods
<'a
, C
> + Copy
,
42 C
: LayoutOf
<Ty
= Ty
, TyLayout
= TyLayout
<'a
, Ty
>> + HasDataLayout
44 if !off
.is_abi_aligned(layout
.align
) {
51 let mut c
= match layout
.abi
{
52 Abi
::Uninhabited
=> return Ok(()),
54 Abi
::Scalar(ref scalar
) => {
57 abi
::Pointer
=> Class
::Int
,
58 abi
::Float(_
) => Class
::Sse
62 Abi
::Vector { .. }
=> Class
::Sse
,
65 Abi
::Aggregate { .. }
=> {
66 match layout
.variants
{
67 abi
::Variants
::Single { .. }
=> {
68 for i
in 0..layout
.fields
.count() {
69 let field_off
= off
+ layout
.fields
.offset(i
);
70 classify(cx
, layout
.field(cx
, i
), cls
, field_off
)?
;
74 abi
::Variants
::Tagged { .. }
|
75 abi
::Variants
::NicheFilling { .. }
=> return Err(Memory
),
81 // Fill in `cls` for scalars (Int/Sse) and vectors (Sse).
82 let first
= (off
.bytes() / 8) as usize;
83 let last
= ((off
.bytes() + layout
.size
.bytes() - 1) / 8) as usize;
84 for cls
in &mut cls
[first
..=last
] {
85 *cls
= Some(cls
.map_or(c
, |old
| old
.min(c
)));
87 // Everything after the first Sse "eightbyte"
88 // component is the upper half of a register.
97 let n
= ((arg
.layout
.size
.bytes() + 7) / 8) as usize;
98 if n
> MAX_EIGHTBYTES
{
102 let mut cls
= [None
; MAX_EIGHTBYTES
];
103 classify(cx
, arg
.layout
, &mut cls
, Size
::ZERO
)?
;
105 if cls
[0] != Some(Class
::Sse
) {
108 if cls
[1..n
].iter().any(|&c
| c
!= Some(Class
::SseUp
)) {
114 if cls
[i
] == Some(Class
::SseUp
) {
115 cls
[i
] = Some(Class
::Sse
);
116 } else if cls
[i
] == Some(Class
::Sse
) {
118 while i
!= n
&& cls
[i
] == Some(Class
::SseUp
) { i += 1; }
128 fn reg_component(cls
: &[Option
<Class
>], i
: &mut usize, size
: Size
) -> Option
<Reg
> {
135 Some(Class
::Int
) => {
137 Some(if size
.bytes() < 8 {
139 kind
: RegKind
::Integer
,
146 Some(Class
::Sse
) => {
147 let vec_len
= 1 + cls
[*i
+1..].iter()
148 .take_while(|&&c
| c
== Some(Class
::SseUp
))
151 Some(if vec_len
== 1 {
158 kind
: RegKind
::Vector
,
159 size
: Size
::from_bytes(8) * (vec_len
as u64)
163 Some(c
) => unreachable
!("reg_component: unhandled class {:?}", c
)
167 fn cast_target(cls
: &[Option
<Class
>], size
: Size
) -> CastTarget
{
169 let lo
= reg_component(cls
, &mut i
, size
).unwrap();
170 let offset
= Size
::from_bytes(8) * (i
as u64);
171 let mut target
= CastTarget
::from(lo
);
173 if let Some(hi
) = reg_component(cls
, &mut i
, size
- offset
) {
174 target
= CastTarget
::pair(lo
, hi
);
177 assert_eq
!(reg_component(cls
, &mut i
, Size
::ZERO
), None
);
181 pub fn compute_abi_info
<'a
, Ty
, C
>(cx
: C
, fty
: &mut FnType
<'a
, Ty
>)
182 where Ty
: TyLayoutMethods
<'a
, C
> + Copy
,
183 C
: LayoutOf
<Ty
= Ty
, TyLayout
= TyLayout
<'a
, Ty
>> + HasDataLayout
185 let mut int_regs
= 6; // RDI, RSI, RDX, RCX, R8, R9
186 let mut sse_regs
= 8; // XMM0-7
188 let mut x86_64_ty
= |arg
: &mut ArgType
<'a
, Ty
>, is_arg
: bool
| {
189 let mut cls_or_mem
= classify_arg(cx
, arg
);
191 let mut needed_int
= 0;
192 let mut needed_sse
= 0;
194 if let Ok(cls
) = cls_or_mem
{
197 Some(Class
::Int
) => needed_int
+= 1,
198 Some(Class
::Sse
) => needed_sse
+= 1,
202 if arg
.layout
.is_aggregate() {
203 if int_regs
< needed_int
|| sse_regs
< needed_sse
{
204 cls_or_mem
= Err(Memory
);
213 arg
.make_indirect_byval();
215 // `sret` parameter thus one less integer register available
221 // split into sized chunks passed individually
222 int_regs
-= needed_int
;
223 sse_regs
-= needed_sse
;
225 if arg
.layout
.is_aggregate() {
226 let size
= arg
.layout
.size
;
227 arg
.cast_to(cast_target(cls
, size
))
229 arg
.extend_integer_width_to(32);
235 if !fty
.ret
.is_ignore() {
236 x86_64_ty(&mut fty
.ret
, false);
239 for arg
in &mut fty
.args
{
240 if arg
.is_ignore() { continue; }
241 x86_64_ty(arg
, true);