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