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 use lib::llvm::{llvm, Integer, Pointer, Float, Double};
15 use lib::llvm::{Struct, Array, Attribute};
16 use lib::llvm::{StructRetAttribute, ByValAttribute};
17 use middle::trans::cabi::*;
19 use middle::trans::type_::Type;
23 use std::option::Option;
26 #[deriving(Clone, Eq)]
43 fn is_reg_ty(&self) -> bool;
46 impl TypeMethods for Type {
47 fn is_reg_ty(&self) -> bool {
49 Integer | Pointer | Float | Double => true,
56 fn is_sse(&self) -> bool {
58 SSEFs | SSEFv | SSEDs | SSEDv => true,
65 fn is_pass_byval(&self) -> bool;
66 fn is_ret_bysret(&self) -> bool;
69 impl<'self> ClassList for &'self [RegClass] {
70 fn is_pass_byval(&self) -> bool {
71 if self.len() == 0 { return false; }
76 || class == ComplexX87
79 fn is_ret_bysret(&self) -> bool {
80 if self.len() == 0 { return false; }
86 fn classify_ty(ty: Type) -> ~[RegClass] {
87 fn align(off: uint, ty: Type) -> uint {
89 return (off + a - 1u) / a * a;
92 fn ty_align(ty: Type) -> uint {
96 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
106 let str_tys = ty.field_types();
107 str_tys.iter().fold(1, |a, t| num::max(a, ty_align(*t)))
111 let elt = ty.element_type();
114 _ => fail!("ty_size: unhandled type")
118 fn ty_size(ty: Type) -> uint {
122 ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as uint) + 7) / 8
129 let str_tys = ty.field_types();
131 str_tys.iter().fold(0, |s, t| s + ty_size(*t))
133 let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
138 let len = ty.array_length();
139 let elt = ty.element_type();
140 let eltsz = ty_size(elt);
143 _ => fail!("ty_size: unhandled type")
147 fn all_mem(cls: &mut [RegClass]) {
148 for elt in cls.mut_iter() {
153 fn unify(cls: &mut [RegClass],
158 } else if cls[i] == NoClass {
160 } else if newv == NoClass {
162 } else if cls[i] == Memory || newv == Memory {
164 } else if cls[i] == Int || newv == Int {
166 } else if cls[i] == X87 ||
168 cls[i] == ComplexX87 ||
178 fn classify_struct(tys: &[Type],
179 cls: &mut [RegClass], i: uint,
181 let mut field_off = off;
182 for ty in tys.iter() {
183 field_off = align(field_off, *ty);
184 classify(*ty, cls, i, field_off);
185 field_off += ty_size(*ty);
189 fn classify(ty: Type,
190 cls: &mut [RegClass], ix: uint,
192 let t_align = ty_align(ty);
193 let t_size = ty_size(ty);
195 let misalign = off % t_align;
197 let mut i = off / 8u;
198 let e = (off + t_size + 7u) / 8u;
200 unify(cls, ix + i, Memory);
209 unify(cls, ix + off / 8u, Int);
213 unify(cls, ix + off / 8u, SSEFv);
215 unify(cls, ix + off / 8u, SSEFs);
219 unify(cls, ix + off / 8u, SSEDs);
222 classify_struct(ty.field_types(), cls, ix, off);
225 let len = ty.array_length();
226 let elt = ty.element_type();
227 let eltsz = ty_size(elt);
230 classify(elt, cls, ix, off + i * eltsz);
234 _ => fail!("classify: unhandled type")
238 fn fixup(ty: Type, cls: &mut [RegClass]) {
240 let ty_kind = ty.kind();
242 if cls.len() > 2u && (ty_kind == Struct || ty_kind == Array) {
258 if cls[i] == Memory {
270 } else if cls[i].is_sse() {
272 while i != e && cls[i] == SSEUp { i += 1u; }
273 } else if cls[i] == X87 {
275 while i != e && cls[i] == X87Up { i += 1u; }
283 let words = (ty_size(ty) + 7) / 8;
284 let mut cls = vec::from_elem(words, NoClass);
289 classify(ty, cls, 0, 0);
294 fn llreg_ty(cls: &[RegClass]) -> Type {
295 fn llvec_len(cls: &[RegClass]) -> uint {
297 for c in cls.iter() {
312 tys.push(Type::i64());
315 let vec_len = llvec_len(cls.tailn(i + 1u));
316 let vec_ty = Type::vector(&Type::f32(), (vec_len * 2u) as u64);
322 tys.push(Type::f32());
325 tys.push(Type::f64());
327 _ => fail!("llregtype: unhandled class")
331 return Type::struct_(tys, false);
334 fn x86_64_tys(atys: &[Type],
336 ret_def: bool) -> FnType {
338 fn x86_64_ty(ty: Type,
339 is_mem_cls: &fn(cls: &[RegClass]) -> bool,
340 attr: Attribute) -> (LLVMType, Option<Attribute>) {
342 let (cast, attr, ty) = if !ty.is_reg_ty() {
343 let cls = classify_ty(ty);
345 (false, option::Some(attr), ty.ptr_to())
347 (true, option::None, llreg_ty(cls))
350 (false, option::None, ty)
353 (LLVMType { cast: cast, ty: ty }, attr)
356 let mut arg_tys = ~[];
358 for t in atys.iter() {
359 let (ty, attr) = x86_64_ty(*t, |cls| cls.is_pass_byval(), ByValAttribute);
363 let (ret_ty, ret_attr) = x86_64_ty(rty, |cls| cls.is_ret_bysret(),
365 let mut ret_ty = ret_ty;
366 let sret = ret_attr.is_some();
368 arg_tys = vec::append(~[ret_ty], arg_tys);
373 attrs = vec::append(~[ret_attr], attrs);
388 enum X86_64_ABIInfo { X86_64_ABIInfo }
390 impl ABIInfo for X86_64_ABIInfo {
391 fn compute_info(&self,
394 ret_def: bool) -> FnType {
395 return x86_64_tys(atys, rty, ret_def);
399 pub fn abi_info() -> @ABIInfo {
400 return @X86_64_ABIInfo as @ABIInfo;