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