mir: Support RustCall ABI functions.
This commit is contained in:
parent
92e485874e
commit
b63a5eed6e
4 changed files with 54 additions and 10 deletions
|
@ -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
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -149,7 +149,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
pattern,
|
||||
&lvalue));
|
||||
}
|
||||
ArgDecl { ty: ty }
|
||||
ArgDecl { ty: ty, spread: false }
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue