]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/cabi_arm.rs
ca80ce26ae3962b0ff33dccb4a7f01f0b999da62
[rust.git] / src / librustc / middle / 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_uppercase_pattern_statics)];
12
13 use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
14 use lib::llvm::StructRetAttribute;
15 use middle::trans::cabi::{FnType, ArgType};
16 use middle::trans::context::CrateContext;
17
18 use middle::trans::type_::Type;
19
20 use std::cmp;
21 use std::option::{None, Some};
22
23 fn align_up_to(off: uint, a: uint) -> uint {
24     return (off + a - 1u) / a * a;
25 }
26
27 fn align(off: uint, ty: Type) -> uint {
28     let a = ty_align(ty);
29     return align_up_to(off, a);
30 }
31
32 fn ty_align(ty: Type) -> uint {
33     match ty.kind() {
34         Integer => {
35             unsafe {
36                 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
37             }
38         }
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, ty_align(*t)))
48             }
49         }
50         Array => {
51             let elt = ty.element_type();
52             ty_align(elt)
53         }
54         _ => fail!("ty_align: unhandled type")
55     }
56 }
57
58 fn ty_size(ty: Type) -> uint {
59     match ty.kind() {
60         Integer => {
61             unsafe {
62                 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
63             }
64         }
65         Pointer => 4,
66         Float => 4,
67         Double => 8,
68         Struct => {
69             if ty.is_packed() {
70                 let str_tys = ty.field_types();
71                 str_tys.iter().fold(0, |s, t| s + ty_size(*t))
72             } else {
73                 let str_tys = ty.field_types();
74                 let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
75                 align(size, ty)
76             }
77         }
78         Array => {
79             let len = ty.array_length();
80             let elt = ty.element_type();
81             let eltsz = ty_size(elt);
82             len * eltsz
83         }
84         _ => fail!("ty_size: unhandled type")
85     }
86 }
87
88 fn classify_ret_ty(ty: Type) -> ArgType {
89     if is_reg_ty(ty) {
90         return ArgType::direct(ty, None, None, None);
91     }
92     let size = ty_size(ty);
93     if size <= 4 {
94         let llty = if size <= 1 {
95             Type::i8()
96         } else if size <= 2 {
97             Type::i16()
98         } else {
99             Type::i32()
100         };
101         return ArgType::direct(ty, Some(llty), None, None);
102     }
103     ArgType::indirect(ty, Some(StructRetAttribute))
104 }
105
106 fn classify_arg_ty(ty: Type) -> ArgType {
107     if is_reg_ty(ty) {
108         return ArgType::direct(ty, None, None, None);
109     }
110     let align = ty_align(ty);
111     let size = ty_size(ty);
112     let llty = if align <= 4 {
113         Type::array(&Type::i32(), ((size + 3) / 4) as u64)
114     } else {
115         Type::array(&Type::i64(), ((size + 7) / 8) as u64)
116     };
117     ArgType::direct(ty, Some(llty), None, None)
118 }
119
120 fn is_reg_ty(ty: Type) -> bool {
121     match ty.kind() {
122         Integer
123         | Pointer
124         | Float
125         | Double => true,
126         _ => false
127     }
128 }
129
130 pub fn compute_abi_info(_ccx: &CrateContext,
131                         atys: &[Type],
132                         rty: Type,
133                         ret_def: bool) -> FnType {
134     let mut arg_tys = ~[];
135     for &aty in atys.iter() {
136         let ty = classify_arg_ty(aty);
137         arg_tys.push(ty);
138     }
139
140     let ret_ty = if ret_def {
141         classify_ret_ty(rty)
142     } else {
143         ArgType::direct(Type::void(), None, None, None)
144     };
145
146     return FnType {
147         arg_tys: arg_tys,
148         ret_ty: ret_ty,
149     };
150 }