]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/cabi_mips.rs
complete openbsd support for `std::env`
[rust.git] / src / librustc_trans / 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_upper_case_globals)]
12
13 use libc::c_uint;
14 use std::cmp;
15 use llvm;
16 use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
17 use llvm::{StructRetAttribute, ZExtAttribute};
18 use trans::cabi::{ArgType, FnType};
19 use trans::context::CrateContext;
20 use trans::type_::Type;
21
22 fn align_up_to(off: uint, a: uint) -> uint {
23     return (off + a - 1) / 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 => ((ty.int_width() as uint) + 7) / 8,
34         Pointer => 4,
35         Float => 4,
36         Double => 8,
37         Struct => {
38           if ty.is_packed() {
39             1
40           } else {
41             let str_tys = ty.field_types();
42             str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
43           }
44         }
45         Array => {
46             let elt = ty.element_type();
47             ty_align(elt)
48         }
49         Vector => {
50             let len = ty.vector_length();
51             let elt = ty.element_type();
52             ty_align(elt) * len
53         }
54         _ => panic!("ty_align: unhandled type")
55     }
56 }
57
58 fn ty_size(ty: Type) -> uint {
59     match ty.kind() {
60         Integer => ((ty.int_width() as uint) + 7) / 8,
61         Pointer => 4,
62         Float => 4,
63         Double => 8,
64         Struct => {
65             if ty.is_packed() {
66                 let str_tys = ty.field_types();
67                 str_tys.iter().fold(0, |s, t| s + ty_size(*t))
68             } else {
69                 let str_tys = ty.field_types();
70                 let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
71                 align(size, ty)
72             }
73         }
74         Array => {
75             let len = ty.array_length();
76             let elt = ty.element_type();
77             let eltsz = ty_size(elt);
78             len * eltsz
79         }
80         Vector => {
81             let len = ty.vector_length();
82             let elt = ty.element_type();
83             let eltsz = ty_size(elt);
84             len * eltsz
85         }
86         _ => panic!("ty_size: unhandled type")
87     }
88 }
89
90 fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
91     if is_reg_ty(ty) {
92         let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
93         ArgType::direct(ty, None, None, attr)
94     } else {
95         ArgType::indirect(ty, Some(StructRetAttribute))
96     }
97 }
98
99 fn classify_arg_ty(ccx: &CrateContext, ty: Type, offset: &mut uint) -> ArgType {
100     let orig_offset = *offset;
101     let size = ty_size(ty) * 8;
102     let mut align = ty_align(ty);
103
104     align = cmp::min(cmp::max(align, 4), 8);
105     *offset = align_up_to(*offset, align);
106     *offset += align_up_to(size, align * 8) / 8;
107
108     if is_reg_ty(ty) {
109         let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
110         ArgType::direct(ty, None, None, attr)
111     } else {
112         ArgType::direct(
113             ty,
114             Some(struct_ty(ccx, ty)),
115             padding_ty(ccx, align, orig_offset),
116             None
117         )
118     }
119 }
120
121 fn is_reg_ty(ty: Type) -> bool {
122     return match ty.kind() {
123         Integer
124         | Pointer
125         | Float
126         | Double
127         | Vector => true,
128         _ => false
129     };
130 }
131
132 fn padding_ty(ccx: &CrateContext, align: uint, offset: uint) -> Option<Type> {
133     if ((align - 1 ) & offset) > 0 {
134         Some(Type::i32(ccx))
135     } else {
136         None
137     }
138 }
139
140 fn coerce_to_int(ccx: &CrateContext, size: uint) -> Vec<Type> {
141     let int_ty = Type::i32(ccx);
142     let mut args = Vec::new();
143
144     let mut n = size / 32;
145     while n > 0 {
146         args.push(int_ty);
147         n -= 1;
148     }
149
150     let r = size % 32;
151     if r > 0 {
152         unsafe {
153             args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
154         }
155     }
156
157     args
158 }
159
160 fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
161     let size = ty_size(ty) * 8;
162     Type::struct_(ccx, coerce_to_int(ccx, size).as_slice(), false)
163 }
164
165 pub fn compute_abi_info(ccx: &CrateContext,
166                         atys: &[Type],
167                         rty: Type,
168                         ret_def: bool) -> FnType {
169     let ret_ty = if ret_def {
170         classify_ret_ty(ccx, rty)
171     } else {
172         ArgType::direct(Type::void(ccx), None, None, None)
173     };
174
175     let sret = ret_ty.is_indirect();
176     let mut arg_tys = Vec::new();
177     let mut offset = if sret { 4 } else { 0 };
178
179     for aty in atys {
180         let ty = classify_arg_ty(ccx, *aty, &mut offset);
181         arg_tys.push(ty);
182     };
183
184     return FnType {
185         arg_tys: arg_tys,
186         ret_ty: ret_ty,
187     };
188 }