]> git.lizzy.rs Git - rust.git/commitdiff
mir: Support RustCall ABI functions.
authorEduard Burtescu <edy.burt@gmail.com>
Tue, 8 Mar 2016 12:24:44 +0000 (14:24 +0200)
committerEduard Burtescu <edy.burt@gmail.com>
Thu, 17 Mar 2016 19:51:53 +0000 (21:51 +0200)
src/librustc/mir/repr.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/mir_map.rs
src/librustc_trans/trans/mir/mod.rs

index fe86e3b1ed69d8b7d9dbdfdeff25ed0c839553cd..84187d941a6b08b9722405a9e442ce5184875ba0 100644 (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
 }
 
 ///////////////////////////////////////////////////////////////////////////
index 5d9f827984e0e116e45a1039d2fd653412f6c3a6..7fd959390de374c635cc95081a133149d0902e66 100644 (file)
@@ -149,7 +149,7 @@ fn args_and_body(&mut self,
                                                                  pattern,
                                                                  &lvalue));
                     }
-                    ArgDecl { ty: ty }
+                    ArgDecl { ty: ty, spread: false }
                 })
                 .collect();
 
index 13521de78af28edd54fe9ca4440d04740887c7ce..4717c54ca649161e6b692c2031761110c778459c 100644 (file)
@@ -33,6 +33,7 @@
 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>,
index dac9310c8b9e1eefd0b623cc725ad46de7c87af4..c9269e9f793fefa6d62718e12a625bc6fa34f9e8 100644 (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