]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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}; | |
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 - 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_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 | _ => 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 | 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 | } |