1 // Copyright 2016 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 use abi
::call
::{ArgAttribute, ArgType, CastTarget, FnType, PassMode, Reg, RegKind, Uniform}
;
12 use abi
::{self, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods}
;
14 fn extend_integer_width_mips
<Ty
>(arg
: &mut ArgType
<Ty
>, bits
: u64) {
15 // Always sign extend u32 values on 64-bit mips
16 if let abi
::Abi
::Scalar(ref scalar
) = arg
.layout
.abi
{
17 if let abi
::Int(i
, signed
) = scalar
.value
{
18 if !signed
&& i
.size().bits() == 32 {
19 if let PassMode
::Direct(ref mut attrs
) = arg
.mode
{
20 attrs
.set(ArgAttribute
::SExt
);
27 arg
.extend_integer_width_to(bits
);
30 fn float_reg
<'a
, Ty
, C
>(cx
: &C
, ret
: &ArgType
<'a
, Ty
>, i
: usize) -> Option
<Reg
>
31 where Ty
: TyLayoutMethods
<'a
, C
> + Copy
,
32 C
: LayoutOf
<Ty
= Ty
, TyLayout
= TyLayout
<'a
, Ty
>> + HasDataLayout
34 match ret
.layout
.field(cx
, i
).abi
{
35 abi
::Abi
::Scalar(ref scalar
) => match scalar
.value
{
36 abi
::Float(abi
::FloatTy
::F32
) => Some(Reg
::f32()),
37 abi
::Float(abi
::FloatTy
::F64
) => Some(Reg
::f64()),
44 fn classify_ret_ty
<'a
, Ty
, C
>(cx
: &C
, ret
: &mut ArgType
<'a
, Ty
>)
45 where Ty
: TyLayoutMethods
<'a
, C
> + Copy
,
46 C
: LayoutOf
<Ty
= Ty
, TyLayout
= TyLayout
<'a
, Ty
>> + HasDataLayout
48 if !ret
.layout
.is_aggregate() {
49 extend_integer_width_mips(ret
, 64);
53 let size
= ret
.layout
.size
;
54 let bits
= size
.bits();
56 // Unlike other architectures which return aggregates in registers, MIPS n64 limits the
57 // use of float registers to structures (not unions) containing exactly one or two
60 if let abi
::FieldPlacement
::Arbitrary { .. }
= ret
.layout
.fields
{
61 if ret
.layout
.fields
.count() == 1 {
62 if let Some(reg
) = float_reg(cx
, ret
, 0) {
66 } else if ret
.layout
.fields
.count() == 2 {
67 if let Some(reg0
) = float_reg(cx
, ret
, 0) {
68 if let Some(reg1
) = float_reg(cx
, ret
, 1) {
69 ret
.cast_to(CastTarget
::pair(reg0
, reg1
));
76 // Cast to a uniform int structure
86 fn classify_arg_ty
<'a
, Ty
, C
>(cx
: &C
, arg
: &mut ArgType
<'a
, Ty
>)
87 where Ty
: TyLayoutMethods
<'a
, C
> + Copy
,
88 C
: LayoutOf
<Ty
= Ty
, TyLayout
= TyLayout
<'a
, Ty
>> + HasDataLayout
90 if !arg
.layout
.is_aggregate() {
91 extend_integer_width_mips(arg
, 64);
95 let dl
= cx
.data_layout();
96 let size
= arg
.layout
.size
;
97 let mut prefix
= [None
; 8];
98 let mut prefix_index
= 0;
100 match arg
.layout
.fields
{
101 abi
::FieldPlacement
::Array { .. }
=> {
102 // Arrays are passed indirectly
106 abi
::FieldPlacement
::Union(_
) => {
107 // Unions and are always treated as a series of 64-bit integer chunks
109 abi
::FieldPlacement
::Arbitrary { .. }
=> {
110 // Structures are split up into a series of 64-bit integer chunks, but any aligned
111 // doubles not part of another aggregate are passed as floats.
112 let mut last_offset
= Size
::ZERO
;
114 for i
in 0..arg
.layout
.fields
.count() {
115 let field
= arg
.layout
.field(cx
, i
);
116 let offset
= arg
.layout
.fields
.offset(i
);
118 // We only care about aligned doubles
119 if let abi
::Abi
::Scalar(ref scalar
) = field
.abi
{
120 if let abi
::Float(abi
::FloatTy
::F64
) = scalar
.value
{
121 if offset
.is_aligned(dl
.f64_align
.abi
) {
122 // Insert enough integers to cover [last_offset, offset)
123 assert
!(last_offset
.is_aligned(dl
.f64_align
.abi
));
124 for _
in 0..((offset
- last_offset
).bits() / 64)
125 .min((prefix
.len() - prefix_index
) as u64) {
127 prefix
[prefix_index
] = Some(RegKind
::Integer
);
131 if prefix_index
== prefix
.len() {
135 prefix
[prefix_index
] = Some(RegKind
::Float
);
137 last_offset
= offset
+ Reg
::f64().size
;
145 // Extract first 8 chunks as the prefix
146 let rest_size
= size
- Size
::from_bytes(8) * prefix_index
as u64;
147 arg
.cast_to(CastTarget
{
149 prefix_chunk
: Size
::from_bytes(8),
150 rest
: Uniform { unit: Reg::i64(), total: rest_size }
154 pub fn compute_abi_info
<'a
, Ty
, C
>(cx
: &C
, fty
: &mut FnType
<'a
, Ty
>)
155 where Ty
: TyLayoutMethods
<'a
, C
> + Copy
,
156 C
: LayoutOf
<Ty
= Ty
, TyLayout
= TyLayout
<'a
, Ty
>> + HasDataLayout
158 if !fty
.ret
.is_ignore() {
159 classify_ret_ty(cx
, &mut fty
.ret
);
162 for arg
in &mut fty
.args
{
163 if arg
.is_ignore() { continue; }
164 classify_arg_ty(cx
, arg
);