]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
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 | ||
1a4d82fc | 11 | #![allow(non_upper_case_globals)] |
223e47cc | 12 | |
85aaf69f | 13 | use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; |
1a4d82fc JJ |
14 | use llvm::{StructRetAttribute, ZExtAttribute}; |
15 | use trans::cabi::{FnType, ArgType}; | |
16 | use trans::context::CrateContext; | |
17 | use trans::type_::Type; | |
970d7e83 | 18 | |
1a4d82fc | 19 | use std::cmp; |
223e47cc | 20 | |
c34b1796 | 21 | fn align_up_to(off: usize, a: usize) -> usize { |
85aaf69f | 22 | return (off + a - 1) / a * a; |
223e47cc LB |
23 | } |
24 | ||
c34b1796 | 25 | fn align(off: usize, ty: Type) -> usize { |
223e47cc LB |
26 | let a = ty_align(ty); |
27 | return align_up_to(off, a); | |
28 | } | |
29 | ||
c34b1796 | 30 | fn ty_align(ty: Type) -> usize { |
970d7e83 | 31 | match ty.kind() { |
c34b1796 | 32 | Integer => ((ty.int_width() as usize) + 7) / 8, |
1a4d82fc | 33 | Pointer => 8, |
970d7e83 LB |
34 | Float => 4, |
35 | Double => 8, | |
36 | Struct => { | |
37 | if ty.is_packed() { | |
38 | 1 | |
39 | } else { | |
40 | let str_tys = ty.field_types(); | |
1a4d82fc | 41 | str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) |
223e47cc | 42 | } |
970d7e83 LB |
43 | } |
44 | Array => { | |
45 | let elt = ty.element_type(); | |
46 | ty_align(elt) | |
47 | } | |
85aaf69f SL |
48 | Vector => { |
49 | let len = ty.vector_length(); | |
50 | let elt = ty.element_type(); | |
51 | ty_align(elt) * len | |
52 | } | |
1a4d82fc | 53 | _ => panic!("ty_align: unhandled type") |
223e47cc LB |
54 | } |
55 | } | |
56 | ||
c34b1796 | 57 | fn ty_size(ty: Type) -> usize { |
970d7e83 | 58 | match ty.kind() { |
c34b1796 | 59 | Integer => ((ty.int_width() as usize) + 7) / 8, |
1a4d82fc | 60 | Pointer => 8, |
970d7e83 LB |
61 | Float => 4, |
62 | Double => 8, | |
63 | Struct => { | |
64 | if ty.is_packed() { | |
65 | let str_tys = ty.field_types(); | |
66 | str_tys.iter().fold(0, |s, t| s + ty_size(*t)) | |
67 | } else { | |
68 | let str_tys = ty.field_types(); | |
69 | let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); | |
223e47cc LB |
70 | align(size, ty) |
71 | } | |
970d7e83 LB |
72 | } |
73 | Array => { | |
74 | let len = ty.array_length(); | |
75 | let elt = ty.element_type(); | |
76 | let eltsz = ty_size(elt); | |
77 | len * eltsz | |
78 | } | |
85aaf69f SL |
79 | Vector => { |
80 | let len = ty.vector_length(); | |
81 | let elt = ty.element_type(); | |
82 | let eltsz = ty_size(elt); | |
83 | len * eltsz | |
84 | } | |
1a4d82fc | 85 | _ => panic!("ty_size: unhandled type") |
223e47cc LB |
86 | } |
87 | } | |
88 | ||
9346a6ac AL |
89 | fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { |
90 | fn check_array(ty: Type) -> Option<(Type, u64)> { | |
91 | let len = ty.array_length() as u64; | |
92 | if len == 0 { | |
93 | return None | |
94 | } | |
95 | let elt = ty.element_type(); | |
96 | ||
97 | // if our element is an HFA/HVA, so are we; multiply members by our len | |
98 | is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members)) | |
99 | } | |
100 | ||
101 | fn check_struct(ty: Type) -> Option<(Type, u64)> { | |
102 | let str_tys = ty.field_types(); | |
103 | if str_tys.len() == 0 { | |
104 | return None | |
105 | } | |
106 | ||
107 | let mut prev_base_ty = None; | |
108 | let mut members = 0; | |
109 | for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) { | |
110 | match (prev_base_ty, opt_homog_agg) { | |
111 | // field isn't itself an HFA, so we aren't either | |
112 | (_, None) => return None, | |
113 | ||
114 | // first field - store its type and number of members | |
115 | (None, Some((field_ty, field_members))) => { | |
116 | prev_base_ty = Some(field_ty); | |
117 | members = field_members; | |
118 | }, | |
119 | ||
120 | // 2nd or later field - give up if it's a different type; otherwise incr. members | |
121 | (Some(prev_ty), Some((field_ty, field_members))) => { | |
122 | if prev_ty != field_ty { | |
123 | return None; | |
124 | } | |
125 | members += field_members; | |
126 | } | |
127 | } | |
128 | } | |
129 | ||
130 | // Because of previous checks, we know prev_base_ty is Some(...) because | |
131 | // 1. str_tys has at least one element; and | |
132 | // 2. prev_base_ty was filled in (or we would've returned early) | |
133 | let (base_ty, members) = (prev_base_ty.unwrap(), members); | |
134 | ||
135 | // Ensure there is no padding. | |
136 | if ty_size(ty) == ty_size(base_ty) * (members as usize) { | |
137 | Some((base_ty, members)) | |
138 | } else { | |
139 | None | |
140 | } | |
141 | } | |
142 | ||
143 | let homog_agg = match ty.kind() { | |
144 | Float => Some((ty, 1)), | |
145 | Double => Some((ty, 1)), | |
146 | Array => check_array(ty), | |
147 | Struct => check_struct(ty), | |
148 | Vector => match ty_size(ty) { | |
149 | 4|8 => Some((ty, 1)), | |
150 | _ => None | |
151 | }, | |
152 | _ => None | |
153 | }; | |
154 | ||
155 | // Ensure we have at most four uniquely addressable members | |
156 | homog_agg.and_then(|(base_ty, members)| { | |
157 | if members > 0 && members <= 4 { | |
158 | Some((base_ty, members)) | |
159 | } else { | |
160 | None | |
161 | } | |
162 | }) | |
163 | } | |
164 | ||
1a4d82fc | 165 | fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType { |
223e47cc | 166 | if is_reg_ty(ty) { |
1a4d82fc JJ |
167 | let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; |
168 | return ArgType::direct(ty, None, None, attr); | |
223e47cc | 169 | } |
9346a6ac AL |
170 | if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) { |
171 | let llty = Type::array(&base_ty, members); | |
172 | return ArgType::direct(ty, Some(llty), None, None); | |
173 | } | |
223e47cc | 174 | let size = ty_size(ty); |
1a4d82fc | 175 | if size <= 16 { |
223e47cc | 176 | let llty = if size <= 1 { |
1a4d82fc | 177 | Type::i8(ccx) |
223e47cc | 178 | } else if size <= 2 { |
1a4d82fc JJ |
179 | Type::i16(ccx) |
180 | } else if size <= 4 { | |
181 | Type::i32(ccx) | |
182 | } else if size <= 8 { | |
183 | Type::i64(ccx) | |
223e47cc | 184 | } else { |
1a4d82fc | 185 | Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) |
223e47cc | 186 | }; |
1a4d82fc | 187 | return ArgType::direct(ty, Some(llty), None, None); |
223e47cc | 188 | } |
1a4d82fc | 189 | ArgType::indirect(ty, Some(StructRetAttribute)) |
223e47cc LB |
190 | } |
191 | ||
1a4d82fc | 192 | fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType { |
223e47cc | 193 | if is_reg_ty(ty) { |
1a4d82fc JJ |
194 | let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; |
195 | return ArgType::direct(ty, None, None, attr); | |
223e47cc | 196 | } |
9346a6ac AL |
197 | if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) { |
198 | let llty = Type::array(&base_ty, members); | |
199 | return ArgType::direct(ty, Some(llty), None, None); | |
200 | } | |
223e47cc | 201 | let size = ty_size(ty); |
1a4d82fc JJ |
202 | if size <= 16 { |
203 | let llty = if size == 0 { | |
c34b1796 | 204 | Type::array(&Type::i64(ccx), 0) |
1a4d82fc JJ |
205 | } else if size == 1 { |
206 | Type::i8(ccx) | |
207 | } else if size == 2 { | |
208 | Type::i16(ccx) | |
209 | } else if size <= 4 { | |
210 | Type::i32(ccx) | |
211 | } else if size <= 8 { | |
212 | Type::i64(ccx) | |
213 | } else { | |
214 | Type::array(&Type::i64(ccx), ((size + 7 ) / 8 ) as u64) | |
215 | }; | |
216 | return ArgType::direct(ty, Some(llty), None, None); | |
217 | } | |
218 | ArgType::indirect(ty, None) | |
223e47cc LB |
219 | } |
220 | ||
970d7e83 LB |
221 | fn is_reg_ty(ty: Type) -> bool { |
222 | match ty.kind() { | |
223 | Integer | |
224 | | Pointer | |
225 | | Float | |
85aaf69f SL |
226 | | Double |
227 | | Vector => true, | |
970d7e83 | 228 | _ => false |
223e47cc LB |
229 | } |
230 | } | |
231 | ||
1a4d82fc JJ |
232 | pub fn compute_abi_info(ccx: &CrateContext, |
233 | atys: &[Type], | |
234 | rty: Type, | |
235 | ret_def: bool) -> FnType { | |
236 | let mut arg_tys = Vec::new(); | |
85aaf69f | 237 | for &aty in atys { |
1a4d82fc JJ |
238 | let ty = classify_arg_ty(ccx, aty); |
239 | arg_tys.push(ty); | |
223e47cc | 240 | } |
223e47cc | 241 | |
1a4d82fc JJ |
242 | let ret_ty = if ret_def { |
243 | classify_ret_ty(ccx, rty) | |
244 | } else { | |
245 | ArgType::direct(Type::void(ccx), None, None, None) | |
246 | }; | |
247 | ||
248 | return FnType { | |
249 | arg_tys: arg_tys, | |
250 | ret_ty: ret_ty, | |
251 | }; | |
223e47cc | 252 | } |