]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/cabi_arm.rs
Refactor determining of relocation model into methods
[rust.git] / src / librustc_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 abi::{FnType, ArgType};
15 use context::CrateContext;
16 use type_::Type;
17
18 use std::cmp;
19
20 pub enum Flavor {
21     General,
22     Ios
23 }
24
25 type TyAlignFn = fn(ty: Type) -> usize;
26
27 fn align_up_to(off: usize, a: usize) -> usize {
28     return (off + a - 1) / a * a;
29 }
30
31 fn align(off: usize, ty: Type, align_fn: TyAlignFn) -> usize {
32     let a = align_fn(ty);
33     return align_up_to(off, a);
34 }
35
36 fn general_ty_align(ty: Type) -> usize {
37     match ty.kind() {
38         Integer => ((ty.int_width() as usize) + 7) / 8,
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();
47                 str_tys.iter().fold(1, |a, t| cmp::max(a, general_ty_align(*t)))
48             }
49         }
50         Array => {
51             let elt = ty.element_type();
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
58         }
59         _ => bug!("ty_align: unhandled type")
60     }
61 }
62
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
70 fn ios_ty_align(ty: Type) -> usize {
71     match ty.kind() {
72         Integer => cmp::min(4, ((ty.int_width() as usize) + 7) / 8),
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)))
82             }
83         }
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         _ => bug!("ty_align: unhandled type")
94     }
95 }
96
97 fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize {
98     match ty.kind() {
99         Integer => ((ty.int_width() as usize) + 7) / 8,
100         Pointer => 4,
101         Float => 4,
102         Double => 8,
103         Struct => {
104             if ty.is_packed() {
105                 let str_tys = ty.field_types();
106                 str_tys.iter().fold(0, |s, t| s + ty_size(*t, align_fn))
107             } else {
108                 let str_tys = ty.field_types();
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)
114             }
115         }
116         Array => {
117             let len = ty.array_length();
118             let elt = ty.element_type();
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);
126             len * eltsz
127         }
128         _ => bug!("ty_size: unhandled type")
129     }
130 }
131
132 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
133     if is_reg_ty(ret.ty) {
134         ret.extend_integer_width_to(32);
135         return;
136     }
137     let size = ty_size(ret.ty, align_fn);
138     if size <= 4 {
139         let llty = if size <= 1 {
140             Type::i8(ccx)
141         } else if size <= 2 {
142             Type::i16(ccx)
143         } else {
144             Type::i32(ccx)
145         };
146         ret.cast = Some(llty);
147         return;
148     }
149     ret.make_indirect(ccx);
150 }
151
152 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) {
153     if is_reg_ty(arg.ty) {
154         arg.extend_integer_width_to(32);
155         return;
156     }
157     let align = align_fn(arg.ty);
158     let size = ty_size(arg.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     arg.cast = Some(llty);
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, fty: &mut FnType, flavor: Flavor) {
179     let align_fn = match flavor {
180         Flavor::General => general_ty_align as TyAlignFn,
181         Flavor::Ios => ios_ty_align as TyAlignFn,
182     };
183
184     if !fty.ret.is_ignore() {
185         classify_ret_ty(ccx, &mut fty.ret, align_fn);
186     }
187
188     for arg in &mut fty.args {
189         if arg.is_ignore() { continue; }
190         classify_arg_ty(ccx, arg, align_fn);
191     }
192 }