auto merge of #9517 : crabtw/rust/cabi, r=nikomatsakis
I borrow some ideas from clang's ABIInfo.h and TargetInfo.cpp. LLVMType is replaced with ArgType, which is similar to clang's ABIArgInfo, and I also merge attrs of FnType into it. Now ABI implementation doesn't need to insert hidden return pointer to arg_tys of FnType. Instead it is handled in foreign.rs. This change also fixes LLVM assertion failure when compiling MIPS target.
This commit is contained in:
commit
0daced63fc
@ -18,10 +18,62 @@ use middle::trans::cabi_mips;
|
||||
use middle::trans::type_::Type;
|
||||
use syntax::abi::{X86, X86_64, Arm, Mips};
|
||||
|
||||
#[deriving(Clone, Eq)]
|
||||
pub enum ArgKind {
|
||||
/// Pass the argument directly using the normal converted
|
||||
/// LLVM type or by coercing to another specified type
|
||||
Direct,
|
||||
/// Pass the argument indirectly via a hidden pointer
|
||||
Indirect
|
||||
}
|
||||
|
||||
/// Information about how a specific C type
|
||||
/// should be passed to or returned from a function
|
||||
///
|
||||
/// This is borrowed from clang's ABIInfo.h
|
||||
#[deriving(Clone)]
|
||||
pub struct LLVMType {
|
||||
cast: bool,
|
||||
ty: Type
|
||||
pub struct ArgType {
|
||||
kind: ArgKind,
|
||||
/// Original LLVM type
|
||||
ty: Type,
|
||||
/// Coerced LLVM Type
|
||||
cast: option::Option<Type>,
|
||||
/// Dummy argument, which is emitted before the real argument
|
||||
pad: option::Option<Type>,
|
||||
/// LLVM attribute of argument
|
||||
attr: option::Option<Attribute>
|
||||
}
|
||||
|
||||
impl ArgType {
|
||||
pub fn direct(ty: Type, cast: option::Option<Type>,
|
||||
pad: option::Option<Type>,
|
||||
attr: option::Option<Attribute>) -> ArgType {
|
||||
ArgType {
|
||||
kind: Direct,
|
||||
ty: ty,
|
||||
cast: cast,
|
||||
pad: pad,
|
||||
attr: attr
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indirect(ty: Type, attr: option::Option<Attribute>) -> ArgType {
|
||||
ArgType {
|
||||
kind: Indirect,
|
||||
ty: ty,
|
||||
cast: option::None,
|
||||
pad: option::None,
|
||||
attr: attr
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_direct(&self) -> bool {
|
||||
return self.kind == Direct;
|
||||
}
|
||||
|
||||
pub fn is_indirect(&self) -> bool {
|
||||
return self.kind == Indirect;
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata describing how the arguments to a native function
|
||||
@ -30,22 +82,11 @@ pub struct LLVMType {
|
||||
/// I will do my best to describe this structure, but these
|
||||
/// comments are reverse-engineered and may be inaccurate. -NDM
|
||||
pub struct FnType {
|
||||
/// The LLVM types of each argument. If the cast flag is true,
|
||||
/// then the argument should be cast, typically because the
|
||||
/// official argument type will be an int and the rust type is i8
|
||||
/// or something like that.
|
||||
arg_tys: ~[LLVMType],
|
||||
|
||||
/// A list of attributes to be attached to each argument (parallel
|
||||
/// the `arg_tys` array). If the attribute for a given is Some,
|
||||
/// then the argument should be passed by reference.
|
||||
attrs: ~[option::Option<Attribute>],
|
||||
/// The LLVM types of each argument.
|
||||
arg_tys: ~[ArgType],
|
||||
|
||||
/// LLVM return type.
|
||||
ret_ty: LLVMType,
|
||||
|
||||
/// If true, then an implicit pointer should be added for the result.
|
||||
sret: bool
|
||||
ret_ty: ArgType,
|
||||
}
|
||||
|
||||
pub fn compute_abi_info(ccx: &mut CrateContext,
|
||||
|
@ -11,14 +11,14 @@
|
||||
#[allow(non_uppercase_pattern_statics)];
|
||||
|
||||
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
|
||||
use lib::llvm::{Attribute, StructRetAttribute};
|
||||
use middle::trans::cabi::{FnType, LLVMType};
|
||||
use lib::llvm::StructRetAttribute;
|
||||
use middle::trans::cabi::{FnType, ArgType};
|
||||
use middle::trans::context::CrateContext;
|
||||
|
||||
use middle::trans::type_::Type;
|
||||
|
||||
use std::num;
|
||||
use std::option::{Option, None, Some};
|
||||
use std::option::{None, Some};
|
||||
|
||||
fn align_up_to(off: uint, a: uint) -> uint {
|
||||
return (off + a - 1u) / a * a;
|
||||
@ -85,9 +85,9 @@ fn ty_size(ty: Type) -> uint {
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_ret_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
|
||||
fn classify_ret_ty(ty: Type) -> ArgType {
|
||||
if is_reg_ty(ty) {
|
||||
return (LLVMType { cast: false, ty: ty }, None);
|
||||
return ArgType::direct(ty, None, None, None);
|
||||
}
|
||||
let size = ty_size(ty);
|
||||
if size <= 4 {
|
||||
@ -98,14 +98,14 @@ fn classify_ret_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
|
||||
} else {
|
||||
Type::i32()
|
||||
};
|
||||
return (LLVMType { cast: true, ty: llty }, None);
|
||||
return ArgType::direct(ty, Some(llty), None, None);
|
||||
}
|
||||
(LLVMType { cast: false, ty: ty.ptr_to() }, Some(StructRetAttribute))
|
||||
ArgType::indirect(ty, Some(StructRetAttribute))
|
||||
}
|
||||
|
||||
fn classify_arg_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
|
||||
fn classify_arg_ty(ty: Type) -> ArgType {
|
||||
if is_reg_ty(ty) {
|
||||
return (LLVMType { cast: false, ty: ty }, None);
|
||||
return ArgType::direct(ty, None, None, None);
|
||||
}
|
||||
let align = ty_align(ty);
|
||||
let size = ty_size(ty);
|
||||
@ -114,7 +114,7 @@ fn classify_arg_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
|
||||
} else {
|
||||
Type::array(&Type::i64(), ((size + 7) / 8) as u64)
|
||||
};
|
||||
(LLVMType { cast: true, ty: llty }, None)
|
||||
ArgType::direct(ty, Some(llty), None, None)
|
||||
}
|
||||
|
||||
fn is_reg_ty(ty: Type) -> bool {
|
||||
@ -132,32 +132,19 @@ pub fn compute_abi_info(_ccx: &mut CrateContext,
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
let mut arg_tys = ~[];
|
||||
let mut attrs = ~[];
|
||||
for &aty in atys.iter() {
|
||||
let (ty, attr) = classify_arg_ty(aty);
|
||||
let ty = classify_arg_ty(aty);
|
||||
arg_tys.push(ty);
|
||||
attrs.push(attr);
|
||||
}
|
||||
|
||||
let (ret_ty, ret_attr) = if ret_def {
|
||||
let ret_ty = if ret_def {
|
||||
classify_ret_ty(rty)
|
||||
} else {
|
||||
(LLVMType { cast: false, ty: Type::void() }, None)
|
||||
ArgType::direct(Type::void(), None, None, None)
|
||||
};
|
||||
|
||||
let mut ret_ty = ret_ty;
|
||||
|
||||
let sret = ret_attr.is_some();
|
||||
if sret {
|
||||
arg_tys.unshift(ret_ty);
|
||||
attrs.unshift(ret_attr);
|
||||
ret_ty = LLVMType { cast: false, ty: Type::void() };
|
||||
}
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
attrs: attrs,
|
||||
sret: sret
|
||||
};
|
||||
}
|
||||
|
@ -12,9 +12,8 @@
|
||||
|
||||
use std::libc::c_uint;
|
||||
use std::num;
|
||||
use std::vec;
|
||||
use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array};
|
||||
use lib::llvm::{Attribute, StructRetAttribute};
|
||||
use lib::llvm::StructRetAttribute;
|
||||
use middle::trans::context::CrateContext;
|
||||
use middle::trans::context::task_llcx;
|
||||
use middle::trans::cabi::*;
|
||||
@ -86,15 +85,15 @@ fn ty_size(ty: Type) -> uint {
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_ret_ty(ty: Type) -> (LLVMType, Option<Attribute>) {
|
||||
return if is_reg_ty(ty) {
|
||||
(LLVMType { cast: false, ty: ty }, None)
|
||||
fn classify_ret_ty(ty: Type) -> ArgType {
|
||||
if is_reg_ty(ty) {
|
||||
ArgType::direct(ty, None, None, None)
|
||||
} else {
|
||||
(LLVMType { cast: false, ty: ty.ptr_to() }, Some(StructRetAttribute))
|
||||
};
|
||||
ArgType::indirect(ty, Some(StructRetAttribute))
|
||||
}
|
||||
}
|
||||
|
||||
fn classify_arg_ty(ty: Type, offset: &mut uint) -> (LLVMType, Option<Attribute>) {
|
||||
fn classify_arg_ty(ty: Type, offset: &mut uint) -> ArgType {
|
||||
let orig_offset = *offset;
|
||||
let size = ty_size(ty) * 8;
|
||||
let mut align = ty_align(ty);
|
||||
@ -103,20 +102,16 @@ fn classify_arg_ty(ty: Type, offset: &mut uint) -> (LLVMType, Option<Attribute>)
|
||||
*offset = align_up_to(*offset, align);
|
||||
*offset += align_up_to(size, align * 8) / 8;
|
||||
|
||||
let padding = padding_ty(align, orig_offset);
|
||||
return if !is_reg_ty(ty) {
|
||||
(LLVMType {
|
||||
cast: true,
|
||||
ty: struct_ty(ty, padding, true)
|
||||
}, None)
|
||||
} else if padding.is_some() {
|
||||
(LLVMType {
|
||||
cast: true,
|
||||
ty: struct_ty(ty, padding, false)
|
||||
}, None)
|
||||
if is_reg_ty(ty) {
|
||||
ArgType::direct(ty, None, None, None)
|
||||
} else {
|
||||
(LLVMType { cast: false, ty: ty }, None)
|
||||
};
|
||||
ArgType::direct(
|
||||
ty,
|
||||
Some(struct_ty(ty)),
|
||||
padding_ty(align, orig_offset),
|
||||
None
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_reg_ty(ty: Type) -> bool {
|
||||
@ -157,18 +152,9 @@ fn coerce_to_int(size: uint) -> ~[Type] {
|
||||
args
|
||||
}
|
||||
|
||||
fn struct_ty(ty: Type,
|
||||
padding: Option<Type>,
|
||||
coerce: bool) -> Type {
|
||||
fn struct_ty(ty: Type) -> Type {
|
||||
let size = ty_size(ty) * 8;
|
||||
let mut fields = padding.map_default(~[], |p| ~[p]);
|
||||
|
||||
if coerce {
|
||||
fields = vec::append(fields, coerce_to_int(size));
|
||||
} else {
|
||||
fields.push(ty);
|
||||
}
|
||||
|
||||
let fields = coerce_to_int(size);
|
||||
return Type::struct_(fields, false);
|
||||
}
|
||||
|
||||
@ -176,35 +162,23 @@ pub fn compute_abi_info(_ccx: &mut CrateContext,
|
||||
atys: &[Type],
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
let (ret_ty, ret_attr) = if ret_def {
|
||||
let ret_ty = if ret_def {
|
||||
classify_ret_ty(rty)
|
||||
} else {
|
||||
(LLVMType { cast: false, ty: Type::void() }, None)
|
||||
ArgType::direct(Type::void(), None, None, None)
|
||||
};
|
||||
|
||||
let mut ret_ty = ret_ty;
|
||||
|
||||
let sret = ret_attr.is_some();
|
||||
let sret = ret_ty.is_indirect();
|
||||
let mut arg_tys = ~[];
|
||||
let mut attrs = ~[];
|
||||
let mut offset = if sret { 4 } else { 0 };
|
||||
|
||||
for aty in atys.iter() {
|
||||
let (ty, attr) = classify_arg_ty(*aty, &mut offset);
|
||||
let ty = classify_arg_ty(*aty, &mut offset);
|
||||
arg_tys.push(ty);
|
||||
attrs.push(attr);
|
||||
};
|
||||
|
||||
if sret {
|
||||
arg_tys = vec::append(~[ret_ty], arg_tys);
|
||||
attrs = vec::append(~[ret_attr], attrs);
|
||||
ret_ty = LLVMType { cast: false, ty: Type::void() };
|
||||
}
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
attrs: attrs,
|
||||
sret: sret
|
||||
};
|
||||
}
|
||||
|
@ -21,16 +21,10 @@ pub fn compute_abi_info(ccx: &mut CrateContext,
|
||||
rty: Type,
|
||||
ret_def: bool) -> FnType {
|
||||
let mut arg_tys = ~[];
|
||||
let mut attrs = ~[];
|
||||
|
||||
let ret_ty;
|
||||
let sret;
|
||||
if !ret_def {
|
||||
ret_ty = LLVMType {
|
||||
cast: false,
|
||||
ty: Type::void(),
|
||||
};
|
||||
sret = false;
|
||||
ret_ty = ArgType::direct(Type::void(), None, None, None);
|
||||
} else if rty.kind() == Struct {
|
||||
// Returning a structure. Most often, this will use
|
||||
// a hidden first argument. On some platforms, though,
|
||||
@ -58,43 +52,22 @@ pub fn compute_abi_info(ccx: &mut CrateContext,
|
||||
|
||||
match strategy {
|
||||
RetValue(t) => {
|
||||
ret_ty = LLVMType {
|
||||
cast: true,
|
||||
ty: t
|
||||
};
|
||||
sret = false;
|
||||
ret_ty = ArgType::direct(rty, Some(t), None, None);
|
||||
}
|
||||
RetPointer => {
|
||||
arg_tys.push(LLVMType {
|
||||
cast: false,
|
||||
ty: rty.ptr_to()
|
||||
});
|
||||
attrs.push(Some(StructRetAttribute));
|
||||
|
||||
ret_ty = LLVMType {
|
||||
cast: false,
|
||||
ty: Type::void(),
|
||||
};
|
||||
sret = true;
|
||||
ret_ty = ArgType::indirect(rty, Some(StructRetAttribute));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret_ty = LLVMType {
|
||||
cast: false,
|
||||
ty: rty
|
||||
};
|
||||
sret = false;
|
||||
ret_ty = ArgType::direct(rty, None, None, None);
|
||||
}
|
||||
|
||||
for &a in atys.iter() {
|
||||
arg_tys.push(LLVMType { cast: false, ty: a });
|
||||
attrs.push(None);
|
||||
arg_tys.push(ArgType::direct(a, None, None, None));
|
||||
}
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
attrs: attrs,
|
||||
sret: sret
|
||||
};
|
||||
}
|
||||
|
@ -22,8 +22,6 @@ use middle::trans::context::CrateContext;
|
||||
use middle::trans::type_::Type;
|
||||
|
||||
use std::num;
|
||||
use std::option;
|
||||
use std::option::Option;
|
||||
use std::vec;
|
||||
|
||||
#[deriving(Clone, Eq)]
|
||||
@ -340,50 +338,34 @@ pub fn compute_abi_info(_ccx: &mut CrateContext,
|
||||
ret_def: bool) -> FnType {
|
||||
fn x86_64_ty(ty: Type,
|
||||
is_mem_cls: &fn(cls: &[RegClass]) -> bool,
|
||||
attr: Attribute) -> (LLVMType, Option<Attribute>) {
|
||||
attr: Attribute) -> ArgType {
|
||||
|
||||
let (cast, attr, ty) = if !ty.is_reg_ty() {
|
||||
if !ty.is_reg_ty() {
|
||||
let cls = classify_ty(ty);
|
||||
if is_mem_cls(cls) {
|
||||
(false, option::Some(attr), ty.ptr_to())
|
||||
ArgType::indirect(ty, Some(attr))
|
||||
} else {
|
||||
(true, option::None, llreg_ty(cls))
|
||||
ArgType::direct(ty, Some(llreg_ty(cls)), None, None)
|
||||
}
|
||||
} else {
|
||||
(false, option::None, ty)
|
||||
};
|
||||
|
||||
(LLVMType { cast: cast, ty: ty }, attr)
|
||||
ArgType::direct(ty, None, None, None)
|
||||
}
|
||||
}
|
||||
|
||||
let mut arg_tys = ~[];
|
||||
let mut attrs = ~[];
|
||||
for t in atys.iter() {
|
||||
let (ty, attr) = x86_64_ty(*t, |cls| cls.is_pass_byval(), ByValAttribute);
|
||||
let ty = x86_64_ty(*t, |cls| cls.is_pass_byval(), ByValAttribute);
|
||||
arg_tys.push(ty);
|
||||
attrs.push(attr);
|
||||
}
|
||||
let (ret_ty, ret_attr) = x86_64_ty(rty, |cls| cls.is_ret_bysret(),
|
||||
StructRetAttribute);
|
||||
let mut ret_ty = ret_ty;
|
||||
let sret = ret_attr.is_some();
|
||||
if sret {
|
||||
arg_tys = vec::append(~[ret_ty], arg_tys);
|
||||
ret_ty = LLVMType {
|
||||
cast: false,
|
||||
ty: Type::void()
|
||||
};
|
||||
attrs = vec::append(~[ret_attr], attrs);
|
||||
} else if !ret_def {
|
||||
ret_ty = LLVMType {
|
||||
cast: false,
|
||||
ty: Type::void()
|
||||
};
|
||||
}
|
||||
|
||||
let ret_ty = if ret_def {
|
||||
x86_64_ty(rty, |cls| cls.is_ret_bysret(), StructRetAttribute)
|
||||
} else {
|
||||
ArgType::direct(Type::void(), None, None, None)
|
||||
};
|
||||
|
||||
return FnType {
|
||||
arg_tys: arg_tys,
|
||||
ret_ty: ret_ty,
|
||||
attrs: attrs,
|
||||
sret: sret
|
||||
};
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
use back::{link};
|
||||
use std::libc::c_uint;
|
||||
use lib::llvm::{ValueRef, Attribute, CallConv, StructRetAttribute};
|
||||
use lib::llvm::{ValueRef, CallConv, StructRetAttribute};
|
||||
use lib::llvm::llvm;
|
||||
use lib;
|
||||
use middle::trans::machine;
|
||||
@ -183,8 +183,7 @@ pub fn trans_native_call(bcx: @mut Block,
|
||||
llsig.llret_ty,
|
||||
ret_def);
|
||||
|
||||
let all_arg_tys: &[cabi::LLVMType] = fn_type.arg_tys;
|
||||
let all_attributes: &[Option<Attribute>] = fn_type.attrs;
|
||||
let arg_tys: &[cabi::ArgType] = fn_type.arg_tys;
|
||||
|
||||
let mut llargs_foreign = ~[];
|
||||
|
||||
@ -192,20 +191,18 @@ pub fn trans_native_call(bcx: @mut Block,
|
||||
// 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}).
|
||||
let (arg_tys, attributes) = {
|
||||
if fn_type.sret {
|
||||
if all_arg_tys[0].cast {
|
||||
if fn_type.ret_ty.is_indirect() {
|
||||
match fn_type.ret_ty.cast {
|
||||
Some(ty) => {
|
||||
let llcastedretptr =
|
||||
BitCast(bcx, llretptr, all_arg_tys[0].ty.ptr_to());
|
||||
BitCast(bcx, llretptr, ty.ptr_to());
|
||||
llargs_foreign.push(llcastedretptr);
|
||||
} else {
|
||||
}
|
||||
None => {
|
||||
llargs_foreign.push(llretptr);
|
||||
}
|
||||
(all_arg_tys.tail(), all_attributes.tail())
|
||||
} else {
|
||||
(all_arg_tys, all_attributes)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
|
||||
let mut llarg_rust = llarg_rust;
|
||||
@ -231,16 +228,16 @@ pub fn trans_native_call(bcx: @mut Block,
|
||||
ccx.tn.val_to_str(llarg_rust));
|
||||
|
||||
// Check whether we need to do any casting
|
||||
let foreignarg_ty = arg_tys[i].ty;
|
||||
if arg_tys[i].cast {
|
||||
llarg_rust = BitCast(bcx, llarg_rust, foreignarg_ty.ptr_to());
|
||||
match arg_tys[i].cast {
|
||||
Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
|
||||
None => ()
|
||||
}
|
||||
|
||||
debug2!("llarg_rust={} (after casting)",
|
||||
ccx.tn.val_to_str(llarg_rust));
|
||||
|
||||
// Finally, load the value if needed for the foreign ABI
|
||||
let foreign_indirect = attributes[i].is_some();
|
||||
let foreign_indirect = arg_tys[i].is_indirect();
|
||||
let llarg_foreign = if foreign_indirect {
|
||||
llarg_rust
|
||||
} else {
|
||||
@ -250,6 +247,11 @@ pub fn trans_native_call(bcx: @mut Block,
|
||||
debug2!("argument {}, llarg_foreign={}",
|
||||
i, ccx.tn.val_to_str(llarg_foreign));
|
||||
|
||||
// fill padding with undef value
|
||||
match arg_tys[i].pad {
|
||||
Some(ty) => llargs_foreign.push(C_undef(ty)),
|
||||
None => ()
|
||||
}
|
||||
llargs_foreign.push(llarg_foreign);
|
||||
}
|
||||
|
||||
@ -268,7 +270,7 @@ pub fn trans_native_call(bcx: @mut Block,
|
||||
// any attributes with ABI implications directly to the call instruction. Right now, the
|
||||
// only attribute we need to worry about is `sret`.
|
||||
let attrs;
|
||||
if fn_type.sret {
|
||||
if fn_type.ret_ty.is_indirect() {
|
||||
attrs = &[(1, StructRetAttribute)];
|
||||
} else {
|
||||
attrs = &[];
|
||||
@ -280,9 +282,12 @@ pub fn trans_native_call(bcx: @mut Block,
|
||||
// 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 ret_def && !fn_type.sret {
|
||||
if ret_def && !fn_type.ret_ty.is_indirect() {
|
||||
let llrust_ret_ty = llsig.llret_ty;
|
||||
let llforeign_ret_ty = fn_type.ret_ty.ty;
|
||||
let llforeign_ret_ty = match fn_type.ret_ty.cast {
|
||||
Some(ty) => ty,
|
||||
None => fn_type.ret_ty.ty
|
||||
};
|
||||
|
||||
debug2!("llretptr={}", ccx.tn.val_to_str(llretptr));
|
||||
debug2!("llforeign_retval={}", ccx.tn.val_to_str(llforeign_retval));
|
||||
@ -474,17 +479,17 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
|
||||
// Array for the arguments we will pass to the rust function.
|
||||
let mut llrust_args = ~[];
|
||||
let mut next_foreign_arg_counter: c_uint = 0;
|
||||
let next_foreign_arg: &fn() -> c_uint = {
|
||||
|| {
|
||||
next_foreign_arg_counter += 1;
|
||||
let next_foreign_arg: &fn(pad: bool) -> c_uint = {
|
||||
|pad: bool| {
|
||||
next_foreign_arg_counter += if pad { 2 } else { 1 };
|
||||
next_foreign_arg_counter - 1
|
||||
}
|
||||
};
|
||||
|
||||
// If there is an out pointer on the foreign function
|
||||
let foreign_outptr = {
|
||||
if tys.fn_ty.sret {
|
||||
Some(llvm::LLVMGetParam(llwrapfn, next_foreign_arg()))
|
||||
if tys.fn_ty.ret_ty.is_indirect() {
|
||||
Some(llvm::LLVMGetParam(llwrapfn, next_foreign_arg(false)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -553,9 +558,12 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
|
||||
for i in range(0, tys.fn_sig.inputs.len()) {
|
||||
let rust_ty = tys.fn_sig.inputs[i];
|
||||
let llrust_ty = tys.llsig.llarg_tys[i];
|
||||
let foreign_index = next_foreign_arg();
|
||||
let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
|
||||
let foreign_indirect = tys.fn_ty.attrs[foreign_index].is_some();
|
||||
let llforeign_arg_ty = tys.fn_ty.arg_tys[i];
|
||||
let foreign_indirect = llforeign_arg_ty.is_indirect();
|
||||
|
||||
// skip padding
|
||||
let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
|
||||
let mut llforeign_arg = llvm::LLVMGetParam(llwrapfn, foreign_index);
|
||||
|
||||
debug2!("llforeign_arg \\#{}: {}",
|
||||
@ -578,7 +586,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
|
||||
// If the types in the ABI and the Rust types don't match,
|
||||
// bitcast the llforeign_arg pointer so it matches the types
|
||||
// Rust expects.
|
||||
if tys.fn_ty.arg_tys[foreign_index].cast {
|
||||
if llforeign_arg_ty.cast.is_some() {
|
||||
assert!(!foreign_indirect);
|
||||
llforeign_arg = llvm::LLVMBuildBitCast(
|
||||
builder, llforeign_arg,
|
||||
@ -604,7 +612,10 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
|
||||
};
|
||||
|
||||
// Get the return value where the foreign fn expects it.
|
||||
let llforeign_ret_ty = tys.fn_ty.ret_ty.ty;
|
||||
let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
|
||||
Some(ty) => ty,
|
||||
None => tys.fn_ty.ret_ty.ty
|
||||
};
|
||||
match foreign_outptr {
|
||||
None if !tys.ret_def => {
|
||||
// Function returns `()` or `bot`, which in Rust is the LLVM
|
||||
@ -744,9 +755,38 @@ fn foreign_types_for_fn_ty(ccx: &mut CrateContext,
|
||||
}
|
||||
|
||||
fn lltype_for_fn_from_foreign_types(tys: &ForeignTypes) -> Type {
|
||||
let llargument_tys: ~[Type] =
|
||||
tys.fn_ty.arg_tys.iter().map(|t| t.ty).collect();
|
||||
let llreturn_ty = tys.fn_ty.ret_ty.ty;
|
||||
let mut llargument_tys = ~[];
|
||||
|
||||
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()
|
||||
} else {
|
||||
match ret_ty.cast {
|
||||
Some(ty) => ty,
|
||||
None => ret_ty.ty
|
||||
}
|
||||
};
|
||||
|
||||
for &arg_ty in tys.fn_ty.arg_tys.iter() {
|
||||
// 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);
|
||||
}
|
||||
|
||||
Type::func(llargument_tys, &llreturn_ty)
|
||||
}
|
||||
|
||||
@ -757,8 +797,27 @@ pub fn lltype_for_foreign_fn(ccx: &mut CrateContext, ty: ty::t) -> Type {
|
||||
|
||||
fn add_argument_attributes(tys: &ForeignTypes,
|
||||
llfn: ValueRef) {
|
||||
for (i, a) in tys.fn_ty.attrs.iter().enumerate() {
|
||||
match *a {
|
||||
let mut i = 0;
|
||||
|
||||
if tys.fn_ty.ret_ty.is_indirect() {
|
||||
match tys.fn_ty.ret_ty.attr {
|
||||
Some(attr) => {
|
||||
let llarg = get_param(llfn, i);
|
||||
unsafe {
|
||||
llvm::LLVMAddAttribute(llarg, attr as c_uint);
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
for &arg_ty in tys.fn_ty.arg_tys.iter() {
|
||||
// skip padding
|
||||
if arg_ty.pad.is_some() { i += 1; }
|
||||
|
||||
match arg_ty.attr {
|
||||
Some(attr) => {
|
||||
let llarg = get_param(llfn, i);
|
||||
unsafe {
|
||||
@ -767,5 +826,7 @@ fn add_argument_attributes(tys: &ForeignTypes,
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user