]> git.lizzy.rs Git - rust.git/commitdiff
Plumbing to omit allocas for temps when possible (currently unused)
authorNiko Matsakis <niko@alum.mit.edu>
Mon, 2 Nov 2015 14:39:59 +0000 (09:39 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 3 Nov 2015 09:35:00 +0000 (04:35 -0500)
src/librustc_trans/lib.rs
src/librustc_trans/trans/mir/lvalue.rs
src/librustc_trans/trans/mir/mod.rs
src/librustc_trans/trans/mir/rvalue.rs
src/librustc_trans/trans/mir/statement.rs

index bc5b6f6b9d7d989c99db9eafb556a6d3c28cb7da..84ce458ed14f7f4b62acfffd87453a2e12a0e0bb 100644 (file)
@@ -51,6 +51,7 @@
 extern crate libc;
 extern crate rustc;
 extern crate rustc_back;
+extern crate rustc_data_structures;
 extern crate rustc_front;
 extern crate rustc_llvm as llvm;
 extern crate rustc_mir;
index 282c6a7e6de17e797c612590341a8a4cd3c3f554..1ce7b55a9c686400d077d7eb44ecd88091212427 100644 (file)
@@ -20,7 +20,7 @@
 use trans::machine;
 use trans::tvec;
 
-use super::MirContext;
+use super::{MirContext, TempRef};
 
 #[derive(Copy, Clone)]
 pub struct LvalueRef<'tcx> {
@@ -58,7 +58,12 @@ pub fn trans_lvalue(&mut self,
         let tcx = bcx.tcx();
         match *lvalue {
             mir::Lvalue::Var(index) => self.vars[index as usize],
-            mir::Lvalue::Temp(index) => self.temps[index as usize],
+            mir::Lvalue::Temp(index) => match self.temps[index as usize] {
+                TempRef::Lvalue(lvalue) =>
+                    lvalue,
+                TempRef::Operand(..) =>
+                    tcx.sess.bug(&format!("using operand temp {:?} as lvalue", lvalue)),
+            },
             mir::Lvalue::Arg(index) => self.args[index as usize],
             mir::Lvalue::Static(_def_id) => unimplemented!(),
             mir::Lvalue::ReturnPointer => {
index 6ed839d1a442d073999d7e82512743a81e7f287a..760018b4313c817fb27ada2df9df3e5eabd23054 100644 (file)
@@ -10,9 +10,9 @@
 
 use libc::c_uint;
 use llvm::{self, ValueRef};
+use rustc_data_structures::fnv::FnvHashSet;
 use rustc_mir::repr as mir;
 use rustc_mir::tcx::LvalueTy;
-use std::cell::Cell;
 use trans::base;
 use trans::build;
 use trans::common::{self, Block};
@@ -21,6 +21,7 @@
 use trans::type_of;
 
 use self::lvalue::LvalueRef;
+use self::operand::OperandRef;
 
 // FIXME DebugLoc is always None right now
 
@@ -43,8 +44,19 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
     /// An LLVM alloca for each MIR `VarDecl`
     vars: Vec<LvalueRef<'tcx>>,
 
-    /// An LLVM alloca for each MIR `TempDecl`
-    temps: Vec<LvalueRef<'tcx>>,
+    /// The location where each MIR `TempDecl` is stored. This is
+    /// usually an `LvalueRef` representing an alloca, but not always:
+    /// sometimes we can skip the alloca and just store the value
+    /// directly using an `OperandRef`, which makes for tighter LLVM
+    /// IR. The conditions for using an `OperandRef` are as follows:
+    ///
+    /// - the type of the temporary must be judged "immediate" by `type_is_immediate`
+    /// - the operand must never be referenced indirectly
+    ///     - we should not take its address using the `&` operator
+    ///     - nor should it appear in an lvalue path like `tmp.a`
+    /// - the operand must be defined by an rvalue that can generate immediate
+    ///   values
+    temps: Vec<TempRef<'tcx>>,
 
     /// The arguments to the function; as args are lvalues, these are
     /// always indirect, though we try to avoid creating an alloca
@@ -52,6 +64,11 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
     args: Vec<LvalueRef<'tcx>>,
 }
 
+enum TempRef<'tcx> {
+    Lvalue(LvalueRef<'tcx>),
+    Operand(Option<OperandRef<'tcx>>),
+}
+
 ///////////////////////////////////////////////////////////////////////////
 
 pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
@@ -60,6 +77,10 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
 
     let mir_blocks = bcx.mir().all_basic_blocks();
 
+    // Analyze the temps to determine which must be lvalues
+    // FIXME
+    let lvalue_temps: FnvHashSet<usize> = (0..mir.temp_decls.len()).collect();
+
     // Allocate variable and temp allocas
     let vars = mir.var_decls.iter()
                             .map(|decl| (bcx.monomorphize(&decl.ty), decl.name))
@@ -68,7 +89,16 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
     let temps = mir.temp_decls.iter()
                               .map(|decl| bcx.monomorphize(&decl.ty))
                               .enumerate()
-                              .map(|(i, mty)| LvalueRef::alloca(bcx, mty, &format!("temp{:?}", i)))
+                              .map(|(i, mty)| if lvalue_temps.contains(&i) {
+                                  TempRef::Lvalue(LvalueRef::alloca(bcx,
+                                                                    mty,
+                                                                    &format!("temp{:?}", i)))
+                              } else {
+                                  // If this is an immediate temp, we do not create an
+                                  // alloca in advance. Instead we wait until we see the
+                                  // definition and update the operand there.
+                                  TempRef::Operand(None)
+                              })
                               .collect();
     let args = arg_value_refs(bcx, mir);
 
index 416aa061276fe3052ebd5f208f7438ffe3ba061e..c82726fd0e577beece9bdb860c4f015a8121a774 100644 (file)
@@ -53,12 +53,87 @@ pub fn trans_rvalue(&mut self,
                 unimplemented!()
             }
 
+            mir::Rvalue::Aggregate(_, ref operands) => {
+                for (i, operand) in operands.iter().enumerate() {
+                    let lldest_i = build::GEPi(bcx, lldest, &[0, i]);
+                    self.trans_operand_into(bcx, lldest_i, operand);
+                }
+                bcx
+            }
+
+            mir::Rvalue::Slice { ref input, from_start, from_end } => {
+                let ccx = bcx.ccx();
+                let input = self.trans_lvalue(bcx, input);
+                let (llbase, lllen) = tvec::get_base_and_len(bcx,
+                                                             input.llval,
+                                                             input.ty.to_ty(bcx.tcx()));
+                let llbase1 = build::GEPi(bcx, llbase, &[from_start]);
+                let adj = common::C_uint(ccx, from_start + from_end);
+                let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None);
+                build::Store(bcx, llbase1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR]));
+                build::Store(bcx, lllen1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA]));
+                bcx
+            }
+
+            mir::Rvalue::InlineAsm(inline_asm) => {
+                asm::trans_inline_asm(bcx, inline_asm)
+            }
+
+            _ => {
+                assert!(self.rvalue_creates_operand(rvalue));
+                let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
+                build::Store(bcx, temp.llval, lldest);
+                bcx
+            }
+        }
+    }
+
+    pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool {
+        match *rvalue {
+            mir::Rvalue::Use(..) | // (*)
+            mir::Rvalue::Ref(..) |
+            mir::Rvalue::Len(..) |
+            mir::Rvalue::Cast(..) | // (*)
+            mir::Rvalue::BinaryOp(..) |
+            mir::Rvalue::UnaryOp(..) |
+            mir::Rvalue::Box(..) =>
+                true,
+            mir::Rvalue::Repeat(..) |
+            mir::Rvalue::Aggregate(..) |
+            mir::Rvalue::Slice { .. } |
+            mir::Rvalue::InlineAsm(..) =>
+                false,
+        }
+
+        // (*) this is only true if the type is suitable
+    }
+
+    pub fn trans_rvalue_operand(&mut self,
+                                bcx: Block<'bcx, 'tcx>,
+                                rvalue: &mir::Rvalue<'tcx>)
+                                -> (Block<'bcx, 'tcx>, OperandRef<'tcx>)
+    {
+        assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
+
+        match *rvalue {
+            mir::Rvalue::Use(ref operand) => {
+                let operand = self.trans_operand(bcx, operand);
+                (bcx, operand)
+            }
+
+            mir::Rvalue::Cast(..) => {
+                unimplemented!()
+            }
+
             mir::Rvalue::Ref(_, _, ref lvalue) => {
                 let tr_lvalue = self.trans_lvalue(bcx, lvalue);
+
                 // Note: lvalues are indirect, so storing the `llval` into the
                 // destination effectively creates a reference.
-                build::Store(bcx, tr_lvalue.llval, lldest);
-                bcx
+                (bcx, OperandRef {
+                    llval: tr_lvalue.llval,
+                    ty: tr_lvalue.ty.to_ty(bcx.tcx()),
+                })
             }
 
             mir::Rvalue::Len(ref lvalue) => {
@@ -66,8 +141,10 @@ pub fn trans_rvalue(&mut self,
                 let (_, lllen) = tvec::get_base_and_len(bcx,
                                                         tr_lvalue.llval,
                                                         tr_lvalue.ty.to_ty(bcx.tcx()));
-                build::Store(bcx, lllen, lldest);
-                bcx
+                (bcx, OperandRef {
+                    llval: lllen,
+                    ty: bcx.tcx().types.usize,
+                })
             }
 
             mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
@@ -170,8 +247,10 @@ pub fn trans_rvalue(&mut self,
                     mir::BinOp::Gt => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty,
                                                                  hir::BiGt, binop_debug_loc),
                 };
-                build::Store(bcx, llval, lldest);
-                bcx
+                (bcx, OperandRef {
+                    llval: llval,
+                    ty: lhs.ty,
+                })
             }
 
             mir::Rvalue::UnaryOp(op, ref operand) => {
@@ -186,12 +265,14 @@ pub fn trans_rvalue(&mut self,
                         build::Neg(bcx, operand.llval, debug_loc)
                     }
                 };
-                build::Store(bcx, llval, lldest);
-                bcx
+                (bcx, OperandRef {
+                    llval: llval,
+                    ty: operand.ty,
+                })
             }
 
             mir::Rvalue::Box(content_ty) => {
-                let content_ty: Ty<'tcx> = content_ty;
+                let content_ty: Ty<'tcx> = bcx.monomorphize(&content_ty);
                 let llty = type_of::type_of(bcx.ccx(), content_ty);
                 let llsize = machine::llsize_of(bcx.ccx(), llty);
                 let align = type_of::align_of(bcx.ccx(), content_ty);
@@ -204,34 +285,17 @@ pub fn trans_rvalue(&mut self,
                                                                       llsize,
                                                                       llalign,
                                                                       DebugLoc::None);
-                build::Store(bcx, llval, lldest);
-                bcx
-            }
-
-            mir::Rvalue::Aggregate(_, ref operands) => {
-                for (i, operand) in operands.iter().enumerate() {
-                    let lldest_i = build::GEPi(bcx, lldest, &[0, i]);
-                    self.trans_operand_into(bcx, lldest_i, operand);
-                }
-                bcx
+                (bcx, OperandRef {
+                    llval: llval,
+                    ty: box_ty,
+                })
             }
 
-            mir::Rvalue::Slice { ref input, from_start, from_end } => {
-                let ccx = bcx.ccx();
-                let input = self.trans_lvalue(bcx, input);
-                let (llbase, lllen) = tvec::get_base_and_len(bcx,
-                                                             input.llval,
-                                                             input.ty.to_ty(bcx.tcx()));
-                let llbase1 = build::GEPi(bcx, llbase, &[from_start]);
-                let adj = common::C_uint(ccx, from_start + from_end);
-                let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None);
-                build::Store(bcx, llbase1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR]));
-                build::Store(bcx, lllen1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA]));
-                bcx
-            }
-
-            mir::Rvalue::InlineAsm(inline_asm) => {
-                asm::trans_inline_asm(bcx, inline_asm)
+            mir::Rvalue::Repeat(..) |
+            mir::Rvalue::Aggregate(..) |
+            mir::Rvalue::Slice { .. } |
+            mir::Rvalue::InlineAsm(..) => {
+                bcx.tcx().sess.bug(&format!("cannot generate operand from rvalue {:?}", rvalue));
             }
         }
     }
