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)]
|
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub struct ArgDecl<'tcx> {
|
pub struct ArgDecl<'tcx> {
|
||||||
pub ty: Ty<'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,
|
pattern,
|
||||||
&lvalue));
|
&lvalue));
|
||||||
}
|
}
|
||||||
ArgDecl { ty: ty }
|
ArgDecl { ty: ty, spread: false }
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ use rustc::util::common::ErrorReported;
|
||||||
use rustc::util::nodemap::NodeMap;
|
use rustc::util::nodemap::NodeMap;
|
||||||
use rustc_front::hir;
|
use rustc_front::hir;
|
||||||
use rustc_front::intravisit::{self, Visitor};
|
use rustc_front::intravisit::{self, Visitor};
|
||||||
|
use syntax::abi::Abi;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::attr::AttrMetaMethods;
|
use syntax::attr::AttrMetaMethods;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
|
@ -181,13 +182,20 @@ fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
|
||||||
let parameter_scope =
|
let parameter_scope =
|
||||||
cx.tcx().region_maps.lookup_code_extent(
|
cx.tcx().region_maps.lookup_code_extent(
|
||||||
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
|
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
|
||||||
Ok(build::construct(cx,
|
let mut mir = build::construct(cx, span, implicit_arg_tys, arguments,
|
||||||
span,
|
parameter_scope, fn_sig.output, body);
|
||||||
implicit_arg_tys,
|
|
||||||
arguments,
|
match cx.tcx().node_id_to_type(fn_id).sty {
|
||||||
parameter_scope,
|
ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
|
||||||
fn_sig.output,
|
// RustCall pseudo-ABI untuples the last argument.
|
||||||
body))
|
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>,
|
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>,
|
fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||||
mir: &mir::Mir<'tcx>)
|
mir: &mir::Mir<'tcx>)
|
||||||
-> Vec<LvalueRef<'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 fcx = bcx.fcx();
|
||||||
let tcx = bcx.tcx();
|
let tcx = bcx.tcx();
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
|
let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
|
||||||
mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| {
|
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];
|
let arg = &fcx.fn_ty.args[idx];
|
||||||
idx += 1;
|
idx += 1;
|
||||||
let arg_ty = bcx.monomorphize(&arg_decl.ty);
|
|
||||||
let llval = if arg.is_indirect() {
|
let llval = if arg.is_indirect() {
|
||||||
// Don't copy an indirect argument to an alloca, the caller
|
// Don't copy an indirect argument to an alloca, the caller
|
||||||
// already put it in a temporary alloca and gave it up, unless
|
// already put it in a temporary alloca and gave it up, unless
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue