trans: Pass fat pointers as two arguments even for FFI.

This commit is contained in:
Eduard Burtescu 2016-02-24 11:09:25 +02:00
parent 3342da4113
commit 200d001784
2 changed files with 68 additions and 42 deletions

View File

@ -12,7 +12,7 @@ pub use self::ArgKind::*;
use llvm::{self, AttrHelper, ValueRef};
use trans::attributes;
use trans::common::return_type_is_void;
use trans::common::{return_type_is_void, type_is_fat_ptr};
use trans::context::CrateContext;
use trans::cabi_x86;
use trans::cabi_x86_64;
@ -184,10 +184,20 @@ impl FnType {
_ => Type::void(ccx)
};
let mut args = Vec::with_capacity(sig.inputs.len() + extra_args.len());
for ty in sig.inputs.iter().chain(extra_args.iter()) {
let llty = c_type_of(ccx, ty);
if type_is_fat_ptr(ccx.tcx(), ty) {
args.extend(llty.field_types().into_iter().map(|llty| {
ArgType::direct(llty, None, None, None)
}));
} else {
args.push(ArgType::direct(llty, None, None, None));
}
}
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(),
args: args,
ret: ArgType::direct(rty, None, None, None),
variadic: sig.variadic,
cconv: cconv

View File

@ -13,7 +13,7 @@ use back::link;
use llvm::{ValueRef, get_param};
use llvm;
use middle::weak_lang_items;
use trans::abi::{self, Abi, FnType};
use trans::abi::{Abi, FnType};
use trans::attributes;
use trans::base::{llvm_linkage_by_name, push_ctxt};
use trans::base;
@ -21,11 +21,9 @@ use trans::build::*;
use trans::common::*;
use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::expr;
use trans::machine;
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of::*;
use trans::type_of;
use trans::value::Value;
use middle::infer;
@ -167,17 +165,40 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
}
let mut offset = 0;
for (i, arg_ty) in fn_type.args.iter().enumerate() {
let mut llarg_rust = llargs_rust[i + offset];
let mut i = 0;
for &passed_arg_ty in &passed_arg_tys {
let arg_ty = fn_type.args[i];
if arg_ty.is_ignore() {
i += 1;
continue;
}
if type_is_fat_ptr(ccx.tcx(), passed_arg_ty) {
// Fat pointers are one pointer and one integer or pointer.
let (a, b) = (fn_type.args[i], fn_type.args[i + 1]);
assert_eq!((a.cast, b.cast), (None, None));
assert!(!a.is_indirect() && !b.is_indirect());
if let Some(ty) = a.pad {
llargs_foreign.push(C_undef(ty));
}
llargs_foreign.push(llargs_rust[i]);
i += 1;
if let Some(ty) = b.pad {
llargs_foreign.push(C_undef(ty));
}
llargs_foreign.push(llargs_rust[i]);
i += 1;
continue;
}
// Does Rust pass this argument by pointer?
let rust_indirect = type_of::arg_is_indirect(ccx, passed_arg_tys[i]);
let rust_indirect = type_of::arg_is_indirect(ccx, passed_arg_ty);
let mut llarg_rust = llargs_rust[i];
i += 1;
debug!("argument {}, llarg_rust={:?}, rust_indirect={}, arg_ty={:?}",
i,
Value(llarg_rust),
@ -187,14 +208,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// Ensure that we always have the Rust value indirectly,
// because it makes bitcasting easier.
if !rust_indirect {
let scratch = base::alloc_ty(bcx, passed_arg_tys[i], "__arg");
if type_is_fat_ptr(ccx.tcx(), passed_arg_tys[i]) {
Store(bcx, llargs_rust[i + offset], expr::get_dataptr(bcx, scratch));
Store(bcx, llargs_rust[i + offset + 1], expr::get_meta(bcx, scratch));
offset += 1;
} else {
base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]);
}
let scratch = base::alloc_ty(bcx, passed_arg_ty, "__arg");
base::store_ty(bcx, llarg_rust, scratch, passed_arg_ty);
llarg_rust = scratch;
}
@ -202,9 +217,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Value(llarg_rust));
// Check whether we need to do any casting
match arg_ty.cast {
Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
None => ()
if let Some(ty) = arg_ty.cast {
llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to());
}
debug!("llarg_rust={:?} (after casting)",
@ -214,22 +228,19 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let foreign_indirect = arg_ty.is_indirect();
let llarg_foreign = if foreign_indirect {
llarg_rust
} else if passed_arg_ty.is_bool() {
let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, llvm::False);
Trunc(bcx, val, Type::i1(bcx.ccx()))
} else {
if passed_arg_tys[i].is_bool() {
let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, llvm::False);
Trunc(bcx, val, Type::i1(bcx.ccx()))
} else {
Load(bcx, llarg_rust)
}
Load(bcx, llarg_rust)
};
debug!("argument {}, llarg_foreign={:?}",
i, Value(llarg_foreign));
// fill padding with undef value
match arg_ty.pad {
Some(ty) => llargs_foreign.push(C_undef(ty)),
None => ()
if let Some(ty) = arg_ty.pad {
llargs_foreign.push(C_undef(ty));
}
llargs_foreign.push(llarg_foreign);
}
@ -552,16 +563,16 @@ 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.
let mut tys = fn_ty.args.iter().zip(rust_param_tys);
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 (llforeign_arg_ty, llty) = tys.next().expect("Not enough parameter types!");
let llrust_ty = if rust_indirect {
llty.element_type()
} else {
llty
};
let llforeign_arg_ty = fn_ty.args[i];
let foreign_indirect = llforeign_arg_ty.is_indirect();
if llforeign_arg_ty.is_ignore() {
@ -574,6 +585,19 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
let mut llforeign_arg = get_param(llwrapfn, foreign_index);
if type_is_fat_ptr(ccx.tcx(), rust_ty) {
// Fat pointers are one pointer and one integer or pointer.
let a = llforeign_arg_ty;
let (b, _) = tys.next().expect("Not enough parameter types!");
assert_eq!((a.cast, b.cast), (None, None));
assert!(!a.is_indirect() && !b.is_indirect());
llrust_args.push(llforeign_arg);
let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
llrust_args.push(get_param(llwrapfn, foreign_index));
continue;
}
debug!("llforeign_arg {}{}: {:?}", "#",
i, Value(llforeign_arg));
debug!("rust_indirect = {}, foreign_indirect = {}",
@ -624,15 +648,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
debug!("llrust_arg {}{}: {:?}", "#",
i, Value(llrust_arg));
if type_is_fat_ptr(ccx.tcx(), rust_ty) {
let next_llrust_ty = rust_param_tys.next().expect("Not enough parameter types!");
llrust_args.push(builder.load(builder.bitcast(builder.struct_gep(
llrust_arg, abi::FAT_PTR_ADDR), llrust_ty.ptr_to())));
llrust_args.push(builder.load(builder.bitcast(builder.struct_gep(
llrust_arg, abi::FAT_PTR_EXTRA), next_llrust_ty.ptr_to())));
} else {
llrust_args.push(llrust_arg);
}
llrust_args.push(llrust_arg);
}
// Perform the call itself