Skip to content

Commit 8f8ebb5

Browse files
committed
Implement a last-use-of-local finding algorithm
Issue #925
1 parent 0c97fcb commit 8f8ebb5

File tree

6 files changed

+250
-6
lines changed

6 files changed

+250
-6
lines changed

src/comp/driver/rustc.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import metadata::{creader, cstore};
55
import syntax::parse::{parser};
66
import syntax::{ast, codemap};
77
import front::attr;
8-
import middle::{trans, resolve, freevars, kind, ty, typeck, fn_usage};
8+
import middle::{trans, resolve, freevars, kind, ty, typeck, fn_usage,
9+
last_use};
910
import syntax::print::{pp, pprust};
1011
import util::{ppaux, filesearch};
1112
import back::link;
@@ -138,6 +139,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
138139
bind freevars::annotate_freevars(def_map, crate));
139140
let ty_cx = ty::mk_ctxt(sess, def_map, ext_map, ast_map, freevars);
140141
time(time_passes, "typechecking", bind typeck::check_crate(ty_cx, crate));
142+
let last_uses = time(time_passes, "last use finding",
143+
bind last_use::find_last_uses(crate, def_map, ty_cx));
141144
time(time_passes, "function usage",
142145
bind fn_usage::check_crate_fn_usage(ty_cx, crate));
143146
time(time_passes, "alt checking",
@@ -150,7 +153,8 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
150153
let copy_map =
151154
time(time_passes, "alias checking",
152155
bind middle::alias::check_crate(ty_cx, crate));
153-
time(time_passes, "kind checking", bind kind::check_crate(ty_cx, crate));
156+
time(time_passes, "kind checking",
157+
bind kind::check_crate(ty_cx, last_uses, crate));
154158
time(time_passes, "const checking",
155159
bind middle::check_const::check_crate(ty_cx, crate));
156160
if sess.get_opts().no_trans { ret; }

src/comp/middle/kind.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ type rval_map = std::map::hashmap<node_id, ()>;
1515

1616
type ctx = {tcx: ty::ctxt,
1717
rval_map: rval_map,
18+
last_uses: last_use::last_uses,
1819
mutable ret_by_ref: bool};
1920

20-
fn check_crate(tcx: ty::ctxt, crate: @crate) -> rval_map {
21+
fn check_crate(tcx: ty::ctxt, last_uses: last_use::last_uses,
22+
crate: @crate) -> rval_map {
2123
let ctx = {tcx: tcx,
2224
rval_map: std::map::new_int_hash(),
25+
last_uses: last_uses,
2326
mutable ret_by_ref: false};
2427
let visit = visit::mk_vt(@{
2528
visit_expr: check_expr,
@@ -118,7 +121,7 @@ fn maybe_copy(cx: ctx, ex: @expr) {
118121
}
119122

120123
fn check_copy_ex(cx: ctx, ex: @expr, _warn: bool) {
121-
if ty::expr_is_lval(cx.tcx, ex) {
124+
if ty::expr_is_lval(cx.tcx, ex) && !cx.last_uses.contains_key(ex.id) {
122125
let ty = ty::expr_ty(cx.tcx, ex);
123126
check_copy(cx, ty, ex.span);
124127
// FIXME turn this on again once vector types are no longer unique.

src/comp/middle/last_use.rs

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import syntax::{visit, ast_util};
2+
import syntax::ast::*;
3+
import std::list::{list, nil, cons, tail};
4+
import std::{vec, list, option};
5+
6+
// Marks expr_paths that are last uses.
7+
type last_uses = std::map::hashmap<node_id, ()>;
8+
9+
tag seen { unset; seen(node_id); }
10+
tag block_type { func; loop; }
11+
12+
type set = [{def: node_id, exprs: list<node_id>}];
13+
type bl = @{type: block_type, mutable second: bool, mutable exits: [set]};
14+
15+
type ctx = {last_uses: std::map::hashmap<node_id, bool>,
16+
def_map: resolve::def_map,
17+
tcx: ty::ctxt,
18+
// The current set of local last uses
19+
mutable current: set,
20+
mutable blocks: list<bl>};
21+
22+
fn find_last_uses(c: @crate, def_map: resolve::def_map, tcx: ty::ctxt)
23+
-> last_uses {
24+
let v = visit::mk_vt(@{visit_expr: visit_expr,
25+
visit_fn: visit_fn
26+
with *visit::default_visitor()});
27+
let cx = {last_uses: std::map::new_int_hash(),
28+
def_map: def_map,
29+
tcx: tcx,
30+
mutable current: [],
31+
mutable blocks: nil};
32+
visit::visit_crate(*c, cx, v);
33+
let mini_table = std::map::new_int_hash();
34+
cx.last_uses.items {|key, val| if val { mini_table.insert(key, ()); }}
35+
ret mini_table;
36+
}
37+
38+
fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
39+
alt ex.node {
40+
expr_ret(oexpr) {
41+
visit::visit_expr_opt(oexpr, cx, v);
42+
if !add_block_exit(cx, func) { leave_fn(cx); }
43+
}
44+
expr_fail(oexpr) {
45+
visit::visit_expr_opt(oexpr, cx, v);
46+
leave_fn(cx);
47+
}
48+
expr_break. { add_block_exit(cx, loop); }
49+
expr_while(_, _) | expr_do_while(_, _) {
50+
visit_block(loop, cx) {|| visit::visit_expr(ex, cx, v);}
51+
}
52+
expr_for(_, coll, blk) {
53+
v.visit_expr(coll, cx, v);
54+
visit_block(loop, cx) {|| visit::visit_block(blk, cx, v);}
55+
}
56+
expr_ternary(_, _, _) {
57+
v.visit_expr(ast_util::ternary_to_if(ex), cx, v);
58+
}
59+
expr_alt(input, arms) {
60+
v.visit_expr(input, cx, v);
61+
let before = cx.current, sets = [];
62+
for arm in arms {
63+
cx.current = before;
64+
v.visit_arm(arm, cx, v);
65+
sets += [cx.current];
66+
}
67+
cx.current = join_branches(sets);
68+
}
69+
expr_if(cond, then, els) {
70+
v.visit_expr(cond, cx, v);
71+
let cur = cx.current;
72+
visit::visit_block(then, cx, v);
73+
cx.current <-> cur;
74+
visit::visit_expr_opt(els, cx, v);
75+
cx.current = join_branches([cur, cx.current]);
76+
}
77+
expr_path(_) {
78+
alt clear_if_path(cx, ex, v, false) {
79+
option::some(my_def) {
80+
cx.current += [{def: my_def, exprs: cons(ex.id, @nil)}];
81+
}
82+
_ {}
83+
}
84+
}
85+
expr_swap(lhs, rhs) {
86+
clear_if_path(cx, lhs, v, false);
87+
clear_if_path(cx, rhs, v, false);
88+
}
89+
expr_move(dest, src) | expr_assign(dest, src) {
90+
v.visit_expr(src, cx, v);
91+
clear_if_path(cx, dest, v, true);
92+
}
93+
expr_assign_op(_, dest, src) {
94+
v.visit_expr(src, cx, v);
95+
v.visit_expr(dest, cx, v);
96+
clear_if_path(cx, dest, v, true);
97+
}
98+
expr_call(f, args, _) {
99+
v.visit_expr(f, cx, v);
100+
let i = 0u;
101+
for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) {
102+
alt arg_t.mode {
103+
by_mut_ref. { clear_if_path(cx, args[i], v, false); }
104+
_ { v.visit_expr(args[i], cx, v); }
105+
}
106+
i += 1u;
107+
}
108+
}
109+
_ { visit::visit_expr(ex, cx, v); }
110+
}
111+
}
112+
113+
fn visit_fn(f: _fn, tps: [ty_param], sp: syntax::codemap::span,
114+
ident: fn_ident, id: node_id, cx: ctx, v: visit::vt<ctx>) {
115+
if f.proto == proto_block {
116+
visit_block(func, cx, {||
117+
visit::visit_fn(f, tps, sp, ident, id, cx, v);
118+
});
119+
} else {
120+
let old = nil;
121+
cx.blocks <-> old;
122+
visit::visit_fn(f, tps, sp, ident, id, cx, v);
123+
cx.blocks <-> old;
124+
leave_fn(cx);
125+
}
126+
}
127+
128+
fn visit_block(tp: block_type, cx: ctx, visit: block()) {
129+
let local = @{type: tp, mutable second: false, mutable exits: []};
130+
cx.blocks = cons(local, @cx.blocks);
131+
visit();
132+
local.second = true;
133+
visit();
134+
cx.blocks = tail(cx.blocks);
135+
cx.current = join_branches(local.exits);
136+
}
137+
138+
fn add_block_exit(cx: ctx, tp: block_type) -> bool {
139+
let cur = cx.blocks;
140+
while cur != nil {
141+
alt cur {
142+
cons(b, tail) {
143+
if (b.type == tp) {
144+
if !b.second { b.exits += [cx.current]; }
145+
ret true;
146+
}
147+
cur = *tail;
148+
}
149+
}
150+
}
151+
ret false;
152+
}
153+
154+
fn join_branches(branches: [set]) -> set {
155+
let found: set = [], i = 0u, l = vec::len(branches);
156+
for set in branches {
157+
i += 1u;
158+
for {def, exprs} in set {
159+
if !vec::any({|v| v.def == def}, found) {
160+
let j = i, ne = exprs;
161+
while j < l {
162+
for {def: d2, exprs} in branches[j] {
163+
if d2 == def {
164+
list::iter(exprs) {|e|
165+
if !list::has(ne, e) { ne = cons(e, @ne); }
166+
}
167+
}
168+
}
169+
j += 1u;
170+
}
171+
found += [{def: def, exprs: ne}];
172+
}
173+
}
174+
}
175+
ret found;
176+
}
177+
178+
fn leave_fn(cx: ctx) {
179+
for {def, exprs} in cx.current {
180+
list::iter(exprs) {|ex_id|
181+
if !cx.last_uses.contains_key(ex_id) {
182+
cx.last_uses.insert(ex_id, true);
183+
}
184+
}
185+
}
186+
}
187+
188+
fn clear_in_current(cx: ctx, my_def: node_id, to: bool) {
189+
for {def, exprs} in cx.current {
190+
if def == my_def {
191+
list::iter(exprs) {|expr|
192+
if !to || !cx.last_uses.contains_key(expr) {
193+
cx.last_uses.insert(expr, to);
194+
}
195+
}
196+
cx.current = vec::filter({|x| x.def != my_def},
197+
copy cx.current);
198+
break;
199+
}
200+
}
201+
}
202+
203+
fn clear_if_path(cx: ctx, ex: @expr, v: visit::vt<ctx>, to: bool)
204+
-> option::t<node_id> {
205+
alt ex.node {
206+
expr_path(_) {
207+
alt cx.def_map.get(ex.id) {
208+
def_local(def_id, let_copy.) | def_arg(def_id, by_copy.) |
209+
def_arg(def_id, by_move.) {
210+
clear_in_current(cx, def_id.node, to);
211+
ret option::some(def_id.node);
212+
}
213+
_ {}
214+
}
215+
}
216+
_ { v.visit_expr(ex, cx, v); }
217+
}
218+
ret option::none;
219+
}

src/comp/rustc.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ mod middle {
3030
mod check_const;
3131
mod mut;
3232
mod alias;
33+
mod last_use;
3334
mod kind;
3435
mod freevars;
3536
mod shape;

src/lib/list.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,23 @@ fn append<T>(l: list<T>, m: list<T>) -> list<T> {
134134
}
135135
}
136136

137+
/*
138+
Function: iter
139+
140+
Iterate over a list
141+
*/
142+
fn iter<copy T>(l: list<T>, f: block(T)) {
143+
let cur = l;
144+
while cur != nil {
145+
alt cur {
146+
cons(hd, tl) {
147+
f(hd);
148+
cur = *tl;
149+
}
150+
}
151+
}
152+
}
153+
137154
// Local Variables:
138155
// mode: rust;
139156
// fill-column: 78;

src/lib/vec.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -703,8 +703,8 @@ Iterates over vector `v` and, for each element, calls function `f` with the
703703
element's value and index.
704704
*/
705705
fn iter2<T>(v: [const T], f: block(uint, T)) {
706-
let i = 0u;
707-
for x in v { f(i, x); i += 1u; }
706+
let i = 0u, l = len(v);
707+
while i < l { f(i, v[i]); i += 1u; }
708708
}
709709

710710
/*

0 commit comments

Comments
 (0)