]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/cabi_mips.rs
librustc: Automatically change uses of `~[T]` to `Vec<T>` in rustc.
[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_pattern_statics)];
12
13 use std::libc::c_uint;
14 use std::cmp;
15 use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
16 use lib::llvm::StructRetAttribute;
17 use middle::trans::context::CrateContext;
18 use middle::trans::context::task_llcx;
19 use middle::trans::cabi::*;
20
21 use middle::trans::type_::Type;
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_size: 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         ArgType::direct(ty, None, None, None)
91     } else {
92         ArgType::indirect(ty, Some(StructRetAttribute))
93     }
94 }
95
96 fn classify_arg_ty(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         ArgType::direct(ty, None, None, None)
107     } else {
108         ArgType::direct(
109             ty,
110             Some(struct_ty(ty)),
111             padding_ty(align, orig_offset),
112             None
113         )
114     }
115 }
116
117 fn is_reg_ty(ty: Type) -> bool {
118     return match ty.kind() {
119         Integer
120         | Pointer
121         | Float
122         | Double => true,
123         _ => false
124     };
125 }
126
127 fn padding_ty(align: uint, offset: uint) -> Option<Type> {
128     if ((align - 1 ) & offset) > 0 {
129         return Some(Type::i32());
130     }
131
132     return None;
133 }
134
135 fn coerce_to_int(size: uint) -> Vec<Type> {
136     let int_ty = Type::i32();
137     let mut args = Vec::new();
138
139     let mut n = size / 32;
140     while n > 0 {
141         args.push(int_ty);
142         n -= 1;
143     }
144
145     let r = size % 32;
146     if r > 0 {
147         unsafe {
148             args.push(Type::from_ref(llvm::LLVMIntTypeInContext(task_llcx(), r as c_uint)));
149         }
150     }
151
152     args
153 }
154
155 fn struct_ty(ty: Type) -> Type {
156     let size = ty_size(ty) * 8;
157     let fields = coerce_to_int(size);
158     return Type::struct_(fields, 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(rty)
167     } else {
168         ArgType::direct(Type::void(), 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(*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 }