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