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 // The classification code for the x86_64 ABI is taken from the clay language
12 // https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
13
14 #![allow(non_uppercase_pattern_statics)]
15
16 use lib::llvm::{llvm, Integer, Pointer, Float, Double};
17 use lib::llvm::{Struct, Array, Attribute};
18 use lib::llvm::{StructRetAttribute, ByValAttribute};
19 use middle::trans::cabi::*;
20 use middle::trans::context::CrateContext;
21 use middle::trans::type_::Type;
22
23 use std::cmp;
24
25 #[deriving(Clone, Eq)]
26 enum RegClass {
27 NoClass,
28 Int,
29 SSEFs,
30 SSEFv,
31 SSEDs,
32 SSEDv,
33 SSEInt,
34 SSEUp,
35 X87,
36 X87Up,
37 ComplexX87,
38 Memory
39 }
40
41 trait TypeMethods {
42 fn is_reg_ty(&self) -> bool;
43 }
44
45 impl TypeMethods for Type {
46 fn is_reg_ty(&self) -> bool {
47 match self.kind() {
48 Integer | Pointer | Float | Double => true,
49 _ => false
50 }
51 }
52 }
53
54 impl RegClass {
55 fn is_sse(&self) -> bool {
56 match *self {
57 SSEFs | SSEFv | SSEDs | SSEDv => true,
58 _ => false
59 }
60 }
61 }
62
63 trait ClassList {
64 fn is_pass_byval(&self) -> bool;
65 fn is_ret_bysret(&self) -> bool;
66 }
67
68 impl<'a> ClassList for &'a [RegClass] {
69 fn is_pass_byval(&self) -> bool {
70 if self.len() == 0 { return false; }
71
72 let class = self[0];
73 class == Memory
74 || class == X87
75 || class == ComplexX87
76 }
77
78 fn is_ret_bysret(&self) -> bool {
79 if self.len() == 0 { return false; }
80
81 self[0] == Memory
82 }
83 }
84
85 fn classify_ty(ty: Type) -> Vec<RegClass> {
86 fn align(off: uint, ty: Type) -> uint {
87 let a = ty_align(ty);
88 return (off + a - 1u) / a * a;
89 }
90
91 fn ty_align(ty: Type) -> uint {
92 match ty.kind() {
93 Integer => {
94 unsafe {
95 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
96 }
97 }
98 Pointer => 8,
99 Float => 4,
100 Double => 8,
101 Struct => {
102 if ty.is_packed() {
103 1
104 } else {
105 let str_tys = ty.field_types();
106 str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
107 }
108 }
109 Array => {
110 let elt = ty.element_type();
111 ty_align(elt)
112 }
113 _ => fail!("ty_size: unhandled type")
114 }
115 }
116
117 fn ty_size(ty: Type) -> uint {
118 match ty.kind() {
119 Integer => {
120 unsafe {
121 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
122 }
123 }
124 Pointer => 8,
125 Float => 4,
126 Double => 8,
127 Struct => {
128 let str_tys = ty.field_types();
129 if ty.is_packed() {
130 str_tys.iter().fold(0, |s, t| s + ty_size(*t))
131 } else {
132 let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
133 align(size, ty)
134 }
135 }
136 Array => {
137 let len = ty.array_length();
138 let elt = ty.element_type();
139 let eltsz = ty_size(elt);
140 len * eltsz
141 }
142 _ => fail!("ty_size: unhandled type")
143 }
144 }
145
146 fn all_mem(cls: &mut [RegClass]) {
147 for elt in cls.mut_iter() {
148 *elt = Memory;
149 }
150 }
151
152 fn unify(cls: &mut [RegClass],
153 i: uint,
154 newv: RegClass) {
155 if cls[i] == newv {
156 return;
157 } else if cls[i] == NoClass {
158 cls[i] = newv;
159 } else if newv == NoClass {
160 return;
161 } else if cls[i] == Memory || newv == Memory {
162 cls[i] = Memory;
163 } else if cls[i] == Int || newv == Int {
164 cls[i] = Int;
165 } else if cls[i] == X87 ||
166 cls[i] == X87Up ||
167 cls[i] == ComplexX87 ||
168 newv == X87 ||
169 newv == X87Up ||
170 newv == ComplexX87 {
171 cls[i] = Memory;
172 } else {
173 cls[i] = newv;
174 }
175 }
176
177 fn classify_struct(tys: &[Type],
178 cls: &mut [RegClass], i: uint,
179 off: uint) {
180 let mut field_off = off;
181 for ty in tys.iter() {
182 field_off = align(field_off, *ty);
183 classify(*ty, cls, i, field_off);
184 field_off += ty_size(*ty);
185 }
186 }
187
188 fn classify(ty: Type,
189 cls: &mut [RegClass], ix: uint,
190 off: uint) {
191 let t_align = ty_align(ty);
192 let t_size = ty_size(ty);
193
194 let misalign = off % t_align;
195 if misalign != 0u {
196 let mut i = off / 8u;
197 let e = (off + t_size + 7u) / 8u;
198 while i < e {
199 unify(cls, ix + i, Memory);
200 i += 1u;
201 }
202 return;
203 }
204
205 match ty.kind() {
206 Integer |
207 Pointer => {
208 unify(cls, ix + off / 8u, Int);
209 }
210 Float => {
211 if off % 8u == 4u {
212 unify(cls, ix + off / 8u, SSEFv);
213 } else {
214 unify(cls, ix + off / 8u, SSEFs);
215 }
216 }
217 Double => {
218 unify(cls, ix + off / 8u, SSEDs);
219 }
220 Struct => {
221 classify_struct(ty.field_types().as_slice(), cls, ix, off);
222 }
223 Array => {
224 let len = ty.array_length();
225 let elt = ty.element_type();
226 let eltsz = ty_size(elt);
227 let mut i = 0u;
228 while i < len {
229 classify(elt, cls, ix, off + i * eltsz);
230 i += 1u;
231 }
232 }
233 _ => fail!("classify: unhandled type")
234 }
235 }
236
237 fn fixup(ty: Type, cls: &mut [RegClass]) {
238 let mut i = 0u;
239 let ty_kind = ty.kind();
240 let e = cls.len();
241 if cls.len() > 2u && (ty_kind == Struct || ty_kind == Array) {
242 if cls[i].is_sse() {
243 i += 1u;
244 while i < e {
245 if cls[i] != SSEUp {
246 all_mem(cls);
247 return;
248 }
249 i += 1u;
250 }
251 } else {
252 all_mem(cls);
253 return
254 }
255 } else {
256 while i < e {
257 if cls[i] == Memory {
258 all_mem(cls);
259 return;
260 }
261 if cls[i] == X87Up {
262 // for darwin
263 // cls[i] = SSEDs;
264 all_mem(cls);
265 return;
266 }
267 if cls[i] == SSEUp {
268 cls[i] = SSEDv;
269 } else if cls[i].is_sse() {
270 i += 1;
271 while i != e && cls[i] == SSEUp { i += 1u; }
272 } else if cls[i] == X87 {
273 i += 1;
274 while i != e && cls[i] == X87Up { i += 1u; }
275 } else {
276 i += 1;
277 }
278 }
279 }
280 }
281
282 let words = (ty_size(ty) + 7) / 8;
283 let mut cls = Vec::from_elem(words, NoClass);
284 if words > 4 {
285 all_mem(cls.as_mut_slice());
286 return cls;
287 }
288 classify(ty, cls.as_mut_slice(), 0, 0);
289 fixup(ty, cls.as_mut_slice());
290 return cls;
291 }
292
293 fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
294 fn llvec_len(cls: &[RegClass]) -> uint {
295 let mut len = 1u;
296 for c in cls.iter() {
297 if *c != SSEUp {
298 break;
299 }
300 len += 1u;
301 }
302 return len;
303 }
304
305 let mut tys = Vec::new();
306 let mut i = 0u;
307 let e = cls.len();
308 while i < e {
309 match cls[i] {
310 Int => {
311 tys.push(Type::i64(ccx));
312 }
313 SSEFv => {
314 let vec_len = llvec_len(cls.tailn(i + 1u));
315 let vec_ty = Type::vector(&Type::f32(ccx), (vec_len * 2u) as u64);
316 tys.push(vec_ty);
317 i += vec_len;
318 continue;
319 }
320 SSEFs => {
321 tys.push(Type::f32(ccx));
322 }
323 SSEDs => {
324 tys.push(Type::f64(ccx));
325 }
326 _ => fail!("llregtype: unhandled class")
327 }
328 i += 1u;
329 }
330 return Type::struct_(ccx, tys.as_slice(), false);
331 }
332
333 pub fn compute_abi_info(ccx: &CrateContext,
334 atys: &[Type],
335 rty: Type,
336 ret_def: bool) -> FnType {
337 fn x86_64_ty(ccx: &CrateContext,
338 ty: Type,
339 is_mem_cls: |cls: &[RegClass]| -> bool,
340 attr: Attribute)
341 -> ArgType {
342 if !ty.is_reg_ty() {
343 let cls = classify_ty(ty);
344 if is_mem_cls(cls.as_slice()) {
345 ArgType::indirect(ty, Some(attr))
346 } else {
347 ArgType::direct(ty,
348 Some(llreg_ty(ccx, cls.as_slice())),
349 None,
350 None)
351 }
352 } else {
353 ArgType::direct(ty, None, None, None)
354 }
355 }
356
357 let mut arg_tys = Vec::new();
358 for t in atys.iter() {
359 let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), ByValAttribute);
360 arg_tys.push(ty);
361 }
362
363 let ret_ty = if ret_def {
364 x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), StructRetAttribute)
365 } else {
366 ArgType::direct(Type::void(ccx), None, None, None)
367 };
368
369 return FnType {
370 arg_tys: arg_tys,
371 ret_ty: ret_ty,
372 };
373 }
librustc/middle/trans/cabi_x86_64.rs:117:4-117:4 -fn- definition:
fn ty_size(ty: Type) -> uint {
match ty.kind() {
Integer => {
references:- 7131: } else {
132: let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
133: align(size, ty)
--
138: let elt = ty.element_type();
139: let eltsz = ty_size(elt);
140: len * eltsz
--
191: let t_align = ty_align(ty);
192: let t_size = ty_size(ty);
--
225: let elt = ty.element_type();
226: let eltsz = ty_size(elt);
227: let mut i = 0u;
--
282: let words = (ty_size(ty) + 7) / 8;
283: let mut cls = Vec::from_elem(words, NoClass);
librustc/middle/trans/cabi_x86_64.rs:86:4-86:4 -fn- definition:
fn align(off: uint, ty: Type) -> uint {
let a = ty_align(ty);
return (off + a - 1u) / a * a;
references:- 3181: for ty in tys.iter() {
182: field_off = align(field_off, *ty);
183: classify(*ty, cls, i, field_off);
librustc/middle/trans/cabi_x86_64.rs:152:4-152:4 -fn- definition:
fn unify(cls: &mut [RegClass],
i: uint,
newv: RegClass) {
references:- 5217: Double => {
218: unify(cls, ix + off / 8u, SSEDs);
219: }
librustc/middle/trans/cabi_x86_64.rs:91:4-91:4 -fn- definition:
fn ty_align(ty: Type) -> uint {
match ty.kind() {
Integer => {
references:- 4190: off: uint) {
191: let t_align = ty_align(ty);
192: let t_size = ty_size(ty);
librustc/middle/trans/cabi_x86_64.rs:337:4-337:4 -fn- definition:
fn x86_64_ty(ccx: &CrateContext,
ty: Type,
is_mem_cls: |cls: &[RegClass]| -> bool,
references:- 2358: for t in atys.iter() {
359: let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), ByValAttribute);
360: arg_tys.push(ty);
--
363: let ret_ty = if ret_def {
364: x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), StructRetAttribute)
365: } else {
librustc/middle/trans/cabi_x86_64.rs:25:23-25:23 -enum- definition:
enum RegClass {
NoClass,
Int,
references:- 17153: i: uint,
154: newv: RegClass) {
155: if cls[i] == newv {
--
188: fn classify(ty: Type,
189: cls: &mut [RegClass], ix: uint,
190: off: uint) {
--
293: fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
294: fn llvec_len(cls: &[RegClass]) -> uint {
--
338: ty: Type,
339: is_mem_cls: |cls: &[RegClass]| -> bool,
340: attr: Attribute)
librustc/middle/trans/cabi_x86_64.rs:188:4-188:4 -fn- definition:
fn classify(ty: Type,
cls: &mut [RegClass], ix: uint,
off: uint) {
references:- 3182: field_off = align(field_off, *ty);
183: classify(*ty, cls, i, field_off);
184: field_off += ty_size(*ty);
--
228: while i < len {
229: classify(elt, cls, ix, off + i * eltsz);
230: i += 1u;
--
287: }
288: classify(ty, cls.as_mut_slice(), 0, 0);
289: fixup(ty, cls.as_mut_slice());
librustc/middle/trans/cabi_x86_64.rs:146:4-146:4 -fn- definition:
fn all_mem(cls: &mut [RegClass]) {
for elt in cls.mut_iter() {
*elt = Memory;
references:- 5284: if words > 4 {
285: all_mem(cls.as_mut_slice());
286: return cls;