trans: Revamp and empower cabi::FnType.
This commit is contained in:
parent
9221b9118b
commit
c6d214bdeb
@ -10,8 +10,9 @@
|
||||
|
||||
pub use self::ArgKind::*;
|
||||
|
||||
use llvm::Attribute;
|
||||
use std::option;
|
||||
use llvm::{self, AttrHelper, ValueRef};
|
||||
use trans::attributes;
|
||||
use trans::common::return_type_is_void;
|
||||
use trans::context::CrateContext;
|
||||
use trans::cabi_x86;
|
||||
use trans::cabi_x86_64;
|
||||
@ -23,6 +24,11 @@ use trans::cabi_powerpc64;
|
||||
use trans::cabi_mips;
|
||||
use trans::cabi_asmjs;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
|
||||
use middle::ty::{self, Ty};
|
||||
|
||||
use syntax::abi::Abi;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum ArgKind {
|
||||
@ -45,17 +51,17 @@ pub struct ArgType {
|
||||
/// Original LLVM type
|
||||
pub ty: Type,
|
||||
/// Coerced LLVM Type
|
||||
pub cast: option::Option<Type>,
|
||||
pub cast: Option<Type>,
|
||||
/// Dummy argument, which is emitted before the real argument
|
||||
pub pad: option::Option<Type>,
|
||||
pub pad: Option<Type>,
|
||||
/// LLVM attribute of argument
|
||||
pub attr: option::Option<Attribute>
|
||||
pub attr: Option<llvm::Attribute>
|
||||
}
|
||||
|
||||
impl ArgType {
|
||||
pub fn direct(ty: Type, cast: option::Option<Type>,
|
||||
pad: option::Option<Type>,
|
||||
attr: option::Option<Attribute>) -> ArgType {
|
||||
pub fn direct(ty: Type, cast: Option<Type>,
|
||||
pad: Option<Type>,
|
||||
attr: Option<llvm::Attribute>) -> ArgType {
|
||||
ArgType {
|
||||
kind: Direct,
|
||||
ty: ty,
|
||||
@ -65,12 +71,12 @@ impl ArgType {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indirect(ty: Type, attr: option::Option<Attribute>) -> ArgType {
|
||||
pub fn indirect(ty: Type, attr: Option<llvm::Attribute>) -> ArgType {
|
||||
ArgType {
|
||||
kind: Indirect,
|
||||
ty: ty,
|
||||
cast: option::Option::None,
|
||||
pad: option::Option::None,
|
||||
cast: Option::None,
|
||||
pad: Option::None,
|
||||
attr: attr
|
||||
}
|
||||
}
|
||||
@ -94,6 +100,14 @@ impl ArgType {
|
||||
}
|
||||
}
|
||||
|
||||
fn c_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
|
||||
if ty.is_bool() {
|
||||
Type::i1(cx)
|
||||
} else {
|
||||
type_of::type_of(cx, ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata describing how the arguments to a native function
|
||||
/// should be passed in order to respect the native ABI.
|
||||
///
|
||||
@ -101,37 +115,160 @@ impl ArgType {
|
||||
/// comments are reverse-engineered and may be inaccurate. -NDM
|
||||
pub struct FnType {
|
||||
/// The LLVM types of each argument.
|
||||
pub arg_tys: Vec<ArgType> ,
|
||||
pub args: Vec<ArgType>,
|
||||
|
||||
/// LLVM return type.
|
||||
pub ret_ty: ArgType,
|
||||
pub ret: ArgType,
|
||||
|
||||
pub variadic: bool,
|
||||
|
||||
pub cconv: llvm::CallConv
|
||||
}
|
||||
|
||||
pub fn compute_abi_info(ccx: &CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
impl FnType {
|
||||
pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
abi: Abi,
|
||||
sig: &ty::FnSig<'tcx>,
|
||||
extra_args: &[Ty<'tcx>]) -> FnType {
|
||||
use syntax::abi::Abi::*;
|
||||
let cconv = match ccx.sess().target.target.adjust_abi(abi) {
|
||||
RustIntrinsic => {
|
||||
// Intrinsics are emitted at the call site
|
||||
ccx.sess().bug("asked to register intrinsic fn");
|
||||
}
|
||||
PlatformIntrinsic => {
|
||||
// Intrinsics are emitted at the call site
|
||||
ccx.sess().bug("asked to register platform intrinsic fn");
|
||||
}
|
||||
|
||||
Rust => {
|
||||
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
|
||||
ccx.sess().unimpl("foreign functions with Rust ABI");
|
||||
}
|
||||
|
||||
RustCall => {
|
||||
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
|
||||
ccx.sess().unimpl("foreign functions with RustCall ABI");
|
||||
}
|
||||
|
||||
// It's the ABI's job to select this, not us.
|
||||
System => ccx.sess().bug("system abi should be selected elsewhere"),
|
||||
|
||||
Stdcall => llvm::X86StdcallCallConv,
|
||||
Fastcall => llvm::X86FastcallCallConv,
|
||||
Vectorcall => llvm::X86_VectorCall,
|
||||
C => llvm::CCallConv,
|
||||
Win64 => llvm::X86_64_Win64,
|
||||
|
||||
// These API constants ought to be more specific...
|
||||
Cdecl => llvm::CCallConv,
|
||||
Aapcs => llvm::CCallConv,
|
||||
};
|
||||
|
||||
let rty = match sig.output {
|
||||
ty::FnConverging(ret_ty) if !return_type_is_void(ccx, ret_ty) => {
|
||||
c_type_of(ccx, ret_ty)
|
||||
}
|
||||
_ => Type::void(ccx)
|
||||
};
|
||||
|
||||
let mut fty = FnType {
|
||||
args: sig.inputs.iter().chain(extra_args.iter()).map(|&ty| {
|
||||
ArgType::direct(c_type_of(ccx, ty), None, None, None)
|
||||
}).collect(),
|
||||
ret: ArgType::direct(rty, None, None, None),
|
||||
variadic: sig.variadic,
|
||||
cconv: cconv
|
||||
};
|
||||
|
||||
match &ccx.sess().target.target.arch[..] {
|
||||
"x86" => cabi_x86::compute_abi_info(ccx, atys, rty, ret_def),
|
||||
"x86" => cabi_x86::compute_abi_info(ccx, &mut fty),
|
||||
"x86_64" => if ccx.sess().target.target.options.is_like_windows {
|
||||
cabi_x86_win64::compute_abi_info(ccx, atys, rty, ret_def)
|
||||
cabi_x86_win64::compute_abi_info(ccx, &mut fty);
|
||||
} else {
|
||||
cabi_x86_64::compute_abi_info(ccx, atys, rty, ret_def)
|
||||
cabi_x86_64::compute_abi_info(ccx, &mut fty);
|
||||
},
|
||||
"aarch64" => cabi_aarch64::compute_abi_info(ccx, atys, rty, ret_def),
|
||||
"aarch64" => cabi_aarch64::compute_abi_info(ccx, &mut fty),
|
||||
"arm" => {
|
||||
let flavor = if ccx.sess().target.target.target_os == "ios" {
|
||||
cabi_arm::Flavor::Ios
|
||||
} else {
|
||||
cabi_arm::Flavor::General
|
||||
};
|
||||
cabi_arm::compute_abi_info(ccx, atys, rty, ret_def, flavor)
|
||||
cabi_arm::compute_abi_info(ccx, &mut fty, flavor);
|
||||
},
|
||||
"mips" => cabi_mips::compute_abi_info(ccx, atys, rty, ret_def),
|
||||
"powerpc" => cabi_powerpc::compute_abi_info(ccx, atys, rty, ret_def),
|
||||
"powerpc64" => cabi_powerpc64::compute_abi_info(ccx, atys, rty, ret_def),
|
||||
"asmjs" => cabi_asmjs::compute_abi_info(ccx, atys, rty, ret_def),
|
||||
a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)
|
||||
),
|
||||
"mips" => cabi_mips::compute_abi_info(ccx, &mut fty),
|
||||
"powerpc" => cabi_powerpc::compute_abi_info(ccx, &mut fty),
|
||||
"powerpc64" => cabi_powerpc64::compute_abi_info(ccx, &mut fty),
|
||||
"asmjs" => cabi_asmjs::compute_abi_info(ccx, &mut fty),
|
||||
a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
|
||||
}
|
||||
|
||||
fty
|
||||
}
|
||||
|
||||
pub fn to_llvm(&self, ccx: &CrateContext) -> Type {
|
||||
let mut llargument_tys = Vec::new();
|
||||
|
||||
let llreturn_ty = if self.ret.is_indirect() {
|
||||
llargument_tys.push(self.ret.ty.ptr_to());
|
||||
Type::void(ccx)
|
||||
} else {
|
||||
self.ret.cast.unwrap_or(self.ret.ty)
|
||||
};
|
||||
|
||||
for arg in &self.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
// add padding
|
||||
if let Some(ty) = arg.pad {
|
||||
llargument_tys.push(ty);
|
||||
}
|
||||
|
||||
let llarg_ty = if arg.is_indirect() {
|
||||
arg.ty.ptr_to()
|
||||
} else {
|
||||
arg.cast.unwrap_or(arg.ty)
|
||||
};
|
||||
|
||||
llargument_tys.push(llarg_ty);
|
||||
}
|
||||
|
||||
if self.variadic {
|
||||
Type::variadic_func(&llargument_tys, &llreturn_ty)
|
||||
} else {
|
||||
Type::func(&llargument_tys, &llreturn_ty)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_attributes(&self, llfn: ValueRef) {
|
||||
let mut i = if self.ret.is_indirect() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if let Some(attr) = self.ret.attr {
|
||||
attr.apply_llfn(i, llfn);
|
||||
}
|
||||
|
||||
i += 1;
|
||||
|
||||
for arg in &self.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
// skip padding
|
||||
if arg.pad.is_some() { i += 1; }
|
||||
|
||||
if let Some(attr) = arg.attr {
|
||||
attr.apply_llfn(i, llfn);
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
attributes::unwind(llfn, false);
|
||||
}
|
||||
}
|
||||
|
@ -228,24 +228,12 @@ fn is_reg_ty(ty: Type) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info(ccx: &CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
let mut arg_tys = Vec::new();
|
||||
for &aty in atys {
|
||||
let ty = classify_arg_ty(ccx, aty);
|
||||
arg_tys.push(ty);
|
||||
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
|
||||
if fty.ret.ty != Type::void(ccx) {
|
||||
fty.ret = classify_ret_ty(ccx, fty.ret.ty);
|
||||
}
|
||||
|
||||
let ret_ty = if ret_def {
|
||||
classify_ret_ty(ccx, rty)
|
||||
} else {
|
||||
ArgType::direct(Type::void(ccx), None, None, None)
|
||||
};
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
};
|
||||
for arg in &mut fty.args {
|
||||
*arg = classify_arg_ty(ccx, arg.ty);
|
||||
}
|
||||
}
|
||||
|
@ -174,30 +174,17 @@ fn is_reg_ty(ty: Type) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info(ccx: &CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool,
|
||||
flavor: Flavor) -> FnType {
|
||||
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
|
||||
let align_fn = match flavor {
|
||||
Flavor::General => general_ty_align as TyAlignFn,
|
||||
Flavor::Ios => ios_ty_align as TyAlignFn,
|
||||
};
|
||||
|
||||
let mut arg_tys = Vec::new();
|
||||
for &aty in atys {
|
||||
let ty = classify_arg_ty(ccx, aty, align_fn);
|
||||
arg_tys.push(ty);
|
||||
if fty.ret.ty != Type::void(ccx) {
|
||||
fty.ret = classify_ret_ty(ccx, fty.ret.ty, align_fn);
|
||||
}
|
||||
|
||||
let ret_ty = if ret_def {
|
||||
classify_ret_ty(ccx, rty, align_fn)
|
||||
} else {
|
||||
ArgType::direct(Type::void(ccx), None, None, None)
|
||||
};
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
};
|
||||
for arg in &mut fty.args {
|
||||
*arg = classify_arg_ty(ccx, arg.ty, align_fn);
|
||||
}
|
||||
}
|
||||
|
@ -49,24 +49,12 @@ fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info(ccx: &CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
let mut arg_tys = Vec::new();
|
||||
for &aty in atys {
|
||||
let ty = classify_arg_ty(ccx, aty);
|
||||
arg_tys.push(ty);
|
||||
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
|
||||
if fty.ret.ty != Type::void(ccx) {
|
||||
fty.ret = classify_ret_ty(ccx, fty.ret.ty);
|
||||
}
|
||||
|
||||
let ret_ty = if ret_def {
|
||||
classify_ret_ty(ccx, rty)
|
||||
} else {
|
||||
ArgType::direct(Type::void(ccx), None, None, None)
|
||||
};
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
};
|
||||
for arg in &mut fty.args {
|
||||
*arg = classify_arg_ty(ccx, arg.ty);
|
||||
}
|
||||
}
|
||||
|
@ -161,27 +161,13 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
|
||||
Type::struct_(ccx, &coerce_to_int(ccx, size), false)
|
||||
}
|
||||
|
||||
pub fn compute_abi_info(ccx: &CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
let ret_ty = if ret_def {
|
||||
classify_ret_ty(ccx, rty)
|
||||
} else {
|
||||
ArgType::direct(Type::void(ccx), None, None, None)
|
||||
};
|
||||
|
||||
let sret = ret_ty.is_indirect();
|
||||
let mut arg_tys = Vec::new();
|
||||
let mut offset = if sret { 4 } else { 0 };
|
||||
|
||||
for aty in atys {
|
||||
let ty = classify_arg_ty(ccx, *aty, &mut offset);
|
||||
arg_tys.push(ty);
|
||||
};
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
};
|
||||
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
|
||||
if fty.ret.ty != Type::void(ccx) {
|
||||
fty.ret = classify_ret_ty(ccx, fty.ret.ty);
|
||||
}
|
||||
|
||||
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
|
||||
for arg in &mut fty.args {
|
||||
*arg = classify_arg_ty(ccx, arg.ty, &mut offset);
|
||||
}
|
||||
}
|
||||
|
@ -156,27 +156,13 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
|
||||
Type::struct_(ccx, &coerce_to_int(ccx, size), false)
|
||||
}
|
||||
|
||||
pub fn compute_abi_info(ccx: &CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
let ret_ty = if ret_def {
|
||||
classify_ret_ty(ccx, rty)
|
||||
} else {
|
||||
ArgType::direct(Type::void(ccx), None, None, None)
|
||||
};
|
||||
|
||||
let sret = ret_ty.is_indirect();
|
||||
let mut arg_tys = Vec::new();
|
||||
let mut offset = if sret { 4 } else { 0 };
|
||||
|
||||
for aty in atys {
|
||||
let ty = classify_arg_ty(ccx, *aty, &mut offset);
|
||||
arg_tys.push(ty);
|
||||
};
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
};
|
||||
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
|
||||
if fty.ret.ty != Type::void(ccx) {
|
||||
fty.ret = classify_ret_ty(ccx, fty.ret.ty);
|
||||
}
|
||||
|
||||
let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
|
||||
for arg in &mut fty.args {
|
||||
*arg = classify_arg_ty(ccx, arg.ty, &mut offset);
|
||||
}
|
||||
}
|
||||
|
@ -236,24 +236,12 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
|
||||
Type::struct_(ccx, &coerce_to_long(ccx, size), false)
|
||||
}
|
||||
|
||||
pub fn compute_abi_info(ccx: &CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
let ret_ty = if ret_def {
|
||||
classify_ret_ty(ccx, rty)
|
||||
} else {
|
||||
ArgType::direct(Type::void(ccx), None, None, None)
|
||||
};
|
||||
|
||||
let mut arg_tys = Vec::new();
|
||||
for &aty in atys {
|
||||
let ty = classify_arg_ty(ccx, aty);
|
||||
arg_tys.push(ty);
|
||||
};
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
};
|
||||
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
|
||||
if fty.ret.ty != Type::void(ccx) {
|
||||
fty.ret = classify_ret_ty(ccx, fty.ret.ty);
|
||||
}
|
||||
|
||||
for arg in &mut fty.args {
|
||||
*arg = classify_arg_ty(ccx, arg.ty);
|
||||
}
|
||||
}
|
||||
|
@ -8,24 +8,14 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use self::Strategy::*;
|
||||
use llvm::*;
|
||||
use trans::cabi::{ArgType, FnType};
|
||||
use trans::type_::Type;
|
||||
use super::common::*;
|
||||
use super::machine::*;
|
||||
|
||||
enum Strategy { RetValue(Type), RetPointer }
|
||||
pub fn compute_abi_info(ccx: &CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
let mut arg_tys = Vec::new();
|
||||
|
||||
let ret_ty;
|
||||
if !ret_def {
|
||||
ret_ty = ArgType::direct(Type::void(ccx), None, None, None);
|
||||
} else if rty.kind() == Struct {
|
||||
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
|
||||
if fty.ret.ty.kind() == Struct {
|
||||
// Returning a structure. Most often, this will use
|
||||
// a hidden first argument. On some platforms, though,
|
||||
// small structs are returned as integers.
|
||||
@ -33,53 +23,33 @@ pub fn compute_abi_info(ccx: &CrateContext,
|
||||
// Some links:
|
||||
// http://www.angelcode.com/dev/callconv/callconv.html
|
||||
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
|
||||
let indirect = ArgType::indirect(fty.ret.ty, Some(Attribute::StructRet));
|
||||
|
||||
let t = &ccx.sess().target.target;
|
||||
let strategy = if t.options.is_like_osx || t.options.is_like_windows {
|
||||
match llsize_of_alloc(ccx, rty) {
|
||||
1 => RetValue(Type::i8(ccx)),
|
||||
2 => RetValue(Type::i16(ccx)),
|
||||
4 => RetValue(Type::i32(ccx)),
|
||||
8 => RetValue(Type::i64(ccx)),
|
||||
_ => RetPointer
|
||||
if t.options.is_like_osx || t.options.is_like_windows {
|
||||
match llsize_of_alloc(ccx, fty.ret.ty) {
|
||||
1 => fty.ret.cast = Some(Type::i8(ccx)),
|
||||
2 => fty.ret.cast = Some(Type::i16(ccx)),
|
||||
4 => fty.ret.cast = Some(Type::i32(ccx)),
|
||||
8 => fty.ret.cast = Some(Type::i64(ccx)),
|
||||
_ => fty.ret = indirect
|
||||
}
|
||||
} else {
|
||||
RetPointer
|
||||
};
|
||||
fty.ret = indirect;
|
||||
}
|
||||
} else if fty.ret.ty == Type::i1(ccx) {
|
||||
fty.ret.attr = Some(Attribute::ZExt);
|
||||
}
|
||||
|
||||
match strategy {
|
||||
RetValue(t) => {
|
||||
ret_ty = ArgType::direct(rty, Some(t), None, None);
|
||||
}
|
||||
RetPointer => {
|
||||
ret_ty = ArgType::indirect(rty, Some(Attribute::StructRet));
|
||||
}
|
||||
}
|
||||
for arg in &mut fty.args {
|
||||
if arg.ty.kind() == Struct {
|
||||
*arg = if llsize_of_alloc(ccx, arg.ty) == 0 {
|
||||
ArgType::ignore(arg.ty)
|
||||
} else {
|
||||
let attr = if rty == Type::i1(ccx) { Some(Attribute::ZExt) } else { None };
|
||||
ret_ty = ArgType::direct(rty, None, None, attr);
|
||||
}
|
||||
|
||||
for &t in atys {
|
||||
let ty = match t.kind() {
|
||||
Struct => {
|
||||
let size = llsize_of_alloc(ccx, t);
|
||||
if size == 0 {
|
||||
ArgType::ignore(t)
|
||||
} else {
|
||||
ArgType::indirect(t, Some(Attribute::ByVal))
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let attr = if t == Type::i1(ccx) { Some(Attribute::ZExt) } else { None };
|
||||
ArgType::direct(t, None, None, attr)
|
||||
}
|
||||
ArgType::indirect(arg.ty, Some(Attribute::ByVal))
|
||||
};
|
||||
arg_tys.push(ty);
|
||||
} else if arg.ty == Type::i1(ccx) {
|
||||
arg.attr = Some(Attribute::ZExt);
|
||||
}
|
||||
}
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
};
|
||||
}
|
||||
|
@ -383,10 +383,7 @@ fn llreg_ty(ccx: &CrateContext, cls: &[RegClass]) -> Type {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_abi_info(ccx: &CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
|
||||
fn x86_64_ty<F>(ccx: &CrateContext,
|
||||
ty: Type,
|
||||
is_mem_cls: F,
|
||||
@ -413,8 +410,8 @@ pub fn compute_abi_info(ccx: &CrateContext,
|
||||
let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
|
||||
let mut sse_regs = 8; // XMM0-7
|
||||
|
||||
let ret_ty = if ret_def {
|
||||
x86_64_ty(ccx, rty, |cls| {
|
||||
if fty.ret.ty != Type::void(ccx) {
|
||||
fty.ret = x86_64_ty(ccx, fty.ret.ty, |cls| {
|
||||
if cls.is_ret_bysret() {
|
||||
// `sret` parameter thus one less register available
|
||||
int_regs -= 1;
|
||||
@ -422,14 +419,11 @@ pub fn compute_abi_info(ccx: &CrateContext,
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}, Attribute::StructRet)
|
||||
} else {
|
||||
ArgType::direct(Type::void(ccx), None, None, None)
|
||||
};
|
||||
}, Attribute::StructRet);
|
||||
}
|
||||
|
||||
let mut arg_tys = Vec::new();
|
||||
for t in atys {
|
||||
let ty = x86_64_ty(ccx, *t, |cls| {
|
||||
for arg in &mut fty.args {
|
||||
*arg = x86_64_ty(ccx, arg.ty, |cls| {
|
||||
let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize;
|
||||
let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize;
|
||||
let in_mem = cls.is_pass_byval() ||
|
||||
@ -445,20 +439,14 @@ pub fn compute_abi_info(ccx: &CrateContext,
|
||||
}
|
||||
in_mem
|
||||
}, Attribute::ByVal);
|
||||
arg_tys.push(ty);
|
||||
|
||||
// An integer, pointer, double or float parameter
|
||||
// thus the above closure passed to `x86_64_ty` won't
|
||||
// get called.
|
||||
if t.kind() == Integer || t.kind() == Pointer {
|
||||
int_regs -= 1;
|
||||
} else if t.kind() == Double || t.kind() == Float {
|
||||
sse_regs -= 1;
|
||||
match arg.ty.kind() {
|
||||
Integer | Pointer => int_regs -= 1,
|
||||
Double | Float => sse_regs -= 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
};
|
||||
}
|
||||
|
@ -16,49 +16,23 @@ use trans::type_::Type;
|
||||
|
||||
// Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
|
||||
|
||||
pub fn compute_abi_info(ccx: &CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
let mut arg_tys = Vec::new();
|
||||
|
||||
let ret_ty;
|
||||
if !ret_def {
|
||||
ret_ty = ArgType::direct(Type::void(ccx), None, None, None);
|
||||
} else if rty.kind() == Struct {
|
||||
ret_ty = match llsize_of_alloc(ccx, rty) {
|
||||
1 => ArgType::direct(rty, Some(Type::i8(ccx)), None, None),
|
||||
2 => ArgType::direct(rty, Some(Type::i16(ccx)), None, None),
|
||||
4 => ArgType::direct(rty, Some(Type::i32(ccx)), None, None),
|
||||
8 => ArgType::direct(rty, Some(Type::i64(ccx)), None, None),
|
||||
_ => ArgType::indirect(rty, Some(Attribute::StructRet))
|
||||
};
|
||||
} else {
|
||||
let attr = if rty == Type::i1(ccx) { Some(Attribute::ZExt) } else { None };
|
||||
ret_ty = ArgType::direct(rty, None, None, attr);
|
||||
pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
|
||||
let fixup = |a: &mut ArgType, indirect_attr| {
|
||||
if a.ty.kind() == Struct {
|
||||
match llsize_of_alloc(ccx, a.ty) {
|
||||
1 => a.cast = Some(Type::i8(ccx)),
|
||||
2 => a.cast = Some(Type::i16(ccx)),
|
||||
4 => a.cast = Some(Type::i32(ccx)),
|
||||
8 => a.cast = Some(Type::i64(ccx)),
|
||||
_ => *a = ArgType::indirect(a.ty, indirect_attr)
|
||||
}
|
||||
|
||||
for &t in atys {
|
||||
let ty = match t.kind() {
|
||||
Struct => {
|
||||
match llsize_of_alloc(ccx, t) {
|
||||
1 => ArgType::direct(t, Some(Type::i8(ccx)), None, None),
|
||||
2 => ArgType::direct(t, Some(Type::i16(ccx)), None, None),
|
||||
4 => ArgType::direct(t, Some(Type::i32(ccx)), None, None),
|
||||
8 => ArgType::direct(t, Some(Type::i64(ccx)), None, None),
|
||||
_ => ArgType::indirect(t, None)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let attr = if t == Type::i1(ccx) { Some(Attribute::ZExt) } else { None };
|
||||
ArgType::direct(t, None, None, attr)
|
||||
} else if a.ty == Type::i1(ccx) {
|
||||
a.attr = Some(Attribute::ZExt);
|
||||
}
|
||||
};
|
||||
arg_tys.push(ty);
|
||||
}
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
};
|
||||
fixup(&mut fty.ret, Some(Attribute::StructRet));
|
||||
for arg in &mut fty.args {
|
||||
fixup(arg, None);
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ use trans::attributes;
|
||||
use trans::base::{llvm_linkage_by_name, push_ctxt};
|
||||
use trans::base;
|
||||
use trans::build::*;
|
||||
use trans::cabi;
|
||||
use trans::cabi::FnType;
|
||||
use trans::common::*;
|
||||
use trans::debuginfo::DebugLoc;
|
||||
use trans::declare;
|
||||
@ -45,83 +45,15 @@ use syntax::attr::AttrMetaMethods;
|
||||
use rustc_front::print::pprust;
|
||||
use rustc_front::hir;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Type definitions
|
||||
|
||||
struct ForeignTypes<'tcx> {
|
||||
/// Rust signature of the function
|
||||
fn_sig: ty::FnSig<'tcx>,
|
||||
|
||||
/// Adapter object for handling native ABI rules (trust me, you
|
||||
/// don't want to know)
|
||||
fn_ty: cabi::FnType,
|
||||
|
||||
/// LLVM types that will appear on the foreign function
|
||||
llsig: LlvmSignature,
|
||||
}
|
||||
|
||||
struct LlvmSignature {
|
||||
// LLVM versions of the types of this function's arguments.
|
||||
llarg_tys: Vec<Type> ,
|
||||
|
||||
// LLVM version of the type that this function returns. Note that
|
||||
// this *may not be* the declared return type of the foreign
|
||||
// function, because the foreign function may opt to return via an
|
||||
// out pointer.
|
||||
llret_ty: Type,
|
||||
|
||||
/// True if there is a return value (not bottom, not unit)
|
||||
ret_def: bool,
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Calls to external functions
|
||||
|
||||
pub fn llvm_calling_convention(ccx: &CrateContext,
|
||||
abi: Abi) -> CallConv {
|
||||
use syntax::abi::Abi::*;
|
||||
match ccx.sess().target.target.adjust_abi(abi) {
|
||||
RustIntrinsic => {
|
||||
// Intrinsics are emitted at the call site
|
||||
ccx.sess().bug("asked to register intrinsic fn");
|
||||
}
|
||||
PlatformIntrinsic => {
|
||||
// Intrinsics are emitted at the call site
|
||||
ccx.sess().bug("asked to register platform intrinsic fn");
|
||||
}
|
||||
|
||||
Rust => {
|
||||
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
|
||||
ccx.sess().unimpl("foreign functions with Rust ABI");
|
||||
}
|
||||
|
||||
RustCall => {
|
||||
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
|
||||
ccx.sess().unimpl("foreign functions with RustCall ABI");
|
||||
}
|
||||
|
||||
// It's the ABI's job to select this, not us.
|
||||
System => ccx.sess().bug("system abi should be selected elsewhere"),
|
||||
|
||||
Stdcall => llvm::X86StdcallCallConv,
|
||||
Fastcall => llvm::X86FastcallCallConv,
|
||||
Vectorcall => llvm::X86_VectorCall,
|
||||
C => llvm::CCallConv,
|
||||
Win64 => llvm::X86_64_Win64,
|
||||
|
||||
// These API constants ought to be more specific...
|
||||
Cdecl => llvm::CCallConv,
|
||||
Aapcs => llvm::CCallConv,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_static(ccx: &CrateContext,
|
||||
foreign_item: &hir::ForeignItem) -> ValueRef {
|
||||
let ty = ccx.tcx().node_id_to_type(foreign_item.id);
|
||||
let llty = type_of::type_of(ccx, ty);
|
||||
|
||||
let ident = link_name(foreign_item);
|
||||
let ident = link_name(foreign_item.name, &foreign_item.attrs);
|
||||
let c = match attr::first_attr_value_str_by_name(&foreign_item.attrs,
|
||||
"linkage") {
|
||||
// If this is a static with a linkage specified, then we need to handle
|
||||
@ -265,13 +197,9 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
};
|
||||
let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
|
||||
let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
|
||||
let llsig = foreign_signature(ccx, &fn_sig, &passed_arg_tys[..]);
|
||||
let fn_type = cabi::compute_abi_info(ccx,
|
||||
&llsig.llarg_tys,
|
||||
llsig.llret_ty,
|
||||
llsig.ret_def);
|
||||
|
||||
let arg_tys: &[cabi::ArgType] = &fn_type.arg_tys;
|
||||
let extra_args = &passed_arg_tys[fn_sig.inputs.len()..];
|
||||
let fn_type = FnType::new(ccx, fn_abi, &fn_sig, extra_args);
|
||||
|
||||
let mut llargs_foreign = Vec::new();
|
||||
|
||||
@ -279,8 +207,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
// pointer that Rust gave us. Sometimes we have to bitcast
|
||||
// because foreign fns return slightly different (but equivalent)
|
||||
// views on the same type (e.g., i64 in place of {i32,i32}).
|
||||
if fn_type.ret_ty.is_indirect() {
|
||||
match fn_type.ret_ty.cast {
|
||||
if fn_type.ret.is_indirect() {
|
||||
match fn_type.ret.cast {
|
||||
Some(ty) => {
|
||||
let llcastedretptr =
|
||||
BitCast(bcx, llretptr, ty.ptr_to());
|
||||
@ -293,7 +221,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
}
|
||||
|
||||
let mut offset = 0;
|
||||
for (i, arg_ty) in arg_tys.iter().enumerate() {
|
||||
for (i, arg_ty) in fn_type.args.iter().enumerate() {
|
||||
let mut llarg_rust = llargs_rust[i + offset];
|
||||
|
||||
if arg_ty.is_ignore() {
|
||||
@ -359,15 +287,13 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
llargs_foreign.push(llarg_foreign);
|
||||
}
|
||||
|
||||
let cc = llvm_calling_convention(ccx, fn_abi);
|
||||
|
||||
// A function pointer is called without the declaration available, so we have to apply
|
||||
// any attributes with ABI implications directly to the call instruction.
|
||||
let mut attrs = llvm::AttrBuilder::new();
|
||||
|
||||
// Add attributes that are always applicable, independent of the concrete foreign ABI
|
||||
if fn_type.ret_ty.is_indirect() {
|
||||
let llret_sz = machine::llsize_of_real(ccx, fn_type.ret_ty.ty);
|
||||
if fn_type.ret.is_indirect() {
|
||||
let llret_sz = machine::llsize_of_real(ccx, fn_type.ret.ty);
|
||||
|
||||
// The outptr can be noalias and nocapture because it's entirely
|
||||
// invisible to the program. We also know it's nonnull as well
|
||||
@ -378,14 +304,14 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
};
|
||||
|
||||
// Add attributes that depend on the concrete foreign ABI
|
||||
let mut arg_idx = if fn_type.ret_ty.is_indirect() { 1 } else { 0 };
|
||||
match fn_type.ret_ty.attr {
|
||||
let mut arg_idx = if fn_type.ret.is_indirect() { 1 } else { 0 };
|
||||
match fn_type.ret.attr {
|
||||
Some(attr) => { attrs.arg(arg_idx, attr); },
|
||||
_ => ()
|
||||
}
|
||||
|
||||
arg_idx += 1;
|
||||
for arg_ty in &fn_type.arg_tys {
|
||||
for arg_ty in &fn_type.args {
|
||||
if arg_ty.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
@ -402,7 +328,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
let llforeign_retval = CallWithConv(bcx,
|
||||
llfn,
|
||||
&llargs_foreign[..],
|
||||
cc,
|
||||
fn_type.cconv,
|
||||
Some(attrs),
|
||||
call_debug_loc);
|
||||
|
||||
@ -411,11 +337,11 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
// type to match because some ABIs will use a different type than
|
||||
// the Rust type. e.g., a {u32,u32} struct could be returned as
|
||||
// u64.
|
||||
if llsig.ret_def && !fn_type.ret_ty.is_indirect() {
|
||||
let llrust_ret_ty = llsig.llret_ty;
|
||||
let llforeign_ret_ty = match fn_type.ret_ty.cast {
|
||||
if fn_type.ret.ty != Type::void(ccx) && !fn_type.ret.is_indirect() {
|
||||
let llrust_ret_ty = fn_type.ret.ty;
|
||||
let llforeign_ret_ty = match fn_type.ret.cast {
|
||||
Some(ty) => ty,
|
||||
None => fn_type.ret_ty.ty
|
||||
None => fn_type.ret.ty
|
||||
};
|
||||
|
||||
debug!("llretptr={:?}", Value(llretptr));
|
||||
@ -543,14 +469,20 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
let fnty = ccx.tcx().node_id_to_type(id);
|
||||
let mty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fnty);
|
||||
let tys = foreign_types_for_fn_ty(ccx, mty);
|
||||
let (fn_abi, fn_sig) = match mty.sty {
|
||||
ty::TyFnDef(_, _, ref fn_ty) => (fn_ty.abi, &fn_ty.sig),
|
||||
_ => ccx.sess().bug("trans_rust_fn_with_foreign_abi called on non-function type")
|
||||
};
|
||||
let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
|
||||
let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
|
||||
let fn_ty = FnType::new(ccx, fn_abi, &fn_sig, &[]);
|
||||
|
||||
unsafe { // unsafe because we call LLVM operations
|
||||
// Build up the Rust function (`foo0` above).
|
||||
let llrustfn = build_rust_fn(ccx, decl, body, param_substs, attrs, id, hash);
|
||||
|
||||
// Build up the foreign wrapper (`foo` above).
|
||||
return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, mty);
|
||||
return build_wrap_fn(ccx, llrustfn, llwrapfn, &fn_sig, &fn_ty, mty);
|
||||
}
|
||||
|
||||
fn build_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
@ -568,7 +500,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
let t = monomorphize::apply_param_substs(tcx, param_substs, &t);
|
||||
|
||||
let path =
|
||||
tcx.map.def_path_from_id(id)
|
||||
tcx.map.def_path(tcx.map.local_def_id(id))
|
||||
.into_iter()
|
||||
.map(|e| e.data.as_interned_str())
|
||||
.chain(once(special_idents::clownshoe_abi.name.as_str()));
|
||||
@ -576,23 +508,27 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
// Compute the type that the function would have if it were just a
|
||||
// normal Rust function. This will be the type of the wrappee fn.
|
||||
match t.sty {
|
||||
ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f)=> {
|
||||
let rust_fn_ty = match t.sty {
|
||||
ty::TyFnDef(_, _, ref f) => {
|
||||
assert!(f.abi != Abi::Rust);
|
||||
assert!(f.abi != Abi::RustIntrinsic);
|
||||
assert!(f.abi != Abi::PlatformIntrinsic);
|
||||
tcx.mk_fn_ptr(ty::BareFnTy {
|
||||
unsafety: f.unsafety,
|
||||
abi: Abi::Rust,
|
||||
sig: f.sig.clone()
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
ccx.sess().bug(&format!("build_rust_fn: extern fn {} has ty {:?}, \
|
||||
expected a bare fn ty",
|
||||
ccx.tcx().map.path_to_string(id),
|
||||
t));
|
||||
unreachable!("build_rust_fn: extern fn {} has ty {:?}, \
|
||||
expected a fn item type",
|
||||
tcx.map.path_to_string(id), t);
|
||||
}
|
||||
};
|
||||
|
||||
debug!("build_rust_fn: path={} id={} t={:?}",
|
||||
debug!("build_rust_fn: path={} id={} ty={:?}",
|
||||
ccx.tcx().map.path_to_string(id),
|
||||
id, t);
|
||||
id, rust_fn_ty);
|
||||
|
||||
let llfn = declare::define_internal_rust_fn(ccx, &ps, t);
|
||||
attributes::from_fn_attrs(ccx, attrs, llfn);
|
||||
@ -603,7 +539,8 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
unsafe fn build_wrap_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
llrustfn: ValueRef,
|
||||
llwrapfn: ValueRef,
|
||||
tys: &ForeignTypes<'tcx>,
|
||||
fn_sig: &ty::FnSig<'tcx>,
|
||||
fn_ty: &FnType,
|
||||
t: Ty<'tcx>) {
|
||||
let _icx = push_ctxt(
|
||||
"foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
|
||||
@ -650,7 +587,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
// If there is an out pointer on the foreign function
|
||||
let foreign_outptr = {
|
||||
if tys.fn_ty.ret_ty.is_indirect() {
|
||||
if fn_ty.ret.is_indirect() {
|
||||
Some(get_param(llwrapfn, next_foreign_arg(false)))
|
||||
} else {
|
||||
None
|
||||
@ -660,7 +597,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
let rustfn_ty = Type::from_ref(llvm::LLVMTypeOf(llrustfn)).element_type();
|
||||
let mut rust_param_tys = rustfn_ty.func_params().into_iter();
|
||||
// Push Rust return pointer, using null if it will be unused.
|
||||
let rust_uses_outptr = match tys.fn_sig.output {
|
||||
let rust_uses_outptr = match fn_sig.output {
|
||||
ty::FnConverging(ret_ty) => type_of::return_uses_outptr(ccx, ret_ty),
|
||||
ty::FnDiverging => false
|
||||
};
|
||||
@ -696,7 +633,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
return_ty={:?}",
|
||||
Value(slot),
|
||||
llrust_ret_ty,
|
||||
tys.fn_sig.output);
|
||||
fn_sig.output);
|
||||
llrust_args.push(slot);
|
||||
return_alloca = Some(slot);
|
||||
}
|
||||
@ -711,8 +648,8 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
// Build up the arguments to the call to the rust function.
|
||||
// Careful to adapt for cases where the native convention uses
|
||||
// a pointer and Rust does not or vice versa.
|
||||
for i in 0..tys.fn_sig.inputs.len() {
|
||||
let rust_ty = tys.fn_sig.inputs[i];
|
||||
for i in 0..fn_sig.inputs.len() {
|
||||
let rust_ty = fn_sig.inputs[i];
|
||||
let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
|
||||
let llty = rust_param_tys.next().expect("Not enough parameter types!");
|
||||
let llrust_ty = if rust_indirect {
|
||||
@ -720,7 +657,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
} else {
|
||||
llty
|
||||
};
|
||||
let llforeign_arg_ty = tys.fn_ty.arg_tys[i];
|
||||
let llforeign_arg_ty = fn_ty.args[i];
|
||||
let foreign_indirect = llforeign_arg_ty.is_indirect();
|
||||
|
||||
if llforeign_arg_ty.is_ignore() {
|
||||
@ -802,12 +739,12 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
None, Some(attributes));
|
||||
|
||||
// Get the return value where the foreign fn expects it.
|
||||
let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
|
||||
let llforeign_ret_ty = match fn_ty.ret.cast {
|
||||
Some(ty) => ty,
|
||||
None => tys.fn_ty.ret_ty.ty
|
||||
None => fn_ty.ret.ty
|
||||
};
|
||||
match foreign_outptr {
|
||||
None if !tys.llsig.ret_def => {
|
||||
None if fn_ty.ret.ty == Type::void(ccx) => {
|
||||
// Function returns `()` or `bot`, which in Rust is the LLVM
|
||||
// type "{}" but in foreign ABIs is "Void".
|
||||
builder.ret_void();
|
||||
@ -874,140 +811,6 @@ pub fn link_name(name: ast::Name, attrs: &[ast::Attribute]) -> InternedString {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The ForeignSignature is the LLVM types of the arguments/return type of a function. Note that
|
||||
/// these LLVM types are not quite the same as the LLVM types would be for a native Rust function
|
||||
/// because foreign functions just plain ignore modes. They also don't pass aggregate values by
|
||||
/// pointer like we do.
|
||||
fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
fn_sig: &ty::FnSig<'tcx>,
|
||||
arg_tys: &[Ty<'tcx>])
|
||||
-> LlvmSignature {
|
||||
let llarg_tys = arg_tys.iter().map(|&arg| foreign_arg_type_of(ccx, arg)).collect();
|
||||
let (llret_ty, ret_def) = match fn_sig.output {
|
||||
ty::FnConverging(ret_ty) =>
|
||||
(type_of::foreign_arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)),
|
||||
ty::FnDiverging =>
|
||||
(Type::nil(ccx), false)
|
||||
};
|
||||
LlvmSignature {
|
||||
llarg_tys: llarg_tys,
|
||||
llret_ty: llret_ty,
|
||||
ret_def: ret_def
|
||||
}
|
||||
}
|
||||
|
||||
fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ty: Ty<'tcx>) -> ForeignTypes<'tcx> {
|
||||
let fn_sig = match ty.sty {
|
||||
ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => &fn_ty.sig,
|
||||
_ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
|
||||
};
|
||||
let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
|
||||
let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
|
||||
let llsig = foreign_signature(ccx, &fn_sig, &fn_sig.inputs);
|
||||
let fn_ty = cabi::compute_abi_info(ccx,
|
||||
&llsig.llarg_tys,
|
||||
llsig.llret_ty,
|
||||
llsig.ret_def);
|
||||
debug!("foreign_types_for_fn_ty(\
|
||||
ty={:?}, \
|
||||
llsig={:?} -> {:?}, \
|
||||
fn_ty={:?} -> {:?}, \
|
||||
ret_def={}",
|
||||
ty,
|
||||
llsig.llarg_tys,
|
||||
llsig.llret_ty,
|
||||
fn_ty.arg_tys,
|
||||
fn_ty.ret_ty,
|
||||
llsig.ret_def);
|
||||
|
||||
ForeignTypes {
|
||||
fn_sig: fn_sig,
|
||||
llsig: llsig,
|
||||
fn_ty: fn_ty
|
||||
}
|
||||
}
|
||||
|
||||
fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> Type {
|
||||
let mut llargument_tys = Vec::new();
|
||||
|
||||
let ret_ty = tys.fn_ty.ret_ty;
|
||||
let llreturn_ty = if ret_ty.is_indirect() {
|
||||
llargument_tys.push(ret_ty.ty.ptr_to());
|
||||
Type::void(ccx)
|
||||
} else {
|
||||
match ret_ty.cast {
|
||||
Some(ty) => ty,
|
||||
None => ret_ty.ty
|
||||
}
|
||||
};
|
||||
|
||||
for &arg_ty in &tys.fn_ty.arg_tys {
|
||||
if arg_ty.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
// add padding
|
||||
match arg_ty.pad {
|
||||
Some(ty) => llargument_tys.push(ty),
|
||||
None => ()
|
||||
}
|
||||
|
||||
let llarg_ty = if arg_ty.is_indirect() {
|
||||
arg_ty.ty.ptr_to()
|
||||
} else {
|
||||
match arg_ty.cast {
|
||||
Some(ty) => ty,
|
||||
None => arg_ty.ty
|
||||
}
|
||||
};
|
||||
|
||||
llargument_tys.push(llarg_ty);
|
||||
}
|
||||
|
||||
if tys.fn_sig.variadic {
|
||||
Type::variadic_func(&llargument_tys, &llreturn_ty)
|
||||
} else {
|
||||
Type::func(&llargument_tys[..], &llreturn_ty)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lltype_for_foreign_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ty: Ty<'tcx>) -> Type {
|
||||
lltype_for_fn_from_foreign_types(ccx, &foreign_types_for_fn_ty(ccx, ty))
|
||||
}
|
||||
|
||||
fn add_argument_attributes(tys: &ForeignTypes,
|
||||
llfn: ValueRef) {
|
||||
let mut i = if tys.fn_ty.ret_ty.is_indirect() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
match tys.fn_ty.ret_ty.attr {
|
||||
Some(attr) => unsafe {
|
||||
llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr.bits() as u64);
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
|
||||
for &arg_ty in &tys.fn_ty.arg_tys {
|
||||
if arg_ty.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
// skip padding
|
||||
if arg_ty.pad.is_some() { i += 1; }
|
||||
|
||||
match arg_ty.attr {
|
||||
Some(attr) => unsafe {
|
||||
llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr.bits() as u64);
|
||||
},
|
||||
None => ()
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ use middle::def_id::DefId;
|
||||
use middle::infer;
|
||||
use middle::subst;
|
||||
use trans::adt;
|
||||
use trans::cabi::FnType;
|
||||
use trans::common::*;
|
||||
use trans::foreign;
|
||||
use trans::machine;
|
||||
use middle::ty::{self, Ty, TypeFoldable};
|
||||
|
||||
@ -239,14 +239,6 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
|
||||
llsizingty
|
||||
}
|
||||
|
||||
pub fn foreign_arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
|
||||
if t.is_bool() {
|
||||
Type::i1(cx)
|
||||
} else {
|
||||
type_of(cx, t)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
|
||||
if t.is_bool() {
|
||||
Type::i1(cx)
|
||||
@ -390,12 +382,12 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
|
||||
|
||||
ty::TyFnDef(..) => Type::nil(cx),
|
||||
ty::TyFnPtr(f) => {
|
||||
if f.abi == Abi::Rust || f.abi == Abi::RustCall {
|
||||
let sig = cx.tcx().erase_late_bound_regions(&f.sig);
|
||||
let sig = infer::normalize_associated_type(cx.tcx(), &sig);
|
||||
if f.abi == Abi::Rust || f.abi == Abi::RustCall {
|
||||
type_of_rust_fn(cx, None, &sig, f.abi).ptr_to()
|
||||
} else {
|
||||
foreign::lltype_for_foreign_fn(cx, t).ptr_to()
|
||||
FnType::new(cx, f.abi, &sig, &[]).to_llvm(cx).ptr_to()
|
||||
}
|
||||
}
|
||||
ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
|
||||
|
Loading…
Reference in New Issue
Block a user