Make trans use last_use info to not actually generate copies
Issue #925
This commit is contained in:
parent
f6491bb426
commit
68db68c4cc
4 changed files with 48 additions and 25 deletions
|
@ -161,7 +161,7 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
|
||||||
let llmod =
|
let llmod =
|
||||||
time(time_passes, "translation",
|
time(time_passes, "translation",
|
||||||
bind trans::trans_crate(sess, crate, ty_cx, output, ast_map,
|
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",
|
time(time_passes, "LLVM passes",
|
||||||
bind link::write::run_passes(sess, llmod, output));
|
bind link::write::run_passes(sess, llmod, output));
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,13 @@ fn find_last_uses(c: @crate, def_map: resolve::def_map, tcx: ty::ctxt)
|
||||||
mutable blocks: nil};
|
mutable blocks: nil};
|
||||||
visit::visit_crate(*c, cx, v);
|
visit::visit_crate(*c, cx, v);
|
||||||
let mini_table = std::map::new_int_hash();
|
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;
|
ret mini_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2099,13 +2099,15 @@ fn move_val(cx: @block_ctxt, action: copy_action, dst: ValueRef,
|
||||||
Store(cx, src_val, dst);
|
Store(cx, src_val, dst);
|
||||||
if src.kind == owned { ret zero_alloca(cx, src.val, t); }
|
if src.kind == owned { ret zero_alloca(cx, src.val, t); }
|
||||||
// If we're here, it must be a temporary.
|
// 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) {
|
} else if type_is_structural_or_param(tcx, t) {
|
||||||
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
|
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
|
||||||
cx = memmove_ty(cx, dst, src_val, t);
|
cx = memmove_ty(cx, dst, src_val, t);
|
||||||
if src.kind == owned { ret zero_alloca(cx, src_val, t); }
|
if src.kind == owned { ret zero_alloca(cx, src_val, t); }
|
||||||
// If we're here, it must be a temporary.
|
// 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 */
|
/* FIXME: suggests a type constraint */
|
||||||
bcx_ccx(cx).sess.bug("unexpected type in trans::move_val: " +
|
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,
|
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.
|
// 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)
|
let v = src.kind == owned ? load_if_immediate(cx, src.val, t)
|
||||||
: src.val;
|
: src.val;
|
||||||
ret copy_val(cx, action, dst, v, t);
|
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 {
|
for {v, t} in to_zero {
|
||||||
bcx = zero_alloca(bcx, v, t);
|
bcx = zero_alloca(bcx, v, t);
|
||||||
}
|
}
|
||||||
for {v, _} in to_revoke {
|
for {v, _} in to_revoke { revoke_clean(bcx, v); }
|
||||||
bcx = revoke_clean(bcx, v);
|
|
||||||
}
|
|
||||||
ret bcx;
|
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);
|
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
|
||||||
assert kind == owned;
|
assert kind == owned;
|
||||||
ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r,
|
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) {
|
ast::expr_move(dst, src) {
|
||||||
// FIXME: calculate copy init-ness in typestate.
|
// 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 {
|
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 {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 {
|
alt dest {
|
||||||
by_val(cell) {
|
by_val(cell) {
|
||||||
if kind == temporary {
|
if kind == temporary {
|
||||||
revoke_clean(bcx, val);
|
revoke_clean(bcx, val);
|
||||||
*cell = 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); }
|
if kind == owned { val = Load(bcx, val); }
|
||||||
let {bcx: cx, val} = take_ty_immediate(bcx, val, ty);
|
let {bcx: cx, val} = take_ty_immediate(bcx, val, ty);
|
||||||
*cell = val;
|
*cell = val;
|
||||||
bcx = cx;
|
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. {}
|
ignore. {}
|
||||||
}
|
}
|
||||||
ret bcx;
|
ret bcx;
|
||||||
|
@ -4807,8 +4814,10 @@ fn alloc_local(cx: @block_ctxt, local: @ast::local) -> @block_ctxt {
|
||||||
ast::pat_bind(_) { true } _ { false }
|
ast::pat_bind(_) { true } _ { false }
|
||||||
};
|
};
|
||||||
// Do not allocate space for locals that can be kept immediate.
|
// 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) &&
|
let ccx = bcx_ccx(cx);
|
||||||
ty::type_is_immediate(bcx_tcx(cx), t) {
|
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 {
|
alt local.node.init {
|
||||||
some({op: ast::init_assign., _}) { ret cx; }
|
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,
|
fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
||||||
output: str, amap: ast_map::map, mut_map: mut::mut_map,
|
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 sha = std::sha1::mk_sha1();
|
||||||
let link_meta = link::build_link_meta(sess, *crate, output, sha);
|
let link_meta = link::build_link_meta(sess, *crate, output, sha);
|
||||||
let llmod = str::as_buf(link_meta.name, {|buf|
|
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,
|
tcx: tcx,
|
||||||
mut_map: mut_map,
|
mut_map: mut_map,
|
||||||
copy_map: copy_map,
|
copy_map: copy_map,
|
||||||
|
last_uses: last_uses,
|
||||||
stats:
|
stats:
|
||||||
{mutable n_static_tydescs: 0u,
|
{mutable n_static_tydescs: 0u,
|
||||||
mutable n_derived_tydescs: 0u,
|
mutable n_derived_tydescs: 0u,
|
||||||
|
|
|
@ -102,6 +102,7 @@ type crate_ctxt =
|
||||||
tcx: ty::ctxt,
|
tcx: ty::ctxt,
|
||||||
mut_map: mut::mut_map,
|
mut_map: mut::mut_map,
|
||||||
copy_map: alias::copy_map,
|
copy_map: alias::copy_map,
|
||||||
|
last_uses: last_use::last_uses,
|
||||||
stats: stats,
|
stats: stats,
|
||||||
upcalls: @upcall::upcalls,
|
upcalls: @upcall::upcalls,
|
||||||
rust_object_type: TypeRef,
|
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
|
// 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
|
// this will be more involved. For now, we simply zero out the local, and the
|
||||||
// drop glue checks whether it is zero.
|
// 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 sc_cx = find_scope_cx(cx);
|
||||||
let found = -1;
|
let found = -1;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
@ -296,16 +297,21 @@ fn revoke_clean(cx: @block_ctxt, val: ValueRef) -> @block_ctxt {
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
// The value does not have a cleanup associated with it. Might be a
|
// The value does not have a cleanup associated with it. Continue to next
|
||||||
// constant or some immediate value.
|
// scope.
|
||||||
if found == -1 { ret cx; }
|
if found == -1 {
|
||||||
|
alt sc_cx.parent {
|
||||||
|
parent_some(parent) { revoke_clean(parent, val); } _ {}
|
||||||
|
}
|
||||||
|
ret;
|
||||||
|
}
|
||||||
// We found the cleanup and remove it
|
// We found the cleanup and remove it
|
||||||
sc_cx.cleanups =
|
sc_cx.cleanups =
|
||||||
std::vec::slice(sc_cx.cleanups, 0u, found as uint) +
|
std::vec::slice(sc_cx.cleanups, 0u, found as uint) +
|
||||||
std::vec::slice(sc_cx.cleanups, (found as uint) + 1u,
|
std::vec::slice(sc_cx.cleanups, (found as uint) + 1u,
|
||||||
std::vec::len(sc_cx.cleanups));
|
std::vec::len(sc_cx.cleanups));
|
||||||
sc_cx.lpad_dirty = true;
|
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)
|
fn get_res_dtor(ccx: @crate_ctxt, sp: span, did: ast::def_id, inner_t: ty::t)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue