1 // FIXME: This needs an audit for correctness and completeness.
3 use crate::abi
::call
::{
4 ArgAbi
, ArgAttribute
, ArgAttributes
, ArgExtension
, CastTarget
, FnAbi
, Reg
, Uniform
,
6 use crate::abi
::{self, HasDataLayout, Scalar, Size, TyAbiInterface, TyAndLayout}
;
8 #[derive(Clone, Debug)]
10 pub prefix
: [Option
<Reg
>; 8],
11 pub prefix_index
: usize,
12 pub last_offset
: Size
,
14 pub arg_attribute
: ArgAttribute
,
17 fn arg_scalar
<C
>(cx
: &C
, scalar
: &Scalar
, offset
: Size
, mut data
: Sdata
) -> Sdata
21 let dl
= cx
.data_layout();
23 if !scalar
.primitive().is_float() {
27 data
.has_float
= true;
29 if !data
.last_offset
.is_aligned(dl
.f64_align
.abi
) && data
.last_offset
< offset
{
30 if data
.prefix_index
== data
.prefix
.len() {
33 data
.prefix
[data
.prefix_index
] = Some(Reg
::i32());
34 data
.prefix_index
+= 1;
35 data
.last_offset
= data
.last_offset
+ Reg
::i32().size
;
38 for _
in 0..((offset
- data
.last_offset
).bits() / 64)
39 .min((data
.prefix
.len() - data
.prefix_index
) as u64)
41 data
.prefix
[data
.prefix_index
] = Some(Reg
::i64());
42 data
.prefix_index
+= 1;
43 data
.last_offset
= data
.last_offset
+ Reg
::i64().size
;
46 if data
.last_offset
< offset
{
47 if data
.prefix_index
== data
.prefix
.len() {
50 data
.prefix
[data
.prefix_index
] = Some(Reg
::i32());
51 data
.prefix_index
+= 1;
52 data
.last_offset
= data
.last_offset
+ Reg
::i32().size
;
55 if data
.prefix_index
== data
.prefix
.len() {
59 if scalar
.primitive() == abi
::F32
{
60 data
.arg_attribute
= ArgAttribute
::InReg
;
61 data
.prefix
[data
.prefix_index
] = Some(Reg
::f32());
62 data
.last_offset
= offset
+ Reg
::f32().size
;
64 data
.prefix
[data
.prefix_index
] = Some(Reg
::f64());
65 data
.last_offset
= offset
+ Reg
::f64().size
;
67 data
.prefix_index
+= 1;
71 fn arg_scalar_pair
<C
>(
81 data
= arg_scalar(cx
, scalar1
, offset
, data
);
82 match (scalar1
.primitive(), scalar2
.primitive()) {
83 (abi
::F32
, _
) => offset
+= Reg
::f32().size
,
84 (_
, abi
::F64
) => offset
+= Reg
::f64().size
,
85 (abi
::Int(i
, _signed
), _
) => offset
+= i
.size(),
86 (abi
::Pointer
, _
) => offset
+= Reg
::i64().size
,
90 if (offset
.bytes() % 4) != 0 && scalar2
.primitive().is_float() {
91 offset
+= Size
::from_bytes(4 - (offset
.bytes() % 4));
93 data
= arg_scalar(cx
, scalar2
, offset
, data
);
97 fn parse_structure
<'a
, Ty
, C
>(
99 layout
: TyAndLayout
<'a
, Ty
>,
104 Ty
: TyAbiInterface
<'a
, C
> + Copy
,
107 if let abi
::FieldsShape
::Union(_
) = layout
.fields
{
112 abi
::Abi
::Scalar(scalar
) => {
113 data
= arg_scalar(cx
, &scalar
, offset
, data
);
115 abi
::Abi
::Aggregate { .. }
=> {
116 for i
in 0..layout
.fields
.count() {
117 if offset
< layout
.fields
.offset(i
) {
118 offset
= layout
.fields
.offset(i
);
120 data
= parse_structure(cx
, layout
.field(cx
, i
), data
.clone(), offset
);
124 if let abi
::Abi
::ScalarPair(scalar1
, scalar2
) = &layout
.abi
{
125 data
= arg_scalar_pair(cx
, scalar1
, scalar2
, offset
, data
);
133 fn classify_arg
<'a
, Ty
, C
>(cx
: &C
, arg
: &mut ArgAbi
<'a
, Ty
>, in_registers_max
: Size
)
135 Ty
: TyAbiInterface
<'a
, C
> + Copy
,
138 if !arg
.layout
.is_aggregate() {
139 arg
.extend_integer_width_to(64);
143 let total
= arg
.layout
.size
;
144 if total
> in_registers_max
{
149 match arg
.layout
.fields
{
150 abi
::FieldsShape
::Primitive
=> unreachable
!(),
151 abi
::FieldsShape
::Array { .. }
=> {
152 // Arrays are passed indirectly
156 abi
::FieldsShape
::Union(_
) => {
157 // Unions and are always treated as a series of 64-bit integer chunks
159 abi
::FieldsShape
::Arbitrary { .. }
=> {
160 // Structures with floating point numbers need special care.
162 let mut data
= parse_structure(
168 last_offset
: Size
::ZERO
,
170 arg_attribute
: ArgAttribute
::default(),
176 // Structure { float, int, int } doesn't like to be handled like
177 // { float, long int }. Other way around it doesn't mind.
178 if data
.last_offset
< arg
.layout
.size
179 && (data
.last_offset
.bytes() % 8) != 0
180 && data
.prefix_index
< data
.prefix
.len()
182 data
.prefix
[data
.prefix_index
] = Some(Reg
::i32());
183 data
.prefix_index
+= 1;
184 data
.last_offset
+= Reg
::i32().size
;
187 let mut rest_size
= arg
.layout
.size
- data
.last_offset
;
188 if (rest_size
.bytes() % 8) != 0 && data
.prefix_index
< data
.prefix
.len() {
189 data
.prefix
[data
.prefix_index
] = Some(Reg
::i32());
190 rest_size
= rest_size
- Reg
::i32().size
;
193 arg
.cast_to(CastTarget
{
195 rest
: Uniform { unit: Reg::i64(), total: rest_size }
,
196 attrs
: ArgAttributes
{
197 regular
: data
.arg_attribute
,
198 arg_ext
: ArgExtension
::None
,
199 pointee_size
: Size
::ZERO
,
208 arg
.cast_to(Uniform { unit: Reg::i64(), total }
);
211 pub fn compute_abi_info
<'a
, Ty
, C
>(cx
: &C
, fn_abi
: &mut FnAbi
<'a
, Ty
>)
213 Ty
: TyAbiInterface
<'a
, C
> + Copy
,
216 if !fn_abi
.ret
.is_ignore() {
217 classify_arg(cx
, &mut fn_abi
.ret
, Size
::from_bytes(32));
220 for arg
in fn_abi
.args
.iter_mut() {
224 classify_arg(cx
, arg
, Size
::from_bytes(16));