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