about summary refs log tree commit diff
path: root/src/comp/middle
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-11-18 15:10:14 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2011-11-18 15:56:53 +0100
commit68db68c4cccb9204e91ffcd08fd27be0f33f0033 (patch)
tree70f3b99d5ebab4e4187cbffd598e99aa034be7d0 /src/comp/middle
parentf6491bb42636f4c43f3cbb48fdb98ddd749e6e5d (diff)
downloadrust-68db68c4cccb9204e91ffcd08fd27be0f33f0033.tar.gz
rust-68db68c4cccb9204e91ffcd08fd27be0f33f0033.zip
Make trans use last_use info to not actually generate copies
Issue #925
Diffstat (limited to 'src/comp/middle')
-rw-r--r--src/comp/middle/last_use.rs8
-rw-r--r--src/comp/middle/trans.rs47
-rw-r--r--src/comp/middle/trans_common.rs16
3 files changed, 47 insertions, 24 deletions
diff --git a/src/comp/middle/last_use.rs b/src/comp/middle/last_use.rs
index 5d8aa2493d2..d4026ce8658 100644
--- a/src/comp/middle/last_use.rs
+++ b/src/comp/middle/last_use.rs
@@ -31,7 +31,13 @@ fn find_last_uses(c: @crate, def_map: resolve::def_map, tcx: ty::ctxt)
               mutable blocks: nil};
     visit::visit_crate(*c, cx, v);
     let mini_table = std::map::new_int_hash();
