1
Fork 0

mir: Support RustCall ABI functions.

This commit is contained in:
Eduard Burtescu 2016-03-08 14:24:44 +02:00
parent 92e485874e
commit b63a5eed6e
4 changed files with 54 additions and 10 deletions

View file

@ -178,6 +178,10 @@ pub struct TempDecl<'tcx> {
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ArgDecl<'tcx> {
pub ty: Ty<'tcx>,
/// If true, this argument is a tuple after monomorphization,
/// and has to be collected from multiple actual arguments.
pub spread: bool
}
///////////////////////////////////////////////////////////////////////////

View file

@ -149,7 +149,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
pattern,
&lvalue));
}
ArgDecl { ty: ty }
ArgDecl { ty: ty, spread: false }
})
.collect();

View file

@ -33,6 +33,7 @@ use rustc::util::common::ErrorReported;
use rustc::util::nodemap::NodeMap;
use rustc_front::hir;
use rustc_front::intravisit::{self, Visitor};
use syntax::abi::Abi;
use syntax::ast;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
@ -181,13 +182,20 @@ fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
let parameter_scope =
cx.tcx().region_maps.lookup_code_extent(
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
Ok(build::construct(cx,
span,
implicit_arg_tys,
arguments,
parameter_scope,
fn_sig.output,
body))
let mut mir = build::construct(cx, span, implicit_arg_tys, arguments,
parameter_scope, fn_sig.output, body);
match cx.tcx().node_id_to_type(fn_id).sty {
ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
// RustCall pseudo-ABI untuples the last argument.
if let Some(arg_decl) = mir.arg_decls.last_mut() {
arg_decl.spread = true;
}
}
_ => {}
}
Ok(mir)
}
fn closure_self_ty<'a, 'tcx>(tcx: &TyCtxt<'tcx>,

View file

@ -147,15 +147,47 @@ pub fn trans_mir<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
mir: &mir::Mir<'tcx>)
-> Vec<LvalueRef<'tcx>> {
// FIXME tupled_args? I think I'd rather that mapping is done in MIR land though
let fcx = bcx.fcx();
let tcx = bcx.tcx();
let mut idx = 0;
let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| {
let arg_ty = bcx.monomorphize(&arg_decl.ty);
if arg_decl.spread {
// This argument (e.g. the last argument in the "rust-call" ABI)
// is a tuple that was spread at the ABI level and now we have
// to reconstruct it into a tuple local variable, from multiple
// individual LLVM function arguments.
let tupled_arg_tys = match arg_ty.sty {
ty::TyTuple(ref tys) => tys,
_ => unreachable!("spread argument isn't a tuple?!")
};
let llval = bcx.with_block(|bcx| {
let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index));
for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
let dst = build::StructGEP(bcx, lltemp, i);
let arg = &fcx.fn_ty.args[idx];
idx += 1;
if common::type_is_fat_ptr(tcx, tupled_arg_ty) {
// We pass fat pointers as two words, but inside the tuple
// they are the two sub-fields of a single aggregate field.
let meta = &fcx.fn_ty.args[idx];
idx += 1;
arg.store_fn_arg(bcx, &mut llarg_idx, expr::get_dataptr(bcx, dst));
meta.store_fn_arg(bcx, &mut llarg_idx, expr::get_meta(bcx, dst));
} else {
arg.store_fn_arg(bcx, &mut llarg_idx, dst);
}
}
lltemp
});
return LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty));
}
let arg = &fcx.fn_ty.args[idx];
idx += 1;
let arg_ty = bcx.monomorphize(&arg_decl.ty);
let llval = if arg.is_indirect() {
// Don't copy an indirect argument to an alloca, the caller
// already put it in a temporary alloca and gave it up, unless