@@ -57,6 +57,7 @@ import capture::{cap_move, cap_drop, cap_copy, cap_ref};
5757
5858export check_crate;
5959export last_use_map;
60+ export spill_map;
6061
6162// Maps from an expr id to a list of variable ids for which this expr
6263// is the last use. Typically, the expr is a path and the node id is
@@ -65,6 +66,13 @@ export last_use_map;
6566// list of closed over variables that can be moved into the closure.
6667type last_use_map = hashmap < node_id , @dvec < node_id > > ;
6768
69+ // A set of variable ids which must be spilled (stored on the stack).
70+ // We add in any variables or arguments where:
71+ // (1) the variables are moved;
72+ // (2) the address of the variable/argument is taken;
73+ // or (3) we find a last use (as they may be moved).
74+ type spill_map = hashmap < node_id , ( ) > ;
75+
6876enum variable = uint;
6977enum live_node = uint;
7078
@@ -77,7 +85,7 @@ enum live_node_kind {
7785
7886fn check_crate ( tcx : ty:: ctxt ,
7987 method_map : typeck:: method_map ,
80- crate : @crate ) -> last_use_map {
88+ crate : @crate ) -> ( last_use_map , spill_map ) {
8189 let visitor = visit:: mk_vt ( @{
8290 visit_fn: visit_fn,
8391 visit_local: visit_local,
@@ -86,11 +94,12 @@ fn check_crate(tcx: ty::ctxt,
8694 } ) ;
8795
8896 let last_use_map = int_hash ( ) ;
97+ let spill_map = int_hash ( ) ;
8998 let initial_maps = @ir_maps ( tcx, method_map,
90- last_use_map) ;
99+ last_use_map, spill_map ) ;
91100 visit:: visit_crate ( * crate , initial_maps, visitor) ;
92101 tcx. sess . abort_if_errors ( ) ;
93- ret last_use_map;
102+ ret ( last_use_map, spill_map ) ;
94103}
95104
96105impl of to_str:: to_str for live_node {
@@ -153,6 +162,7 @@ class ir_maps {
153162 let tcx: ty:: ctxt;
154163 let method_map: typeck:: method_map ;
155164 let last_use_map: last_use_map ;
165+ let spill_map: spill_map ;
156166
157167 let mut num_live_nodes: uint ;
158168 let mut num_vars: uint ;
@@ -164,10 +174,11 @@ class ir_maps {
164174 let mut lnks: [ live_node_kind ] ;
165175
166176 new ( tcx: ty:: ctxt, method_map: typeck:: method_map,
167- last_use_map: last_use_map) {
177+ last_use_map: last_use_map, spill_map : spill_map ) {
168178 self . tcx = tcx;
169179 self . method_map = method_map;
170180 self . last_use_map = last_use_map;
181+ self . spill_map = spill_map;
171182
172183 self . num_live_nodes = 0 u;
173184 self . num_vars = 0 u;
@@ -253,6 +264,17 @@ class ir_maps {
253264 self . lnks [ * ln]
254265 }
255266
267+ fn add_spill ( var : variable ) {
268+ let vk = self . var_kinds [ * var] ;
269+ alt vk {
270+ vk_local( id, _) | vk_arg ( id, _, by_val) {
271+ #debug[ "adding spill for %?" , vk] ;
272+ self . spill_map . insert ( id, ( ) ) ;
273+ }
274+ vk_arg ( * ) | vk_field ( _) | vk_self | vk_implicit_ret { }
275+ }
276+ }
277+
256278 fn add_last_use ( expr_id : node_id , var : variable ) {
257279 let vk = self . var_kinds [ * var] ;
258280 #debug[ "Node %d is a last use of variable %?" , expr_id, vk] ;
@@ -286,7 +308,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
286308
287309 // swap in a new set of IR maps for this function body:
288310 let fn_maps = @ir_maps ( self . tcx , self . method_map ,
289- self . last_use_map ) ;
311+ self . last_use_map , self . spill_map ) ;
290312
291313 #debug[ "creating fn_maps: %x" , ptr:: addr_of ( * fn_maps) as uint ] ;
292314
@@ -1385,7 +1407,11 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) {
13851407 vt. visit_expr( f, self , vt) ;
13861408 vec:: iter2( args, targs) { |arg_expr, arg_ty|
13871409 alt ty:: resolved_mode( self . tcx, arg_ty. mode) {
1388- by_val | by_copy | by_ref | by_mutbl_ref {
1410+ by_val | by_copy {
1411+ vt. visit_expr( arg_expr, self, vt) ;
1412+ }
1413+ by_ref | by_mutbl_ref {
1414+ self. spill_expr( arg_expr) ;
13891415 vt. visit_expr( arg_expr, self , vt) ;
13901416 }
13911417 by_move {
@@ -1395,6 +1421,10 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) {
13951421 }
13961422 }
13971423
1424+ expr_addr_of( _, arg_expr) {
1425+ self . spill_expr( arg_expr) ;
1426+ }
1427+
13981428 // no correctness conditions related to liveness
13991429 expr_if_check( * ) | expr_if( * ) | expr_alt( * ) |
14001430 expr_while( * ) | expr_loop( * ) |
@@ -1404,7 +1434,7 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) {
14041434 expr_assert( * ) | expr_check( * ) | expr_copy( * ) |
14051435 expr_loop_body( * ) | expr_cast( * ) | expr_unary( * ) | expr_fail( * ) |
14061436 expr_ret( * ) | expr_break | expr_cont | expr_lit( _) |
1407- expr_block( * ) | expr_swap( * ) | expr_mac( * ) | expr_addr_of ( * ) {
1437+ expr_block( * ) | expr_swap( * ) | expr_mac( * ) {
14081438 visit:: visit_expr( expr, self , vt) ;
14091439 }
14101440 }
@@ -1471,7 +1501,10 @@ impl check_methods for @liveness {
14711501 ln. to_str( ) , var. to_str( ) ] ;
14721502
14731503 alt ( * self ) . live_on_exit( ln, var) {
1474- none { }
1504+ none {
1505+ // update spill map to include this variable, as it is moved:
1506+ ( * self . ir) . add_spill( var) ;
1507+ }
14751508 some( lnk) {
14761509 self . report_illegal_move( span, lnk, var) ;
14771510 }
@@ -1483,10 +1516,20 @@ impl check_methods for @liveness {
14831516 some( _) { }
14841517 none {
14851518 ( * self . ir) . add_last_use( expr. id, var) ;
1519+
1520+ // update spill map to include this variable, as it may be moved:
1521+ ( * self . ir) . add_spill( var) ;
14861522 }
14871523 }
14881524 }
14891525
1526+ fn spill_expr( expr: @expr) {
1527+ alt ( * self ) . variable_from_path( expr) {
1528+ some( var) { ( * self . ir) . add_spill( var) }
1529+ none { }
1530+ }
1531+ }
1532+
14901533 fn check_move_from_expr( expr: @expr, vt: vt<@liveness>) {
14911534 #debug[ "check_move_from_expr( node %d: %s) ",
14921535 expr. id, expr_to_str( expr) ] ;
@@ -1732,4 +1775,4 @@ impl check_methods for @liveness {
17321775 }
17331776 }
17341777 }
1735- }
1778+ }
0 commit comments