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::*;
17 use llvm::{Integer, Pointer, Float, Double};
18 use llvm::{Struct, Array, Vector};
19 use abi::{self, ArgType, ArgAttribute, FnType};
20 use context::CrateContext;
23 #[derive(Clone, Copy, PartialEq)]
31 SSEInt(/* bitwidth */ u64),
32 /// Data that can appear in the upper half of an SSE register.
41 fn is_reg_ty(&self) -> bool;
44 impl TypeMethods for Type {
45 fn is_reg_ty(&self) -> bool {
47 Integer | Pointer | Float | Double => true,
54 fn is_sse(&self) -> bool {
56 SSEFs | SSEFv | SSEDs | SSEDv | SSEInt(_) => true,
63 fn is_pass_byval(&self) -> bool;
64 fn is_ret_bysret(&self) -> bool;
67 impl ClassList for [RegClass] {
68 fn is_pass_byval(&self) -> bool {
69 if self.is_empty() { return false; }
74 || class == ComplexX87
77 fn is_ret_bysret(&self) -> bool {
78 if self.is_empty() { return false; }
84 fn classify_ty(ty: Type) -> Vec<RegClass> {
85 fn align(off: usize, ty: Type) -> usize {
87 return (off + a - 1) / a * a;
90 fn ty_align(ty: Type) -> usize {
94 fn ty_size(ty: Type) -> usize {
98 fn all_mem(cls: &mut [RegClass]) {
104 fn unify(cls: &mut [RegClass],
107 if cls[i] == newv { return }
109 let to_write = match (cls[i], newv) {
110 (NoClass, _) => newv,
111 (_, NoClass) => return,
114 (_, Memory) => Memory,
124 (_, ComplexX87) => Memory,
130 (SSEInt(_), SSEUp) => return,
137 fn classify_struct(tys: &[Type],
138 cls: &mut [RegClass],
142 let mut field_off = off;
145 field_off = align(field_off, *ty);
147 classify(*ty, cls, i, field_off);
148 field_off += ty_size(*ty);
152 fn classify(ty: Type,
153 cls: &mut [RegClass], ix: usize,
155 let t_align = ty_align(ty);
156 let t_size = ty_size(ty);
158 let misalign = off % t_align;
161 let e = (off + t_size + 7) / 8;
163 unify(cls, ix + i, Memory);
172 unify(cls, ix + off / 8, Int);
176 unify(cls, ix + off / 8, SSEFv);
178 unify(cls, ix + off / 8, SSEFs);
182 unify(cls, ix + off / 8, SSEDs);
185 classify_struct(&ty.field_types(), cls, ix, off, ty.is_packed());
188 let len = ty.array_length();
189 let elt = ty.element_type();
190 let eltsz = ty_size(elt);
193 classify(elt, cls, ix, off + i * eltsz);
198 let len = ty.vector_length();
199 let elt = ty.element_type();
200 let eltsz = ty_size(elt);
201 let mut reg = match elt.kind() {
202 Integer => SSEInt(elt.int_width()),
205 _ => bug!("classify: unhandled vector element type")
210 unify(cls, ix + (off + i * eltsz) / 8, reg);
212 // everything after the first one is the upper
213 // half of a register.
218 _ => bug!("classify: unhandled type")
222 fn fixup(ty: Type, cls: &mut [RegClass]) {
224 let ty_kind = ty.kind();
226 if cls.len() > 2 && (ty_kind == Struct || ty_kind == Array || ty_kind == Vector) {
242 if cls[i] == Memory {
254 } else if cls[i].is_sse() {
256 while i != e && cls[i] == SSEUp { i += 1; }
257 } else if cls[i] == X87 {
259 while i != e && cls[i] == X87Up { i += 1; }
267 let words = (ty_size(ty) + 7) / 8;
268 let mut cls = vec![NoClass; words];
273 classify(ty, &mut cls, 0, 0);
278 fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
279 fn llvec_len(cls: &[RegClass]) -> usize {
290 let mut tys = Vec::new();
296 tys.push(Type::i64(ccx));
298 SSEFv | SSEDv | SSEInt(_) => {
299 let (elts_per_word, elt_ty) = match cls[i] {
300 SSEFv => (2, Type::f32(ccx)),
301 SSEDv => (1, Type::f64(ccx)),
303 assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64,
304 "llreg_ty: unsupported SSEInt width {}", bits);
305 (64 / bits, Type::ix(ccx, bits))
309 let vec_len = llvec_len(&cls[i + 1..]);
310 let vec_ty = Type::vector(&elt_ty, vec_len as u64 * elts_per_word);
316 tys.push(Type::f32(ccx));
319 tys.push(Type::f64(ccx));
321 _ => bug!("llregtype: unhandled class")
325 if tys.len() == 1 && tys[0].kind() == Vector {
326 // if the type contains only a vector, pass it as that vector.
329 Type::struct_(ccx, &tys, false)
333 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
334 fn x86_64_ty<F>(ccx: &CrateContext,
337 ind_attr: Option<ArgAttribute>)
338 where F: FnOnce(&[RegClass]) -> bool
340 if !arg.ty.is_reg_ty() {
341 let cls = classify_ty(arg.ty);
342 if is_mem_cls(&cls) {
343 arg.make_indirect(ccx);
344 if let Some(attr) = ind_attr {
348 arg.cast = Some(llreg_ty(ccx, &cls));
351 arg.extend_integer_width_to(32);
355 let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
356 let mut sse_regs = 8; // XMM0-7
358 if !fty.ret.is_ignore() {
359 x86_64_ty(ccx, &mut fty.ret, |cls| {
360 if cls.is_ret_bysret() {
361 // `sret` parameter thus one less register available
370 for arg in &mut fty.args {
371 if arg.is_ignore() { continue; }
372 x86_64_ty(ccx, arg, |cls| {
373 let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize;
374 let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize;
375 let in_mem = cls.is_pass_byval() ||
376 int_regs < needed_int ||
377 sse_regs < needed_sse;
379 // `byval` parameter thus one less integer register available
382 // split into sized chunks passed individually
383 int_regs -= needed_int;
384 sse_regs -= needed_sse;
387 }, Some(ArgAttribute::ByVal));
389 // An integer, pointer, double or float parameter
390 // thus the above closure passed to `x86_64_ty` won't
392 match arg.ty.kind() {
393 Integer | Pointer => int_regs -= 1,
394 Double | Float => sse_regs -= 1,