index 17a20fb817c89c28ae0f6544e8e52e501339b375..95ff049836eb43ed9de900b734f39eb35fda8e87 100644 (file)
@@ -15,6 +15,7 @@
 use trans::glue;
 
 use super::MirContext;
+use super::TempRef;
 
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     pub fn trans_statement(&mut self,
@@ -25,9 +26,30 @@ pub fn trans_statement(&mut self,
 
         match statement.kind {
             mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
-                let tr_dest = self.trans_lvalue(bcx, lvalue);
-                self.trans_rvalue(bcx, tr_dest.llval, rvalue);
-                bcx
+                match *lvalue {
+                    mir::Lvalue::Temp(index) => {
+                        let index = index as usize;
+                        match self.temps[index as usize] {
+                            TempRef::Lvalue(tr_dest) => {
+                                self.trans_rvalue(bcx, tr_dest.llval, rvalue)
+                            }
+                            TempRef::Operand(None) => {
+                                let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue);
+                                self.temps[index] = TempRef::Operand(Some(operand));
+                                bcx
+                            }
+                            TempRef::Operand(Some(_)) => {
+                                bcx.tcx().sess.span_bug(
+                                    statement.span,
+                                    &format!("operand {:?} already assigned", rvalue));
+                            }
+                        }
+                    }
+                    _ => {
+                        let tr_dest = self.trans_lvalue(bcx, lvalue);
+                        self.trans_rvalue(bcx, tr_dest.llval, rvalue)
+                    }
+                }
             }
 
             mir::StatementKind::Drop(mir::DropKind::Deep, ref lvalue) => {