]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/cabi_powerpc64.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_trans / cabi_powerpc64.rs
1 // Copyright 2014-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 // FIXME: The PowerPC64 ABI needs to zero or sign extend function
12 // call parameters, but compute_abi_info() is passed LLVM types
13 // which have no sign information.
14 //
15 // Alignment of 128 bit types is not currently handled, this will
16 // need to be fixed when PowerPC vector support is added.
17
18 use llvm::{Integer, Pointer, Float, Double, Struct, Array};
19 use abi::{FnType, ArgType};
20 use context::CrateContext;
21 use type_::Type;
22
23 use std::cmp;
24
25 fn align_up_to(off: usize, a: usize) -> usize {
26 return (off + a - 1) / a * a;
27 }
28
29 fn align(off: usize, ty: Type) -> usize {
30 let a = ty_align(ty);
31 return align_up_to(off, a);
32 }
33
34 fn ty_align(ty: Type) -> usize {
35 match ty.kind() {
36 Integer => ((ty.int_width() as usize) + 7) / 8,
37 Pointer => 8,
38 Float => 4,
39 Double => 8,
40 Struct => {
41 if ty.is_packed() {
42 1
43 } else {
44 let str_tys = ty.field_types();
45 str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
46 }
47 }
48 Array => {
49 let elt = ty.element_type();
50 ty_align(elt)
51 }
52 _ => bug!("ty_align: unhandled type")
53 }
54 }
55
56 fn ty_size(ty: Type) -> usize {
57 match ty.kind() {
58 Integer => ((ty.int_width() as usize) + 7) / 8,
59 Pointer => 8,
60 Float => 4,
61 Double => 8,
62 Struct => {
63 if ty.is_packed() {
64 let str_tys = ty.field_types();
65 str_tys.iter().fold(0, |s, t| s + ty_size(*t))
66 } else {
67 let str_tys = ty.field_types();
68 let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
69 align(size, ty)
70 }
71 }
72 Array => {
73 let len = ty.array_length();
74 let elt = ty.element_type();
75 let eltsz = ty_size(elt);
76 len * eltsz
77 }
78 _ => bug!("ty_size: unhandled type")
79 }
80 }
81
82 fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
83 fn check_array(ty: Type) -> Option<(Type, u64)> {
84 let len = ty.array_length() as u64;
85 if len == 0 {
86 return None
87 }
88 let elt = ty.element_type();
89
90 // if our element is an HFA/HVA, so are we; multiply members by our len
91 is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members))
92 }
93
94 fn check_struct(ty: Type) -> Option<(Type, u64)> {
95 let str_tys = ty.field_types();
96 if str_tys.len() == 0 {
97 return None
98 }
99
100 let mut prev_base_ty = None;
101 let mut members = 0;
102 for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) {
103 match (prev_base_ty, opt_homog_agg) {
104 // field isn't itself an HFA, so we aren't either
105 (_, None) => return None,
106
107 // first field - store its type and number of members
108 (None, Some((field_ty, field_members))) => {
109 prev_base_ty = Some(field_ty);
110 members = field_members;
111 },
112
113 // 2nd or later field - give up if it's a different type; otherwise incr. members
114 (Some(prev_ty), Some((field_ty, field_members))) => {
115 if prev_ty != field_ty {
116 return None;
117 }
118 members += field_members;
119 }
120 }
121 }
122
123 // Because of previous checks, we know prev_base_ty is Some(...) because
124 // 1. str_tys has at least one element; and
125 // 2. prev_base_ty was filled in (or we would've returned early)
126 let (base_ty, members) = (prev_base_ty.unwrap(), members);
127
128 // Ensure there is no padding.
129 if ty_size(ty) == ty_size(base_ty) * (members as usize) {
130 Some((base_ty, members))
131 } else {
132 None
133 }
134 }
135
136 let homog_agg = match ty.kind() {
137 Float => Some((ty, 1)),
138 Double => Some((ty, 1)),
139 Array => check_array(ty),
140 Struct => check_struct(ty),
141 _ => None
142 };
143
144 // Ensure we have at most eight uniquely addressable members
145 homog_agg.and_then(|(base_ty, members)| {
146 if members > 0 && members <= 8 {
147 Some((base_ty, members))
148 } else {
149 None
150 }
151 })
152 }
153
154 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
155 if is_reg_ty(ret.ty) {
156 ret.extend_integer_width_to(64);
157 return;
158 }
159
160 // The PowerPC64 big endian ABI doesn't return aggregates in registers
161 if ccx.sess().target.target.target_endian == "big" {
162 ret.make_indirect(ccx);
163 }
164
165 if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
166 ret.cast = Some(Type::array(&base_ty, members));
167 return;
168 }
169 let size = ty_size(ret.ty);
170 if size <= 16 {
171 let llty = if size <= 1 {
172 Type::i8(ccx)
173 } else if size <= 2 {
174 Type::i16(ccx)
175 } else if size <= 4 {
176 Type::i32(ccx)
177 } else if size <= 8 {
178 Type::i64(ccx)
179 } else {
180 Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64)
181 };
182 ret.cast = Some(llty);
183 return;
184 }
185
186 ret.make_indirect(ccx);
187 }
188
189 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
190 if is_reg_ty(arg.ty) {
191 arg.extend_integer_width_to(64);
192 return;
193 }
194
195 if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
196 arg.cast = Some(Type::array(&base_ty, members));
197 return;
198 }
199
200 arg.cast = Some(struct_ty(ccx, arg.ty));
201 }
202
203 fn is_reg_ty(ty: Type) -> bool {
204 match ty.kind() {
205 Integer
206 | Pointer
207 | Float
208 | Double => true,
209 _ => false
210 }
211 }
212
213 fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec<Type> {
214 let long_ty = Type::i64(ccx);
215 let mut args = Vec::new();
216
217 let mut n = size / 64;
218 while n > 0 {
219 args.push(long_ty);
220 n -= 1;
221 }
222
223 let r = size % 64;
224 if r > 0 {
225 args.push(Type::ix(ccx, r as u64));
226 }
227
228 args
229 }
230
231 fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
232 let size = ty_size(ty) * 8;
233 Type::struct_(ccx, &coerce_to_long(ccx, size), false)
234 }
235
236 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
237 if !fty.ret.is_ignore() {
238 classify_ret_ty(ccx, &mut fty.ret);
239 }
240
241 for arg in &mut fty.args {
242 if arg.is_ignore() { continue; }
243 classify_arg_ty(ccx, arg);
244 }
245 }