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.
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.
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
14 #[allow(non_uppercase_pattern_statics)];
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;
22 use middle::trans::type_::Type;
27 #[deriving(Clone, Eq)]
44 fn is_reg_ty(&self) -> bool;
47 impl TypeMethods for Type {
48 fn is_reg_ty(&self) -> bool {
50 Integer | Pointer | Float | Double => true,
57 fn is_sse(&self) -> bool {
59 SSEFs | SSEFv | SSEDs | SSEDv => true,
66 fn is_pass_byval(&self) -> bool;
67 fn is_ret_bysret(&self) -> bool;
70 impl<'a> ClassList for &'a [RegClass] {
71 fn is_pass_byval(&self) -> bool {
72 if self.len() == 0 { return false; }
77 || class == ComplexX87
80 fn is_ret_bysret(&self) -> bool {
81 if self.len() == 0 { return false; }
87 fn classify_ty(ty: Type) -> Vec<RegClass> {
88 fn align(off: uint, ty: Type) -> uint {
90 return (off + a - 1u) / a * a;
93 fn ty_align(ty: Type) -> uint {
97 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
107 let str_tys = ty.field_types();
108 str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
112 let elt = ty.element_type();
115 _ => fail!("ty_size: unhandled type")
119 fn ty_size(ty: Type) -> uint {
123 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
130 let str_tys = ty.field_types();
132 str_tys.iter().fold(0, |s, t| s + ty_size(*t))
134 let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
139 let len = ty.array_length();
140 let elt = ty.element_type();
141 let eltsz = ty_size(elt);
144 _ => fail!("ty_size: unhandled type")
148 fn all_mem(cls: &mut [RegClass]) {
149 for elt in cls.mut_iter() {
154 fn unify(cls: &mut [RegClass],
159 } else if cls[i] == NoClass {
161 } else if newv == NoClass {
163 } else if cls[i] == Memory || newv == Memory {
165 } else if cls[i] == Int || newv == Int {
167 } else if cls[i] == X87 ||
169 cls[i] == ComplexX87 ||
179 fn classify_struct(tys: &[Type],
180 cls: &mut [RegClass], i: uint,
182 let mut field_off = off;
183 for ty in tys.iter() {
184 field_off = align(field_off, *ty);
185 classify(*ty, cls, i, field_off);
186 field_off += ty_size(*ty);
190 fn classify(ty: Type,
191 cls: &mut [RegClass], ix: uint,
193 let t_align = ty_align(ty);
194 let t_size = ty_size(ty);
196 let misalign = off % t_align;
198 let mut i = off / 8u;
199 let e = (off + t_size + 7u) / 8u;
201 unify(cls, ix + i, Memory);
210 unify(cls, ix + off / 8u, Int);
214 unify(cls, ix + off / 8u, SSEFv);
216 unify(cls, ix + off / 8u, SSEFs);
220 unify(cls, ix + off / 8u, SSEDs);
223 classify_struct(ty.field_types(), cls, ix, off);
226 let len = ty.array_length();
227 let elt = ty.element_type();
228 let eltsz = ty_size(elt);
231 classify(elt, cls, ix, off + i * eltsz);
235 _ => fail!("classify: unhandled type")
239 fn fixup(ty: Type, cls: &mut [RegClass]) {
241 let ty_kind = ty.kind();
243 if cls.len() > 2u && (ty_kind == Struct || ty_kind == Array) {
259 if cls[i] == Memory {
271 } else if cls[i].is_sse() {
273 while i != e && cls[i] == SSEUp { i += 1u; }
274 } else if cls[i] == X87 {
276 while i != e && cls[i] == X87Up { i += 1u; }
284 let words = (ty_size(ty) + 7) / 8;
285 let mut cls = vec::from_elem(words, NoClass);
290 classify(ty, cls, 0, 0);
295 fn llreg_ty(cls: &[RegClass]) -> Type {
296 fn llvec_len(cls: &[RegClass]) -> uint {
298 for c in cls.iter() {
307 let mut tys = Vec::new();
313 tys.push(Type::i64());
316 let vec_len = llvec_len(cls.tailn(i + 1u));
317 let vec_ty = Type::vector(&Type::f32(), (vec_len * 2u) as u64);
323 tys.push(Type::f32());
326 tys.push(Type::f64());
328 _ => fail!("llregtype: unhandled class")
332 return Type::struct_(tys, false);
335 pub fn compute_abi_info(_ccx: &CrateContext,
338 ret_def: bool) -> FnType {
339 fn x86_64_ty(ty: Type,
340 is_mem_cls: |cls: &[RegClass]| -> bool,
344 let cls = classify_ty(ty);
346 ArgType::indirect(ty, Some(attr))
348 ArgType::direct(ty, Some(llreg_ty(cls)), None, None)
351 ArgType::direct(ty, None, None, None)
355 let mut arg_tys = Vec::new();
356 for t in atys.iter() {
357 let ty = x86_64_ty(*t, |cls| cls.is_pass_byval(), ByValAttribute);
361 let ret_ty = if ret_def {
362 x86_64_ty(rty, |cls| cls.is_ret_bysret(), StructRetAttribute)
364 ArgType::direct(Type::void(), None, None, None)