]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/trans/cabi_powerpc64.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / librustc_trans / trans / cabi_powerpc64.rs
CommitLineData
9cc50fc6
SL
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
18use llvm::{Integer, Pointer, Float, Double, Struct, Array, Attribute};
19use trans::cabi::{FnType, ArgType};
20use trans::context::CrateContext;
21use trans::type_::Type;
22
23use std::cmp;
24
25fn align_up_to(off: usize, a: usize) -> usize {
26 return (off + a - 1) / a * a;
27}
28
29fn align(off: usize, ty: Type) -> usize {
30 let a = ty_align(ty);
31 return align_up_to(off, a);
32}
33
34fn 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 _ => panic!("ty_align: unhandled type")
53 }
54}
55
56fn 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 _ => panic!("ty_size: unhandled type")
79 }
80}
81
82fn 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
154fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
155 if is_reg_ty(ty) {
156 let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExt) } else { None };
157 return ArgType::direct(ty, None, None, attr);
158 }
159
160 // The PowerPC64 big endian ABI doesn't return aggregates in registers
7453a54e 161 if ccx.sess().target.target.target_endian == "big" {
9cc50fc6
SL
162 return ArgType::indirect(ty, Some(Attribute::StructRet))
163 }
164
165 if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) {
166 let llty = Type::array(&base_ty, members);
167 return ArgType::direct(ty, Some(llty), None, None);
168 }
169 let size = ty_size(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 return ArgType::direct(ty, Some(llty), None, None);
183 }
184
185 ArgType::indirect(ty, Some(Attribute::StructRet))
186}
187
188fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType {
189 if is_reg_ty(ty) {
190 let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExt) } else { None };
191 return ArgType::direct(ty, None, None, attr);
192 }
193 if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) {
194 let llty = Type::array(&base_ty, members);
195 return ArgType::direct(ty, Some(llty), None, None);
196 }
197
198 ArgType::direct(
199 ty,
200 Some(struct_ty(ccx, ty)),
201 None,
202 None
203 )
204}
205
206fn is_reg_ty(ty: Type) -> bool {
207 match ty.kind() {
208 Integer
209 | Pointer
210 | Float
211 | Double => true,
212 _ => false
213 }
214}
215
216fn coerce_to_long(ccx: &CrateContext, size: usize) -> Vec<Type> {
217 let long_ty = Type::i64(ccx);
218 let mut args = Vec::new();
219
220 let mut n = size / 64;
221 while n > 0 {
222 args.push(long_ty);
223 n -= 1;
224 }
225
226 let r = size % 64;
227 if r > 0 {
228 args.push(Type::ix(ccx, r as u64));
229 }
230
231 args
232}
233
234fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
235 let size = ty_size(ty) * 8;
236 Type::struct_(ccx, &coerce_to_long(ccx, size), false)
237}
238
239pub fn compute_abi_info(ccx: &CrateContext,
240 atys: &[Type],
241 rty: Type,
242 ret_def: bool) -> FnType {
243 let ret_ty = if ret_def {
244 classify_ret_ty(ccx, rty)
245 } else {
246 ArgType::direct(Type::void(ccx), None, None, None)
247 };
248
249 let mut arg_tys = Vec::new();
250 for &aty in atys {
251 let ty = classify_arg_ty(ccx, aty);
252 arg_tys.push(ty);
253 };
254
255 return FnType {
256 arg_tys: arg_tys,
257 ret_ty: ret_ty,
258 };
259}