diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs deleted file mode 100644 index 07c12d08e1b..00000000000 --- a/src/librustc/middle/trans/cabi.rs +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use lib::llvm::{llvm, TypeRef, ValueRef, Attribute}; -use middle::trans::base::*; -use middle::trans::build::*; -use middle::trans::common::*; - -export ABIInfo, LLVMType, FnType; -export llvm_abi_info; - -trait ABIInfo { - fn compute_info(&self, - atys: &[TypeRef], - rty: TypeRef, - ret_def: bool) -> FnType; -} - -struct LLVMType { - cast: bool, - ty: TypeRef -} - -struct FnType { - arg_tys: ~[LLVMType], - ret_ty: LLVMType, - attrs: ~[Option], - sret: bool -} - -impl FnType { - fn decl_fn(&self, decl: fn(fnty: TypeRef) -> ValueRef) -> ValueRef { - let atys = vec::map(self.arg_tys, |t| t.ty); - let rty = self.ret_ty.ty; - let fnty = T_fn(atys, rty); - let llfn = decl(fnty); - - for vec::eachi(self.attrs) |i, a| { - match *a { - option::Some(attr) => { - unsafe { - let llarg = get_param(llfn, i); - llvm::LLVMAddAttribute(llarg, attr as c_uint); - } - } - _ => () - } - } - return llfn; - } - - fn build_shim_args(&self, bcx: block, - arg_tys: &[TypeRef], - llargbundle: ValueRef) -> ~[ValueRef] { - let mut atys = /*bad*/copy self.arg_tys; - let mut attrs = /*bad*/copy self.attrs; - - let mut llargvals = ~[]; - let mut i = 0u; - let n = vec::len(arg_tys); - - if self.sret { - let llretptr = GEPi(bcx, llargbundle, [0u, n]); - let llretloc = Load(bcx, llretptr); - llargvals = ~[llretloc]; - atys = vec::tail(atys); - attrs = vec::tail(attrs); - } - - while i < n { - let llargval = if atys[i].cast { - let arg_ptr = GEPi(bcx, llargbundle, [0u, i]); - let arg_ptr = BitCast(bcx, arg_ptr, T_ptr(atys[i].ty)); - Load(bcx, arg_ptr) - } else if attrs[i].is_some() { - GEPi(bcx, llargbundle, [0u, i]) - } else { - load_inbounds(bcx, llargbundle, [0u, i]) - }; - llargvals.push(llargval); - i += 1u; - } - - return llargvals; - } - - fn build_shim_ret(&self, bcx: block, - arg_tys: &[TypeRef], ret_def: bool, - llargbundle: ValueRef, llretval: ValueRef) { - for vec::eachi(self.attrs) |i, a| { - match *a { - Some(attr) => { - unsafe { - llvm::LLVMAddInstrAttribute( - llretval, (i + 1u) as c_uint, - attr as c_uint); - } - } - _ => () - } - } - if self.sret || !ret_def { - return; - } - let n = vec::len(arg_tys); - // R** llretptr = &args->r; - let llretptr = GEPi(bcx, llargbundle, [0u, n]); - // R* llretloc = *llretptr; /* (args->r) */ - let llretloc = Load(bcx, llretptr); - if self.ret_ty.cast { - let tmp_ptr = BitCast(bcx, llretloc, T_ptr(self.ret_ty.ty)); - // *args->r = r; - Store(bcx, llretval, tmp_ptr); - } else { - // *args->r = r; - Store(bcx, llretval, llretloc); - }; - } - - fn build_wrap_args(&self, bcx: block, ret_ty: TypeRef, - llwrapfn: ValueRef, llargbundle: ValueRef) { - let mut atys = /*bad*/copy self.arg_tys; - let mut attrs = /*bad*/copy self.attrs; - let mut j = 0u; - let llretptr = if self.sret { - atys = vec::tail(atys); - attrs = vec::tail(attrs); - j = 1u; - get_param(llwrapfn, 0u) - } else if self.ret_ty.cast { - let retptr = alloca(bcx, self.ret_ty.ty); - BitCast(bcx, retptr, T_ptr(ret_ty)) - } else { - alloca(bcx, ret_ty) - }; - - let mut i = 0u; - let n = vec::len(atys); - while i < n { - let mut argval = get_param(llwrapfn, i + j); - if attrs[i].is_some() { - argval = Load(bcx, argval); - store_inbounds(bcx, argval, llargbundle, [0u, i]); - } else if atys[i].cast { - let argptr = GEPi(bcx, llargbundle, [0u, i]); - let argptr = BitCast(bcx, argptr, T_ptr(atys[i].ty)); - Store(bcx, argval, argptr); - } else { - store_inbounds(bcx, argval, llargbundle, [0u, i]); - } - i += 1u; - } - store_inbounds(bcx, llretptr, llargbundle, [0u, n]); - } - - fn build_wrap_ret(&self, bcx: block, - arg_tys: &[TypeRef], ret_def: bool, - llargbundle: ValueRef) { - if self.sret || !ret_def { - RetVoid(bcx); - return; - } - let n = vec::len(arg_tys); - let llretval = load_inbounds(bcx, llargbundle, ~[0u, n]); - let llretval = if self.ret_ty.cast { - let retptr = BitCast(bcx, llretval, T_ptr(self.ret_ty.ty)); - Load(bcx, retptr) - } else { - Load(bcx, llretval) - }; - Ret(bcx, llretval); - } -} - -enum LLVM_ABIInfo { LLVM_ABIInfo } - -impl LLVM_ABIInfo: ABIInfo { - fn compute_info(&self, - atys: &[TypeRef], - rty: TypeRef, - _ret_def: bool) -> FnType { - let arg_tys = do atys.map |a| { - LLVMType { cast: false, ty: *a } - }; - let ret_ty = LLVMType { - cast: false, - ty: rty - }; - let attrs = do atys.map |_| { - option::None - }; - let sret = false; - - return FnType { - arg_tys: arg_tys, - ret_ty: ret_ty, - attrs: attrs, - sret: sret - }; - } -} - -fn llvm_abi_info() -> ABIInfo { - return LLVM_ABIInfo as ABIInfo; -} - - diff --git a/src/librustc/middle/trans/cabi_x86_64.rs b/src/librustc/middle/trans/cabi_x86_64.rs deleted file mode 100644 index 7125764e747..00000000000 --- a/src/librustc/middle/trans/cabi_x86_64.rs +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// The classification code for the x86_64 ABI is taken from the clay language -// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp - -use lib::llvm::{llvm, TypeRef, ValueRef, Integer, Pointer, Float, Double}; -use lib::llvm::{Struct, Array, Attribute}; -use lib::llvm::{StructRetAttribute, ByValAttribute}; -use middle::trans::common::*; -use middle::trans::cabi::*; - -export x86_64_abi_info; - -enum x86_64_reg_class { - no_class, - integer_class, - sse_fs_class, - sse_fv_class, - sse_ds_class, - sse_dv_class, - sse_int_class, - sseup_class, - x87_class, - x87up_class, - complex_x87_class, - memory_class -} - -impl x86_64_reg_class : cmp::Eq { - pure fn eq(&self, other: &x86_64_reg_class) -> bool { - ((*self) as uint) == ((*other) as uint) - } - pure fn ne(&self, other: &x86_64_reg_class) -> bool { !(*self).eq(other) } -} - -fn is_sse(++c: x86_64_reg_class) -> bool { - return match c { - sse_fs_class | sse_fv_class | - sse_ds_class | sse_dv_class => true, - _ => false - }; -} - -fn is_ymm(cls: &[x86_64_reg_class]) -> bool { - let len = vec::len(cls); - return (len > 2u && - is_sse(cls[0]) && - cls[1] == sseup_class && - cls[2] == sseup_class) || - (len > 3u && - is_sse(cls[1]) && - cls[2] == sseup_class && - cls[3] == sseup_class); -} - -fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { - fn align(off: uint, ty: TypeRef) -> uint { - let a = ty_align(ty); - return (off + a - 1u) / a * a; - } - - fn struct_tys(ty: TypeRef) -> ~[TypeRef] { - unsafe { - let n = llvm::LLVMCountStructElementTypes(ty); - if (n == 0) { - return ~[]; - } - let mut elts = vec::from_elem(n as uint, ptr::null()); - llvm::LLVMGetStructElementTypes(ty, - ptr::to_mut_unsafe_ptr(&mut elts[0])); - return elts; - } - } - - fn ty_align(ty: TypeRef) -> uint { - unsafe { - return match llvm::LLVMGetTypeKind(ty) { - Integer => { - ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 - } - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - do vec::foldl(1, struct_tys(ty)) |a, t| { - uint::max(a, ty_align(*t)) - } - } - Array => { - let elt = llvm::LLVMGetElementType(ty); - ty_align(elt) - } - _ => fail ~"ty_size: unhandled type" - }; - } - } - - fn ty_size(ty: TypeRef) -> uint { - unsafe { - return match llvm::LLVMGetTypeKind(ty) { - Integer => { - ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 - } - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - let size = do vec::foldl(0, struct_tys(ty)) |s, t| { - align(s, *t) + ty_size(*t) - }; - align(size, ty) - } - Array => { - let len = llvm::LLVMGetArrayLength(ty) as uint; - let elt = llvm::LLVMGetElementType(ty); - let eltsz = ty_size(elt); - len * eltsz - } - _ => fail ~"ty_size: unhandled type" - }; - } - } - - fn all_mem(cls: &[mut x86_64_reg_class]) { - for uint::range(0, cls.len()) |i| { - cls[i] = memory_class; - } - } - - fn unify(cls: &[mut x86_64_reg_class], - i: uint, - newv: x86_64_reg_class) { - if cls[i] == newv { - return; - } else if cls[i] == no_class { - cls[i] = newv; - } else if newv == no_class { - return; - } else if cls[i] == memory_class || newv == memory_class { - cls[i] = memory_class; - } else if cls[i] == integer_class || newv == integer_class { - cls[i] = integer_class; - } else if cls[i] == x87_class || - cls[i] == x87up_class || - cls[i] == complex_x87_class || - newv == x87_class || - newv == x87up_class || - newv == complex_x87_class { - cls[i] = memory_class; - } else { - cls[i] = newv; - } - } - - fn classify_struct(tys: &[TypeRef], - cls: &[mut x86_64_reg_class], i: uint, - off: uint) { - let mut field_off = off; - for vec::each(tys) |ty| { - field_off = align(field_off, *ty); - classify(*ty, cls, i, field_off); - field_off += ty_size(*ty); - } - } - - fn classify(ty: TypeRef, - cls: &[mut x86_64_reg_class], ix: uint, - off: uint) { - unsafe { - let t_align = ty_align(ty); - let t_size = ty_size(ty); - - let misalign = off % t_align; - if misalign != 0u { - let mut i = off / 8u; - let e = (off + t_size + 7u) / 8u; - while i < e { - unify(cls, ix + i, memory_class); - i += 1u; - } - return; - } - - match llvm::LLVMGetTypeKind(ty) as int { - 8 /* integer */ | - 12 /* pointer */ => { - unify(cls, ix + off / 8u, integer_class); - } - 2 /* float */ => { - if off % 8u == 4u { - unify(cls, ix + off / 8u, sse_fv_class); - } else { - unify(cls, ix + off / 8u, sse_fs_class); - } - } - 3 /* double */ => { - unify(cls, ix + off / 8u, sse_ds_class); - } - 10 /* struct */ => { - classify_struct(struct_tys(ty), cls, ix, off); - } - 11 /* array */ => { - let elt = llvm::LLVMGetElementType(ty); - let eltsz = ty_size(elt); - let len = llvm::LLVMGetArrayLength(ty) as uint; - let mut i = 0u; - while i < len { - classify(elt, cls, ix, off + i * eltsz); - i += 1u; - } - } - _ => fail ~"classify: unhandled type" - } - } - } - - fn fixup(ty: TypeRef, cls: &[mut x86_64_reg_class]) { - unsafe { - let mut i = 0u; - let llty = llvm::LLVMGetTypeKind(ty) as int; - let e = vec::len(cls); - if vec::len(cls) > 2u && - (llty == 10 /* struct */ || - llty == 11 /* array */) { - if is_sse(cls[i]) { - i += 1u; - while i < e { - if cls[i] != sseup_class { - all_mem(cls); - return; - } - i += 1u; - } - } else { - all_mem(cls); - return - } - } else { - while i < e { - if cls[i] == memory_class { - all_mem(cls); - return; - } - if cls[i] == x87up_class { - // for darwin - // cls[i] = sse_ds_class; - all_mem(cls); - return; - } - if cls[i] == sseup_class { - cls[i] = sse_int_class; - } else if is_sse(cls[i]) { - i += 1; - while cls[i] == sseup_class { i += 1u; } - } else if cls[i] == x87_class { - i += 1; - while cls[i] == x87up_class { i += 1u; } - } else { - i += 1; - } - } - } - } - } - - let words = (ty_size(ty) + 7) / 8; - let cls = vec::cast_to_mut(vec::from_elem(words, no_class)); - if words > 4 { - all_mem(cls); - return vec::cast_from_mut(move cls); - } - classify(ty, cls, 0, 0); - fixup(ty, cls); - return vec::cast_from_mut(move cls); -} - -fn llreg_ty(cls: &[x86_64_reg_class]) -> TypeRef { - fn llvec_len(cls: &[x86_64_reg_class]) -> uint { - let mut len = 1u; - for vec::each(cls) |c| { - if *c != sseup_class { - break; - } - len += 1u; - } - return len; - } - - unsafe { - let mut tys = ~[]; - let mut i = 0u; - let e = vec::len(cls); - while i < e { - match cls[i] { - integer_class => { - tys.push(T_i64()); - } - sse_fv_class => { - let vec_len = llvec_len(vec::tailn(cls, i + 1u)) * 2u; - let vec_ty = llvm::LLVMVectorType(T_f32(), - vec_len as c_uint); - tys.push(vec_ty); - i += vec_len; - loop; - } - sse_fs_class => { - tys.push(T_f32()); - } - sse_ds_class => { - tys.push(T_f64()); - } - _ => fail ~"llregtype: unhandled class" - } - i += 1u; - } - return T_struct(tys); - } -} - -fn x86_64_tys(atys: &[TypeRef], - rty: TypeRef, - ret_def: bool) -> FnType { - fn is_reg_ty(ty: TypeRef) -> bool { - unsafe { - return match llvm::LLVMGetTypeKind(ty) as int { - 8 /* integer */ | - 12 /* pointer */ | - 2 /* float */ | - 3 /* double */ => true, - _ => false - }; - } - } - - fn is_pass_byval(cls: &[x86_64_reg_class]) -> bool { - return cls.len() > 0 && - (cls[0] == memory_class || - cls[0] == x87_class || - cls[0] == complex_x87_class); - } - - fn is_ret_bysret(cls: &[x86_64_reg_class]) -> bool { - return cls.len() > 0 && cls[0] == memory_class; - } - - fn x86_64_ty(ty: TypeRef, - is_mem_cls: fn(cls: &[x86_64_reg_class]) -> bool, - attr: Attribute) -> (LLVMType, Option) { - let mut cast = false; - let mut ty_attr = option::None; - let mut llty = ty; - if !is_reg_ty(ty) { - let cls = classify_ty(ty); - if is_mem_cls(cls) { - llty = T_ptr(ty); - ty_attr = option::Some(attr); - } else { - cast = true; - llty = llreg_ty(cls); - } - } - return (LLVMType { cast: cast, ty: llty }, ty_attr); - } - - let mut arg_tys = ~[]; - let mut attrs = ~[]; - for vec::each(atys) |t| { - let (ty, attr) = x86_64_ty(*t, is_pass_byval, ByValAttribute); - arg_tys.push(ty); - attrs.push(attr); - } - let mut (ret_ty, ret_attr) = x86_64_ty(rty, is_ret_bysret, - StructRetAttribute); - let sret = ret_attr.is_some(); - if sret { - arg_tys = vec::append(~[ret_ty], arg_tys); - ret_ty = LLVMType { - cast: false, - ty: T_void() - }; - attrs = vec::append(~[ret_attr], attrs); - } else if !ret_def { - ret_ty = LLVMType { - cast: false, - ty: T_void() - }; - } - return FnType { - arg_tys: arg_tys, - ret_ty: ret_ty, - attrs: attrs, - sret: sret - }; -} - -enum X86_64_ABIInfo { X86_64_ABIInfo } - -impl X86_64_ABIInfo: ABIInfo { - fn compute_info(&self, - atys: &[TypeRef], - rty: TypeRef, - ret_def: bool) -> FnType { - return x86_64_tys(atys, rty, ret_def); - } -} - -fn x86_64_abi_info() -> ABIInfo { - return X86_64_ABIInfo as ABIInfo; -} diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 51d44f33a81..b92950488d1 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// The classification code for the x86_64 ABI is taken from the clay language +// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp + use core::prelude::*; use back::{link, abi}; @@ -19,8 +22,6 @@ use lib::llvm::{StructRetAttribute, ByValAttribute}; use lib::llvm::{llvm, TypeRef, ValueRef, Integer, Pointer, Float, Double}; use lib; use middle::trans::base::*; -use middle::trans::cabi; -use middle::trans::cabi_x86_64::*; use middle::trans::build::*; use middle::trans::callee::*; use middle::trans::common::*; @@ -43,11 +44,417 @@ use syntax::parse::token::special_idents; export link_name, trans_foreign_mod, register_foreign_fn, trans_foreign_fn, trans_intrinsic; -fn abi_info(arch: session::arch) -> cabi::ABIInfo { - return match arch { - arch_x86_64 => x86_64_abi_info(), - _ => cabi::llvm_abi_info() +enum x86_64_reg_class { + no_class, + integer_class, + sse_fs_class, + sse_fv_class, + sse_ds_class, + sse_dv_class, + sse_int_class, + sseup_class, + x87_class, + x87up_class, + complex_x87_class, + memory_class +} + +impl x86_64_reg_class : cmp::Eq { + pure fn eq(&self, other: &x86_64_reg_class) -> bool { + ((*self) as uint) == ((*other) as uint) } + pure fn ne(&self, other: &x86_64_reg_class) -> bool { !(*self).eq(other) } +} + +fn is_sse(++c: x86_64_reg_class) -> bool { + return match c { + sse_fs_class | sse_fv_class | + sse_ds_class | sse_dv_class => true, + _ => false + }; +} + +fn is_ymm(cls: &[x86_64_reg_class]) -> bool { + let len = vec::len(cls); + return (len > 2u && + is_sse(cls[0]) && + cls[1] == sseup_class && + cls[2] == sseup_class) || + (len > 3u && + is_sse(cls[1]) && + cls[2] == sseup_class && + cls[3] == sseup_class); +} + +fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { + fn align(off: uint, ty: TypeRef) -> uint { + let a = ty_align(ty); + return (off + a - 1u) / a * a; + } + + fn struct_tys(ty: TypeRef) -> ~[TypeRef] { + unsafe { + let n = llvm::LLVMCountStructElementTypes(ty); + if (n == 0) { + return ~[]; + } + let mut elts = vec::from_elem(n as uint, ptr::null()); + llvm::LLVMGetStructElementTypes(ty, + ptr::to_mut_unsafe_ptr(&mut elts[0])); + return elts; + } + } + + fn ty_align(ty: TypeRef) -> uint { + unsafe { + return match llvm::LLVMGetTypeKind(ty) { + Integer => { + ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 + } + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + do vec::foldl(1, struct_tys(ty)) |a, t| { + uint::max(a, ty_align(*t)) + } + } + Array => { + let elt = llvm::LLVMGetElementType(ty); + ty_align(elt) + } + _ => fail ~"ty_size: unhandled type" + }; + } + } + + fn ty_size(ty: TypeRef) -> uint { + unsafe { + return match llvm::LLVMGetTypeKind(ty) { + Integer => { + ((llvm::LLVMGetIntTypeWidth(ty) as uint) + 7) / 8 + } + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + let size = do vec::foldl(0, struct_tys(ty)) |s, t| { + align(s, *t) + ty_size(*t) + }; + align(size, ty) + } + Array => { + let len = llvm::LLVMGetArrayLength(ty) as uint; + let elt = llvm::LLVMGetElementType(ty); + let eltsz = ty_size(elt); + len * eltsz + } + _ => fail ~"ty_size: unhandled type" + }; + } + } + + fn all_mem(cls: &[mut x86_64_reg_class]) { + for uint::range(0, cls.len()) |i| { + cls[i] = memory_class; + } + } + + fn unify(cls: &[mut x86_64_reg_class], + i: uint, + newv: x86_64_reg_class) { + if cls[i] == newv { + return; + } else if cls[i] == no_class { + cls[i] = newv; + } else if newv == no_class { + return; + } else if cls[i] == memory_class || newv == memory_class { + cls[i] = memory_class; + } else if cls[i] == integer_class || newv == integer_class { + cls[i] = integer_class; + } else if cls[i] == x87_class || + cls[i] == x87up_class || + cls[i] == complex_x87_class || + newv == x87_class || + newv == x87up_class || + newv == complex_x87_class { + cls[i] = memory_class; + } else { + cls[i] = newv; + } + } + + fn classify_struct(tys: &[TypeRef], + cls: &[mut x86_64_reg_class], i: uint, + off: uint) { + let mut field_off = off; + for vec::each(tys) |ty| { + field_off = align(field_off, *ty); + classify(*ty, cls, i, field_off); + field_off += ty_size(*ty); + } + } + + fn classify(ty: TypeRef, + cls: &[mut x86_64_reg_class], ix: uint, + off: uint) { + unsafe { + let t_align = ty_align(ty); + let t_size = ty_size(ty); + + let misalign = off % t_align; + if misalign != 0u { + let mut i = off / 8u; + let e = (off + t_size + 7u) / 8u; + while i < e { + unify(cls, ix + i, memory_class); + i += 1u; + } + return; + } + + match llvm::LLVMGetTypeKind(ty) as int { + 8 /* integer */ | + 12 /* pointer */ => { + unify(cls, ix + off / 8u, integer_class); + } + 2 /* float */ => { + if off % 8u == 4u { + unify(cls, ix + off / 8u, sse_fv_class); + } else { + unify(cls, ix + off / 8u, sse_fs_class); + } + } + 3 /* double */ => { + unify(cls, ix + off / 8u, sse_ds_class); + } + 10 /* struct */ => { + classify_struct(struct_tys(ty), cls, ix, off); + } + 11 /* array */ => { + let elt = llvm::LLVMGetElementType(ty); + let eltsz = ty_size(elt); + let len = llvm::LLVMGetArrayLength(ty) as uint; + let mut i = 0u; + while i < len { + classify(elt, cls, ix, off + i * eltsz); + i += 1u; + } + } + _ => fail ~"classify: unhandled type" + } + } + } + + fn fixup(ty: TypeRef, cls: &[mut x86_64_reg_class]) { + unsafe { + let mut i = 0u; + let llty = llvm::LLVMGetTypeKind(ty) as int; + let e = vec::len(cls); + if vec::len(cls) > 2u && + (llty == 10 /* struct */ || + llty == 11 /* array */) { + if is_sse(cls[i]) { + i += 1u; + while i < e { + if cls[i] != sseup_class { + all_mem(cls); + return; + } + i += 1u; + } + } else { + all_mem(cls); + return + } + } else { + while i < e { + if cls[i] == memory_class { + all_mem(cls); + return; + } + if cls[i] == x87up_class { + // for darwin + // cls[i] = sse_ds_class; + all_mem(cls); + return; + } + if cls[i] == sseup_class { + cls[i] = sse_int_class; + } else if is_sse(cls[i]) { + i += 1; + while cls[i] == sseup_class { i += 1u; } + } else if cls[i] == x87_class { + i += 1; + while cls[i] == x87up_class { i += 1u; } + } else { + i += 1; + } + } + } + } + } + + let words = (ty_size(ty) + 7) / 8; + let cls = vec::cast_to_mut(vec::from_elem(words, no_class)); + if words > 4 { + all_mem(cls); + return vec::cast_from_mut(move cls); + } + classify(ty, cls, 0, 0); + fixup(ty, cls); + return vec::cast_from_mut(move cls); +} + +fn llreg_ty(cls: &[x86_64_reg_class]) -> TypeRef { + fn llvec_len(cls: &[x86_64_reg_class]) -> uint { + let mut len = 1u; + for vec::each(cls) |c| { + if *c != sseup_class { + break; + } + len += 1u; + } + return len; + } + + unsafe { + let mut tys = ~[]; + let mut i = 0u; + let e = vec::len(cls); + while i < e { + match cls[i] { + integer_class => { + tys.push(T_i64()); + } + sse_fv_class => { + let vec_len = llvec_len(vec::tailn(cls, i + 1u)) * 2u; + let vec_ty = llvm::LLVMVectorType(T_f32(), + vec_len as c_uint); + tys.push(vec_ty); + i += vec_len; + loop; + } + sse_fs_class => { + tys.push(T_f32()); + } + sse_ds_class => { + tys.push(T_f64()); + } + _ => fail ~"llregtype: unhandled class" + } + i += 1u; + } + return T_struct(tys); + } +} + +type x86_64_llty = { + cast: bool, + ty: TypeRef +}; + +type x86_64_tys = { + arg_tys: ~[x86_64_llty], + ret_ty: x86_64_llty, + attrs: ~[Option], + sret: bool +}; + +fn x86_64_tys(atys: &[TypeRef], + rty: TypeRef, + ret_def: bool) -> x86_64_tys { + fn is_reg_ty(ty: TypeRef) -> bool { + unsafe { + return match llvm::LLVMGetTypeKind(ty) as int { + 8 /* integer */ | + 12 /* pointer */ | + 2 /* float */ | + 3 /* double */ => true, + _ => false + }; + } + } + + fn is_pass_byval(cls: &[x86_64_reg_class]) -> bool { + return cls.len() > 0 && + (cls[0] == memory_class || + cls[0] == x87_class || + cls[0] == complex_x87_class); + } + + fn is_ret_bysret(cls: &[x86_64_reg_class]) -> bool { + return cls.len() > 0 && cls[0] == memory_class; + } + + fn x86_64_ty(ty: TypeRef, + is_mem_cls: fn(cls: &[x86_64_reg_class]) -> bool, + attr: Attribute) -> (x86_64_llty, Option) { + let mut cast = false; + let mut ty_attr = option::None; + let mut llty = ty; + if !is_reg_ty(ty) { + let cls = classify_ty(ty); + if is_mem_cls(cls) { + llty = T_ptr(ty); + ty_attr = option::Some(attr); + } else { + cast = true; + llty = llreg_ty(cls); + } + } + return ({ cast: cast, ty: llty }, ty_attr); + } + + let mut arg_tys = ~[]; + let mut attrs = ~[]; + for vec::each(atys) |t| { + let (ty, attr) = x86_64_ty(*t, is_pass_byval, ByValAttribute); + arg_tys.push(ty); + attrs.push(attr); + } + let mut (ret_ty, ret_attr) = x86_64_ty(rty, is_ret_bysret, + StructRetAttribute); + let sret = ret_attr.is_some(); + if sret { + arg_tys = vec::append(~[ret_ty], arg_tys); + ret_ty = { cast: false, + ty: T_void() + }; + attrs = vec::append(~[ret_attr], attrs); + } else if !ret_def { + ret_ty = { cast: false, + ty: T_void() + }; + } + return { + arg_tys: arg_tys, + ret_ty: ret_ty, + attrs: attrs, + sret: sret + }; +} + +fn decl_x86_64_fn(tys: x86_64_tys, + decl: fn(fnty: TypeRef) -> ValueRef) -> ValueRef { + let atys = vec::map(tys.arg_tys, |t| t.ty); + let rty = tys.ret_ty.ty; + let fnty = T_fn(atys, rty); + let llfn = decl(fnty); + + for vec::eachi(tys.attrs) |i, a| { + match *a { + option::Some(attr) => { + unsafe { + let llarg = get_param(llfn, i); + llvm::LLVMAddAttribute(llarg, attr as c_uint); + } + } + _ => () + } + } + return llfn; } fn link_name(ccx: @crate_ctxt, i: @ast::foreign_item) -> ~str { @@ -63,7 +470,7 @@ type c_stack_tys = { ret_def: bool, bundle_ty: TypeRef, shim_fn_ty: TypeRef, - fn_ty: cabi::FnType + x86_64_tys: Option }; fn c_arg_and_ret_lltys(ccx: @crate_ctxt, @@ -86,15 +493,20 @@ fn c_stack_tys(ccx: @crate_ctxt, // XXX: Bad copy. let bundle_ty = T_struct(vec::append_one(copy llargtys, T_ptr(llretty))); let ret_def = !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty); - let fn_ty = abi_info(ccx.sess.targ_cfg.arch). - compute_info(llargtys, llretty, ret_def); + let x86_64 = if ccx.sess.targ_cfg.arch == arch_x86_64 { + option::Some(x86_64_tys(llargtys, llretty, ret_def)) + } else if ccx.sess.targ_cfg.arch == arch_arm { + option::Some(x86_64_tys(llargtys, llretty, ret_def)) + } else { + option::None + }; return @{ arg_tys: llargtys, ret_ty: llretty, ret_def: ret_def, bundle_ty: bundle_ty, shim_fn_ty: T_fn(~[T_ptr(bundle_ty)], T_void()), - fn_ty: fn_ty + x86_64_tys: x86_64 }; } @@ -221,14 +633,92 @@ fn trans_foreign_mod(ccx: @crate_ctxt, fn build_args(bcx: block, tys: @c_stack_tys, llargbundle: ValueRef) -> ~[ValueRef] { let _icx = bcx.insn_ctxt("foreign::shim::build_args"); - return tys.fn_ty.build_shim_args(bcx, tys.arg_tys, llargbundle); + let mut llargvals = ~[]; + let mut i = 0u; + let n = vec::len(tys.arg_tys); + + match tys.x86_64_tys { + Some(ref x86_64) => { + let mut atys = /*bad*/copy (*x86_64).arg_tys; + let mut attrs = /*bad*/copy (*x86_64).attrs; + if (*x86_64).sret { + let llretptr = GEPi(bcx, llargbundle, [0u, n]); + let llretloc = Load(bcx, llretptr); + llargvals = ~[llretloc]; + atys = vec::tail(atys); + attrs = vec::tail(attrs); + } + while i < n { + let llargval = if atys[i].cast { + let arg_ptr = GEPi(bcx, llargbundle, [0u, i]); + let arg_ptr = BitCast(bcx, arg_ptr, + T_ptr(atys[i].ty)); + Load(bcx, arg_ptr) + } else if attrs[i].is_some() { + GEPi(bcx, llargbundle, [0u, i]) + } else { + load_inbounds(bcx, llargbundle, [0u, i]) + }; + llargvals.push(llargval); + i += 1u; + } + } + _ => { + while i < n { + let llargval = load_inbounds(bcx, llargbundle, + [0u, i]); + llargvals.push(llargval); + i += 1u; + } + } + } + return llargvals; } fn build_ret(bcx: block, tys: @c_stack_tys, llargbundle: ValueRef, llretval: ValueRef) { let _icx = bcx.insn_ctxt("foreign::shim::build_ret"); - tys.fn_ty.build_shim_ret(bcx, tys.arg_tys, tys.ret_def, - llargbundle, llretval); + match tys.x86_64_tys { + Some(ref x86_64) => { + for vec::eachi((*x86_64).attrs) |i, a| { + match *a { + Some(attr) => { + unsafe { + llvm::LLVMAddInstrAttribute( + llretval, (i + 1u) as c_uint, + attr as c_uint); + } + } + _ => () + } + } + if (*x86_64).sret || !tys.ret_def { + return; + } + let n = vec::len(tys.arg_tys); + let llretptr = GEPi(bcx, llargbundle, [0u, n]); + let llretloc = Load(bcx, llretptr); + if (*x86_64).ret_ty.cast { + let tmp_ptr = BitCast(bcx, + llretloc, + T_ptr((*x86_64).ret_ty.ty)); + Store(bcx, llretval, tmp_ptr); + } else { + Store(bcx, llretval, llretloc); + }; + } + _ => { + if tys.ret_def { + let n = vec::len(tys.arg_tys); + // R** llretptr = &args->r; + let llretptr = GEPi(bcx, llargbundle, [0u, n]); + // R* llretloc = *llretptr; /* (args->r) */ + let llretloc = Load(bcx, llretptr); + // *args->r = r; + Store(bcx, llretval, llretloc); + } + } + } } let lname = link_name(ccx, foreign_item); @@ -242,8 +732,16 @@ fn trans_foreign_mod(ccx: @crate_ctxt, fn base_fn(ccx: @crate_ctxt, +lname: ~str, tys: @c_stack_tys, cc: lib::llvm::CallConv) -> ValueRef { // Declare the "prototype" for the base function F: - do tys.fn_ty.decl_fn |fnty| { - decl_fn(ccx.llmod, /*bad*/copy lname, cc, fnty) + match tys.x86_64_tys { + Some(ref x86_64) => { + do decl_x86_64_fn((*x86_64)) |fnty| { + decl_fn(ccx.llmod, /*bad*/copy lname, cc, fnty) + } + } + _ => { + let llbasefnty = T_fn(/*bad*/copy tys.arg_tys, tys.ret_ty); + decl_fn(ccx.llmod, lname, cc, llbasefnty) + } } } @@ -885,15 +1383,84 @@ fn trans_foreign_fn(ccx: @crate_ctxt, +path: ast_map::path, fn build_args(bcx: block, tys: @c_stack_tys, llwrapfn: ValueRef, llargbundle: ValueRef) { let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_args"); - tys.fn_ty.build_wrap_args(bcx, tys.ret_ty, - llwrapfn, llargbundle); + match tys.x86_64_tys { + option::Some(ref x86_64) => { + let mut atys = /*bad*/copy (*x86_64).arg_tys; + let mut attrs = /*bad*/copy (*x86_64).attrs; + let mut j = 0u; + let llretptr = if (*x86_64).sret { + atys = vec::tail(atys); + attrs = vec::tail(attrs); + j = 1u; + get_param(llwrapfn, 0u) + } else if (*x86_64).ret_ty.cast { + let retptr = alloca(bcx, (*x86_64).ret_ty.ty); + BitCast(bcx, retptr, T_ptr(tys.ret_ty)) + } else { + alloca(bcx, tys.ret_ty) + }; + + let mut i = 0u; + let n = vec::len(atys); + while i < n { + let mut argval = get_param(llwrapfn, i + j); + if attrs[i].is_some() { + argval = Load(bcx, argval); + store_inbounds(bcx, argval, llargbundle, + [0u, i]); + } else if atys[i].cast { + let argptr = GEPi(bcx, llargbundle, [0u, i]); + let argptr = BitCast(bcx, argptr, + T_ptr(atys[i].ty)); + Store(bcx, argval, argptr); + } else { + store_inbounds(bcx, argval, llargbundle, + [0u, i]); + } + i += 1u; + } + store_inbounds(bcx, llretptr, llargbundle, [0u, n]); + } + _ => { + let llretptr = alloca(bcx, tys.ret_ty); + let n = vec::len(tys.arg_tys); + for uint::range(0u, n) |i| { + let llargval = get_param(llwrapfn, i); + store_inbounds(bcx, llargval, llargbundle, + [0u, i]); + }; + store_inbounds(bcx, llretptr, llargbundle, [0u, n]); + } + } } fn build_ret(bcx: block, tys: @c_stack_tys, llargbundle: ValueRef) { let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_ret"); - tys.fn_ty.build_wrap_ret(bcx, tys.arg_tys, tys.ret_def, - llargbundle); + match tys.x86_64_tys { + option::Some(ref x86_64) => { + if (*x86_64).sret || !tys.ret_def { + RetVoid(bcx); + return; + } + let n = vec::len(tys.arg_tys); + let llretval = load_inbounds(bcx, llargbundle, ~[0u, n]); + let llretval = if (*x86_64).ret_ty.cast { + let retptr = BitCast(bcx, llretval, + T_ptr((*x86_64).ret_ty.ty)); + Load(bcx, retptr) + } else { + Load(bcx, llretval) + }; + Ret(bcx, llretval); + } + _ => { + let n = vec::len(tys.arg_tys); + let llretval = load_inbounds(bcx, llargbundle, ~[0u, n]); + let llretval = Load(bcx, llretval); + Ret(bcx, llretval); + } + } } build_wrap_fn_(ccx, tys, llshimfn, llwrapfn, @@ -920,12 +1487,25 @@ fn register_foreign_fn(ccx: @crate_ctxt, let _icx = ccx.insn_ctxt("foreign::register_foreign_fn"); let t = ty::node_id_to_type(ccx.tcx, node_id); let (llargtys, llretty, ret_ty) = c_arg_and_ret_lltys(ccx, node_id); - let ret_def = !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty); - let fn_ty = abi_info(ccx.sess.targ_cfg.arch). - compute_info(llargtys, llretty, ret_def); - do fn_ty.decl_fn |fnty| { - register_fn_fuller(ccx, sp, /*bad*/copy path, node_id, attrs, - t, lib::llvm::CCallConv, fnty) + return if ccx.sess.targ_cfg.arch == arch_x86_64 { + let ret_def = !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty); + let x86_64 = x86_64_tys(llargtys, llretty, ret_def); + do decl_x86_64_fn(x86_64) |fnty| { + register_fn_fuller(ccx, sp, /*bad*/copy path, node_id, attrs, + t, lib::llvm::CCallConv, fnty) + } + } else if ccx.sess.targ_cfg.arch == arch_arm { + let ret_def = !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty); + let x86_64 = x86_64_tys(llargtys, llretty, ret_def); + do decl_x86_64_fn(x86_64) |fnty| { + register_fn_fuller(ccx, sp, /*bad*/copy path, node_id, attrs, + t, lib::llvm::CCallConv, fnty) + } + + } else { + let llfty = T_fn(llargtys, llretty); + register_fn_fuller(ccx, sp, path, node_id, attrs, + t, lib::llvm::CCallConv, llfty) } } diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 818c6eb04ea..4e101eb5bb7 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -86,10 +86,6 @@ mod middle { #[legacy_exports] mod meth; #[legacy_exports] - mod cabi; - #[legacy_exports] - mod cabi_x86_64; - #[legacy_exports] mod foreign; #[legacy_exports] mod reflect;