-    cx.last_uses.items {|key, val| if val { mini_table.insert(key, ()); }}
+    cx.last_uses.items {|key, val|
+        if val {
+            mini_table.insert(key, ());
+            let def_node = ast_util::def_id_of_def(def_map.get(key)).node;
+            mini_table.insert(def_node, ());
+        }
+    }
     ret mini_table;
 }
 
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 1f821834630..cd31617ade1 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -2099,13 +2099,15 @@ fn move_val(cx: @block_ctxt, action: copy_action, dst: ValueRef,
         Store(cx, src_val, dst);
         if src.kind == owned { ret zero_alloca(cx, src.val, t); }
         // If we're here, it must be a temporary.
-        ret revoke_clean(cx, src_val);
+        revoke_clean(cx, src_val);
+        ret cx;
     } else if type_is_structural_or_param(tcx, t) {
         if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
         cx = memmove_ty(cx, dst, src_val, t);
         if src.kind == owned { ret zero_alloca(cx, src_val, t); }
         // If we're here, it must be a temporary.
-        ret revoke_clean(cx, src_val);
+        revoke_clean(cx, src_val);
+        ret cx;
     }
     /* FIXME: suggests a type constraint */
     bcx_ccx(cx).sess.bug("unexpected type in trans::move_val: " +
@@ -2113,9 +2115,10 @@ fn move_val(cx: @block_ctxt, action: copy_action, dst: ValueRef,
 }
 
 fn store_temp_expr(cx: @block_ctxt, action: copy_action, dst: ValueRef,
-                   src: lval_result, t: ty::t) -> @block_ctxt {
+                   src: lval_result, t: ty::t, last_use: bool)
+    -> @block_ctxt {
     // Lvals in memory are not temporaries. Copy them.
-    if src.kind != temporary {
+    if src.kind != temporary && !last_use {
         let v = src.kind == owned ? load_if_immediate(cx, src.val, t)
                                   : src.val;
         ret copy_val(cx, action, dst, v, t);
@@ -3887,9 +3890,7 @@ fn zero_and_revoke(bcx: @block_ctxt,
     for {v, t} in to_zero {
         bcx = zero_alloca(bcx, v, t);
     }
-    for {v, _} in to_revoke {
-        bcx = revoke_clean(bcx, v);
-    }
+    for {v, _} in to_revoke { revoke_clean(bcx, v); }
     ret bcx;
 }
 
@@ -4246,7 +4247,8 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
         let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
         assert kind == owned;
         ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r,
-                            ty::expr_ty(bcx_tcx(bcx), src));
+                            ty::expr_ty(bcx_tcx(bcx), src),
+                            bcx_ccx(bcx).last_uses.contains_key(src.id));
       }
       ast::expr_move(dst, src) {
         // FIXME: calculate copy init-ness in typestate.
@@ -4277,25 +4279,30 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
 }
 
 fn lval_to_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
-    let lv = trans_lval(bcx, e);
+    let lv = trans_lval(bcx, e), ccx = bcx_ccx(bcx);
     let {bcx, val, kind} = lv;
-    let ty = ty::expr_ty(bcx_tcx(bcx), e);
+    let last_use = kind == owned && ccx.last_uses.contains_key(e.id);
+    let ty = ty::expr_ty(ccx.tcx, e);
     alt dest {
       by_val(cell) {
         if kind == temporary {
             revoke_clean(bcx, val);
             *cell = val;
-        } else if ty::type_is_immediate(bcx_tcx(bcx), ty) {
+        } else if last_use {
+            *cell = Load(bcx, val);
+            if ty::type_needs_drop(ccx.tcx, ty) {
+                bcx = zero_alloca(bcx, val, ty);
+            }
+        } else {
             if kind == owned { val = Load(bcx, val); }
             let {bcx: cx, val} = take_ty_immediate(bcx, val, ty);
             *cell = val;
             bcx = cx;
-        } else {
-            bcx = take_ty(bcx, val, ty);
-            *cell = Load(bcx, val);
         }
       }
-      save_in(loc) { bcx = store_temp_expr(bcx, INIT, loc, lv, ty); }
+      save_in(loc) {
+        bcx = store_temp_expr(bcx, INIT, loc, lv, ty, last_use);
+      }
       ignore. {}
     }
     ret bcx;
@@ -4807,8 +4814,10 @@ fn alloc_local(cx: @block_ctxt, local: @ast::local) -> @block_ctxt {
       ast::pat_bind(_) { true } _ { false }
     };
     // Do not allocate space for locals that can be kept immediate.
-    if is_simple && !bcx_ccx(cx).mut_map.contains_key(local.node.pat.id) &&
-        ty::type_is_immediate(bcx_tcx(cx), t) {
+    let ccx = bcx_ccx(cx);
+    if is_simple && !ccx.mut_map.contains_key(local.node.pat.id) &&
+       !ccx.last_uses.contains_key(local.node.pat.id) &&
+       ty::type_is_immediate(ccx.tcx, t) {
         alt local.node.init {
           some({op: ast::init_assign., _}) { ret cx; }
           _ {}
@@ -6027,7 +6036,8 @@ fn write_abi_version(ccx: @crate_ctxt) {
 
 fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
                output: str, amap: ast_map::map, mut_map: mut::mut_map,
-               copy_map: alias::copy_map) -> ModuleRef {
+               copy_map: alias::copy_map, last_uses: last_use::last_uses)
+    -> ModuleRef {
     let sha = std::sha1::mk_sha1();
     let link_meta = link::build_link_meta(sess, *crate, output, sha);
     let llmod = str::as_buf(link_meta.name, {|buf|
@@ -6088,6 +6098,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
           tcx: tcx,
           mut_map: mut_map,
           copy_map: copy_map,
+          last_uses: last_uses,
           stats:
               {mutable n_static_tydescs: 0u,
                mutable n_derived_tydescs: 0u,
diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs
index 36605d14cdb..55518c027e1 100644
--- a/src/comp/middle/trans_common.rs
+++ b/src/comp/middle/trans_common.rs
@@ -102,6 +102,7 @@ type crate_ctxt =
      tcx: ty::ctxt,
      mut_map: mut::mut_map,
      copy_map: alias::copy_map,
+     last_uses: last_use::last_uses,
      stats: stats,
      upcalls: @upcall::upcalls,
      rust_object_type: TypeRef,
@@ -283,7 +284,7 @@ fn add_clean_free(cx: @block_ctxt, ptr: ValueRef, shared: bool) {
 // to a system where we can also cancel the cleanup on local variables, but
 // this will be more involved. For now, we simply zero out the local, and the
 // drop glue checks whether it is zero.
-fn revoke_clean(cx: @block_ctxt, val: ValueRef) -> @block_ctxt {
+fn revoke_clean(cx: @block_ctxt, val: ValueRef) {
     let sc_cx = find_scope_cx(cx);
     let found = -1;
     let i = 0;
@@ -296,16 +297,21 @@ fn revoke_clean(cx: @block_ctxt, val: ValueRef) -> @block_ctxt {
         }
         i += 1;
     }
-    // The value does not have a cleanup associated with it. Might be a
-    // constant or some immediate value.
-    if found == -1 { ret cx; }
+    // The value does not have a cleanup associated with it. Continue to next
+    // scope.
+    if found == -1 {
+        alt sc_cx.parent {
+          parent_some(parent) { revoke_clean(parent, val); } _ {}
+        }
+        ret;
+    }
     // We found the cleanup and remove it
     sc_cx.cleanups =
         std::vec::slice(sc_cx.cleanups, 0u, found as uint) +
             std::vec::slice(sc_cx.cleanups, (found as uint) + 1u,
                             std::vec::len(sc_cx.cleanups));
     sc_cx.lpad_dirty = true;
-    ret cx;
+    ret;
 }
 
 fn get_res_dtor(ccx: @crate_ctxt, sp: span, did: ast::def_id, inner_t: ty::t)