]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/cabi_mips.rs
return &mut T from the arenas, not &T
[rust.git] / src / librustc / middle / trans / cabi_mips.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 libc::c_uint;
14 use std::cmp;
15 use llvm;
16 use llvm::{Integer, Pointer, Float, Double, Struct, Array};
17 use llvm::{StructRetAttribute, ZExtAttribute};
18 use middle::trans::cabi::{ArgType, FnType};
19 use middle::trans::context::CrateContext;
20 use middle::trans::type_::Type;
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         _ => fail!("ty_size: 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         _ => fail!("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         ArgType::direct(ty, None, None, attr)
91     } else {
92         ArgType::indirect(ty, Some(StructRetAttribute))
93     }
94 }
95
96 fn classify_arg_ty(ccx: &CrateContext, ty: Type, offset: &mut uint) -> ArgType {
97     let orig_offset = *offset;
98     let size = ty_size(ty) * 8;
99     let mut align = ty_align(ty);
100
101     align = cmp::min(cmp::max(align, 4), 8);
102     *offset = align_up_to(*offset, align);
103     *offset += align_up_to(size, align * 8) / 8;
104
105     if is_reg_ty(ty) {
106         let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
107         ArgType::direct(ty, None, None, attr)
108     } else {
109         ArgType::direct(
110             ty,
111             Some(struct_ty(ccx, ty)),
112             padding_ty(ccx, align, orig_offset),
113             None
114         )
115     }
116 }
117
118 fn is_reg_ty(ty: Type) -> bool {
119     return match ty.kind() {
120         Integer
121         | Pointer
122         | Float
123         | Double => true,
124         _ => false
125     };
126 }
127
128 fn padding_ty(ccx: &CrateContext, align: uint, offset: uint) -> Option<Type> {
129     if ((align - 1 ) & offset) > 0 {
130         Some(Type::i32(ccx))
131     } else {
132         None
133     }
134 }
135
136 fn coerce_to_int(ccx: &CrateContext, size: uint) -> Vec<Type> {
137     let int_ty = Type::i32(ccx);
138     let mut args = Vec::new();
139
140     let mut n = size / 32;
141     while n > 0 {
142         args.push(int_ty);
143         n -= 1;
144     }
145
146     let r = size % 32;
147     if r > 0 {
148         unsafe {
149             args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
150         }
151     }
152
153     args
154 }
155
156 fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
157     let size = ty_size(ty) * 8;
158     Type::struct_(ccx, coerce_to_int(ccx, size).as_slice(), false)
159 }
160
161 pub fn compute_abi_info(ccx: &CrateContext,
162                         atys: &[Type],
163                         rty: Type,
164                         ret_def: bool) -> FnType {
165     let ret_ty = if ret_def {
166         classify_ret_ty(ccx, rty)
167     } else {
168         ArgType::direct(Type::void(ccx), None, None, None)
169     };
170
171     let sret = ret_ty.is_indirect();
172     let mut arg_tys = Vec::new();
173     let mut offset = if sret { 4 } else { 0 };
174
175     for aty in atys.iter() {
176         let ty = classify_arg_ty(ccx, *aty, &mut offset);
177         arg_tys.push(ty);
178     };
179
180     return FnType {
181         arg_tys: arg_tys,
182         ret_ty: ret_ty,
183     };
184 }