diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 518a6251702..74ed9f16a6f 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -161,7 +161,7 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str, let llmod = time(time_passes, "translation", bind trans::trans_crate(sess, crate, ty_cx, output, ast_map, - mut_map, copy_map)); + mut_map, copy_map, last_uses)); time(time_passes, "LLVM passes", bind link::write::run_passes(sess, llmod, output)); } 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)