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_upper_case_globals)]
15 use self::RegClass::*;
18 use llvm::{Integer, Pointer, Float, Double};
19 use llvm::{Struct, Array, Attribute};
20 use llvm::{StructRetAttribute, ByValAttribute, ZExtAttribute};
21 use trans::cabi::{ArgType, FnType};
22 use trans::context::CrateContext;
23 use trans::type_::Type;
26 use std::iter::repeat;
28 #[derive(Clone, Copy, PartialEq)]
45 fn is_reg_ty(&self) -> bool;
48 impl TypeMethods for Type {
49 fn is_reg_ty(&self) -> bool {
51 Integer | Pointer | Float | Double => true,
58 fn is_sse(&self) -> bool {
60 SSEFs | SSEFv | SSEDs | SSEDv => true,
66 trait ClassList for Sized? {
67 fn is_pass_byval(&self) -> bool;
68 fn is_ret_bysret(&self) -> bool;
71 impl ClassList for [RegClass] {
72 fn is_pass_byval(&self) -> bool {
73 if self.len() == 0 { return false; }
78 || class == ComplexX87
81 fn is_ret_bysret(&self) -> bool {
82 if self.len() == 0 { return false; }
88 fn classify_ty(ty: Type) -> Vec<RegClass> {
89 fn align(off: uint, ty: Type) -> uint {
91 return (off + a - 1u) / a * a;
94 fn ty_align(ty: Type) -> uint {
98 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
108 let str_tys = ty.field_types();
109 str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
113 let elt = ty.element_type();
116 _ => panic!("ty_size: unhandled type")
120 fn ty_size(ty: Type) -> uint {
124 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
131 let str_tys = ty.field_types();
133 str_tys.iter().fold(0, |s, t| s + ty_size(*t))
135 let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
140 let len = ty.array_length();
141 let elt = ty.element_type();
142 let eltsz = ty_size(elt);
145 _ => panic!("ty_size: unhandled type")
149 fn all_mem(cls: &mut [RegClass]) {
150 for elt in cls.iter_mut() {
155 fn unify(cls: &mut [RegClass],
160 } else if cls[i] == NoClass {
162 } else if newv == NoClass {
164 } else if cls[i] == Memory || newv == Memory {
166 } else if cls[i] == Int || newv == Int {
168 } else if cls[i] == X87 ||
170 cls[i] == ComplexX87 ||
180 fn classify_struct(tys: &[Type],
181 cls: &mut [RegClass],
185 let mut field_off = off;
186 for ty in tys.iter() {
188 field_off = align(field_off, *ty);
190 classify(*ty, cls, i, field_off);
191 field_off += ty_size(*ty);
195 fn classify(ty: Type,
196 cls: &mut [RegClass], ix: uint,
198 let t_align = ty_align(ty);
199 let t_size = ty_size(ty);
201 let misalign = off % t_align;
203 let mut i = off / 8u;
204 let e = (off + t_size + 7u) / 8u;
206 unify(cls, ix + i, Memory);
215 unify(cls, ix + off / 8u, Int);
219 unify(cls, ix + off / 8u, SSEFv);
221 unify(cls, ix + off / 8u, SSEFs);
225 unify(cls, ix + off / 8u, SSEDs);
228 classify_struct(ty.field_types().as_slice(), cls, ix, off, ty.is_packed());
231 let len = ty.array_length();
232 let elt = ty.element_type();
233 let eltsz = ty_size(elt);
236 classify(elt, cls, ix, off + i * eltsz);
240 _ => panic!("classify: unhandled type")
244 fn fixup(ty: Type, cls: &mut [RegClass]) {
246 let ty_kind = ty.kind();
248 if cls.len() > 2u && (ty_kind == Struct || ty_kind == Array) {
264 if cls[i] == Memory {
276 } else if cls[i].is_sse() {
278 while i != e && cls[i] == SSEUp { i += 1u; }
279 } else if cls[i] == X87 {
281 while i != e && cls[i] == X87Up { i += 1u; }
289 let words = (ty_size(ty) + 7) / 8;
290 let mut cls: Vec<_> = repeat(NoClass).take(words).collect();
292 all_mem(cls.as_mut_slice());
295 classify(ty, cls.as_mut_slice(), 0, 0);
296 fixup(ty, cls.as_mut_slice());
300 fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
301 fn llvec_len(cls: &[RegClass]) -> uint {
303 for c in cls.iter() {
312 let mut tys = Vec::new();
318 tys.push(Type::i64(ccx));
321 let vec_len = llvec_len(cls[i + 1u..]);
322 let vec_ty = Type::vector(&Type::f32(ccx), (vec_len * 2u) as u64);
328 tys.push(Type::f32(ccx));
331 tys.push(Type::f64(ccx));
333 _ => panic!("llregtype: unhandled class")
337 return Type::struct_(ccx, tys.as_slice(), false);
340 pub fn compute_abi_info(ccx: &CrateContext,
343 ret_def: bool) -> FnType {
344 fn x86_64_ty<F>(ccx: &CrateContext,
349 F: FnOnce(&[RegClass]) -> bool,
352 let cls = classify_ty(ty);
353 if is_mem_cls(cls.as_slice()) {
354 ArgType::indirect(ty, Some(ind_attr))
357 Some(llreg_ty(ccx, cls.as_slice())),
362 let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None };
363 ArgType::direct(ty, None, None, attr)
367 let mut arg_tys = Vec::new();
368 for t in atys.iter() {
369 let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), ByValAttribute);
373 let ret_ty = if ret_def {
374 x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), StructRetAttribute)
376 ArgType::direct(Type::void(ccx), None, None, None)