]> git.proxmox.com Git - rustc.git/blob - src/librustc_target/abi/call/mips64.rs
New upstream version 1.32.0~beta.2+dfsg1
[rustc.git] / src / librustc_target / abi / call / mips64.rs
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.
4 //
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.
10
11 use abi::call::{ArgAttribute, ArgType, CastTarget, FnType, PassMode, Reg, RegKind, Uniform};
12 use abi::{self, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods};
13
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);
21 return;
22 }
23 }
24 }
25 }
26
27 arg.extend_integer_width_to(bits);
28 }
29
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
33 {
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()),
38 _ => None
39 },
40 _ => None
41 }
42 }
43
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
47 {
48 if !ret.layout.is_aggregate() {
49 extend_integer_width_mips(ret, 64);
50 return;
51 }
52
53 let size = ret.layout.size;
54 let bits = size.bits();
55 if bits <= 128 {
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
58 // float fields.
59
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) {
63 ret.cast_to(reg);
64 return;
65 }
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));
70 return;
71 }
72 }
73 }
74 }
75
76 // Cast to a uniform int structure
77 ret.cast_to(Uniform {
78 unit: Reg::i64(),
79 total: size
80 });
81 } else {
82 ret.make_indirect();
83 }
84 }
85
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
89 {
90 if !arg.layout.is_aggregate() {
91 extend_integer_width_mips(arg, 64);
92 return;
93 }
94
95 let dl = cx.data_layout();
96 let size = arg.layout.size;
97 let mut prefix = [None; 8];
98 let mut prefix_index = 0;
99
100 match arg.layout.fields {
101 abi::FieldPlacement::Array { .. } => {
102 // Arrays are passed indirectly
103 arg.make_indirect();
104 return;
105 }
106 abi::FieldPlacement::Union(_) => {
107 // Unions and are always treated as a series of 64-bit integer chunks
108 },
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;
113
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);
117
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) {
126
127 prefix[prefix_index] = Some(RegKind::Integer);
128 prefix_index += 1;
129 }
130
131 if prefix_index == prefix.len() {
132 break;
133 }
134
135 prefix[prefix_index] = Some(RegKind::Float);
136 prefix_index += 1;
137 last_offset = offset + Reg::f64().size;
138 }
139 }
140 }
141 }
142 }
143 };
144
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 {
148 prefix,
149 prefix_chunk: Size::from_bytes(8),
150 rest: Uniform { unit: Reg::i64(), total: rest_size }
151 });
152 }
153
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
157 {
158 if !fty.ret.is_ignore() {
159 classify_ret_ty(cx, &mut fty.ret);
160 }
161
162 for arg in &mut fty.args {
163 if arg.is_ignore() { continue; }
164 classify_arg_ty(cx, arg);
165 }
166 }