]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | // Copyright 2012-2013 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 | ||
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 | |
85aaf69f SL |
20 | pub enum Flavor { |
21 | General, | |
22 | Ios | |
23 | } | |
24 | ||
c34b1796 | 25 | type TyAlignFn = fn(ty: Type) -> usize; |
85aaf69f | 26 | |
c34b1796 | 27 | fn align_up_to(off: usize, a: usize) -> usize { |
85aaf69f | 28 | return (off + a - 1) / a * a; |
223e47cc LB |
29 | } |
30 | ||
c34b1796 | 31 | fn align(off: usize, ty: Type, align_fn: TyAlignFn) -> usize { |
85aaf69f | 32 | let a = align_fn(ty); |
223e47cc LB |
33 | return align_up_to(off, a); |
34 | } | |
35 | ||
c34b1796 | 36 | fn general_ty_align(ty: Type) -> usize { |
970d7e83 | 37 | match ty.kind() { |
c34b1796 | 38 | Integer => ((ty.int_width() as usize) + 7) / 8, |
970d7e83 LB |
39 | Pointer => 4, |
40 | Float => 4, | |
41 | Double => 8, | |
42 | Struct => { | |
43 | if ty.is_packed() { | |
44 | 1 | |
45 | } else { | |
46 | let str_tys = ty.field_types(); | |
85aaf69f | 47 | str_tys.iter().fold(1, |a, t| cmp::max(a, general_ty_align(*t))) |
223e47cc | 48 | } |
970d7e83 LB |
49 | } |
50 | Array => { | |
51 | let elt = ty.element_type(); | |
85aaf69f SL |
52 | general_ty_align(elt) |
53 | } | |
54 | Vector => { | |
55 | let len = ty.vector_length(); | |
56 | let elt = ty.element_type(); | |
57 | general_ty_align(elt) * len | |
970d7e83 | 58 | } |
1a4d82fc | 59 | _ => panic!("ty_align: unhandled type") |
223e47cc LB |
60 | } |
61 | } | |
62 | ||
85aaf69f SL |
63 | // For more information see: |
64 | // ARMv7 | |
65 | // https://developer.apple.com/library/ios/documentation/Xcode/Conceptual | |
66 | // /iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html | |
67 | // ARMv6 | |
68 | // https://developer.apple.com/library/ios/documentation/Xcode/Conceptual | |
69 | // /iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html | |
c34b1796 | 70 | fn ios_ty_align(ty: Type) -> usize { |
970d7e83 | 71 | match ty.kind() { |
c34b1796 | 72 | Integer => cmp::min(4, ((ty.int_width() as usize) + 7) / 8), |
85aaf69f SL |
73 | Pointer => 4, |
74 | Float => 4, | |
75 | Double => 4, | |
76 | Struct => { | |
77 | if ty.is_packed() { | |
78 | 1 | |
79 | } else { | |
80 | let str_tys = ty.field_types(); | |
81 | str_tys.iter().fold(1, |a, t| cmp::max(a, ios_ty_align(*t))) | |
223e47cc | 82 | } |
970d7e83 | 83 | } |
85aaf69f SL |
84 | Array => { |
85 | let elt = ty.element_type(); | |
86 | ios_ty_align(elt) | |
87 | } | |
88 | Vector => { | |
89 | let len = ty.vector_length(); | |
90 | let elt = ty.element_type(); | |
91 | ios_ty_align(elt) * len | |
92 | } | |
93 | _ => panic!("ty_align: unhandled type") | |
94 | } | |
95 | } | |
96 | ||
c34b1796 | 97 | fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize { |
85aaf69f | 98 | match ty.kind() { |
c34b1796 | 99 | Integer => ((ty.int_width() as usize) + 7) / 8, |
970d7e83 LB |
100 | Pointer => 4, |
101 | Float => 4, | |
102 | Double => 8, | |
103 | Struct => { | |
104 | if ty.is_packed() { | |
105 | let str_tys = ty.field_types(); | |
85aaf69f | 106 | str_tys.iter().fold(0, |s, t| s + ty_size(*t, align_fn)) |
970d7e83 LB |
107 | } else { |
108 | let str_tys = ty.field_types(); | |
85aaf69f SL |
109 | let size = str_tys.iter() |
110 | .fold(0, |s, t| { | |
111 | align(s, *t, align_fn) + ty_size(*t, align_fn) | |
112 | }); | |
113 | align(size, ty, align_fn) | |
223e47cc | 114 | } |
970d7e83 LB |
115 | } |
116 | Array => { | |
117 | let len = ty.array_length(); | |
118 | let elt = ty.element_type(); | |
85aaf69f SL |
119 | let eltsz = ty_size(elt, align_fn); |
120 | len * eltsz | |
121 | } | |
122 | Vector => { | |
123 | let len = ty.vector_length(); | |
124 | let elt = ty.element_type(); | |
125 | let eltsz = ty_size(elt, align_fn); | |
970d7e83 LB |
126 | len * eltsz |
127 | } | |
1a4d82fc | 128 | _ => panic!("ty_size: unhandled type") |
223e47cc LB |
129 | } |
130 | } | |
131 | ||
85aaf69f | 132 | fn classify_ret_ty(ccx: &CrateContext, ty: Type, align_fn: TyAlignFn) -> ArgType { |
223e47cc | 133 | if is_reg_ty(ty) { |
d9579d0f | 134 | let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExt) } else { None }; |
1a4d82fc | 135 | return ArgType::direct(ty, None, None, attr); |
223e47cc | 136 | } |
85aaf69f | 137 | let size = ty_size(ty, align_fn); |
223e47cc LB |
138 | if size <= 4 { |
139 | let llty = if size <= 1 { | |
1a4d82fc | 140 | Type::i8(ccx) |
223e47cc | 141 | } else if size <= 2 { |
1a4d82fc | 142 | Type::i16(ccx) |
223e47cc | 143 | } else { |
1a4d82fc | 144 | Type::i32(ccx) |
223e47cc | 145 | }; |
1a4d82fc | 146 | return ArgType::direct(ty, Some(llty), None, None); |
223e47cc | 147 | } |
d9579d0f | 148 | ArgType::indirect(ty, Some(Attribute::StructRet)) |
223e47cc LB |
149 | } |
150 | ||
85aaf69f | 151 | fn classify_arg_ty(ccx: &CrateContext, ty: Type, align_fn: TyAlignFn) -> ArgType { |
223e47cc | 152 | if is_reg_ty(ty) { |
d9579d0f | 153 | let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExt) } else { None }; |
1a4d82fc | 154 | return ArgType::direct(ty, None, None, attr); |
223e47cc | 155 | } |
85aaf69f SL |
156 | let align = align_fn(ty); |
157 | let size = ty_size(ty, align_fn); | |
223e47cc | 158 | let llty = if align <= 4 { |
1a4d82fc | 159 | Type::array(&Type::i32(ccx), ((size + 3) / 4) as u64) |
223e47cc | 160 | } else { |
1a4d82fc | 161 | Type::array(&Type::i64(ccx), ((size + 7) / 8) as u64) |
223e47cc | 162 | }; |
1a4d82fc | 163 | ArgType::direct(ty, Some(llty), None, None) |
223e47cc LB |
164 | } |
165 | ||
970d7e83 LB |
166 | fn is_reg_ty(ty: Type) -> bool { |
167 | match ty.kind() { | |
168 | Integer | |
169 | | Pointer | |
170 | | Float | |
85aaf69f SL |
171 | | Double |
172 | | Vector => true, | |
970d7e83 | 173 | _ => false |
223e47cc LB |
174 | } |
175 | } | |
176 | ||
1a4d82fc JJ |
177 | pub fn compute_abi_info(ccx: &CrateContext, |
178 | atys: &[Type], | |
179 | rty: Type, | |
85aaf69f SL |
180 | ret_def: bool, |
181 | flavor: Flavor) -> FnType { | |
182 | let align_fn = match flavor { | |
183 | Flavor::General => general_ty_align as TyAlignFn, | |
184 | Flavor::Ios => ios_ty_align as TyAlignFn, | |
185 | }; | |
186 | ||
1a4d82fc | 187 | let mut arg_tys = Vec::new(); |
85aaf69f SL |
188 | for &aty in atys { |
189 | let ty = classify_arg_ty(ccx, aty, align_fn); | |
1a4d82fc | 190 | arg_tys.push(ty); |
223e47cc | 191 | } |
223e47cc | 192 | |
1a4d82fc | 193 | let ret_ty = if ret_def { |
85aaf69f | 194 | classify_ret_ty(ccx, rty, align_fn) |
1a4d82fc JJ |
195 | } else { |
196 | ArgType::direct(Type::void(ccx), None, None, None) | |
197 | }; | |
198 | ||
199 | return FnType { | |
200 | arg_tys: arg_tys, | |
201 | ret_ty: ret_ty, | |
202 | }; | |
223e47cc | 203 | } |