@@ -64,8 +64,14 @@ pub struct DataFlowContext<'a, 'tcx: 'a, O> {
6464 /// bits generated as we exit the cfg node. Updated by `add_gen()`.
6565 gens : Vec < usize > ,
6666
67- /// bits killed as we exit the cfg node. Updated by `add_kill()`.
68- kills : Vec < usize > ,
67+ /// bits killed as we exit the cfg node, or non-locally jump over
68+ /// it. Updated by `add_kill(KillFrom::ScopeEnd)`.
69+ scope_kills : Vec < usize > ,
70+
71+ /// bits killed as we exit the cfg node directly; if it is jumped
72+ /// over, e.g. via `break`, the kills are not reflected in the
73+ /// jump's effects. Updated by `add_kill(KillFrom::Execution)`.
74+ action_kills : Vec < usize > ,
6975
7076 /// bits that are valid on entry to the cfg node. Updated by
7177 /// `propagate()`.
@@ -130,15 +136,23 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
130136 "" . to_string ( )
131137 } ;
132138
133- let kills = & self . kills [ start .. end] ;
134- let kills_str = if kills. iter ( ) . any ( |& u| u != 0 ) {
135- format ! ( " kill: {}" , bits_to_string( kills) )
139+ let action_kills = & self . action_kills [ start .. end] ;
140+ let action_kills_str = if action_kills. iter ( ) . any ( |& u| u != 0 ) {
141+ format ! ( " action_kill: {}" , bits_to_string( action_kills) )
142+ } else {
143+ "" . to_string ( )
144+ } ;
145+
146+ let scope_kills = & self . scope_kills [ start .. end] ;
147+ let scope_kills_str = if scope_kills. iter ( ) . any ( |& u| u != 0 ) {
148+ format ! ( " scope_kill: {}" , bits_to_string( scope_kills) )
136149 } else {
137150 "" . to_string ( )
138151 } ;
139152
140- try!( ps. synth_comment ( format ! ( "id {}: {}{}{}" , id, entry_str,
141- gens_str, kills_str) ) ) ;
153+ try!( ps. synth_comment (
154+ format ! ( "id {}: {}{}{}{}" , id, entry_str,
155+ gens_str, action_kills_str, scope_kills_str) ) ) ;
142156 try!( pp:: space ( & mut ps. s ) ) ;
143157 }
144158 Ok ( ( ) )
@@ -187,6 +201,25 @@ fn build_nodeid_to_index(decl: Option<&ast::FnDecl>,
187201 }
188202}
189203
204+ /// Flag used by `add_kill` to indicate whether the provided kill
205+ /// takes effect only when control flows directly through the node in
206+ /// question, or if the kill's effect is associated with any
207+ /// control-flow directly through or indirectly over the node.
208+ #[ derive( Copy , Clone , PartialEq , Debug ) ]
209+ pub enum KillFrom {
210+ /// A `ScopeEnd` kill is one that takes effect when any control
211+ /// flow goes over the node. A kill associated with the end of the
212+ /// scope of a variable declaration `let x;` is an example of a
213+ /// `ScopeEnd` kill.
214+ ScopeEnd ,
215+
216+ /// An `Execution` kill is one that takes effect only when control
217+ /// flow goes through the node to completion. A kill associated
218+ /// with an assignment statement `x = expr;` is an example of an
219+ /// `Execution` kill.
220+ Execution ,
221+ }
222+
190223impl < ' a , ' tcx , O : DataFlowOperator > DataFlowContext < ' a , ' tcx , O > {
191224 pub fn new ( tcx : & ' a ty:: ctxt < ' tcx > ,
192225 analysis_name : & ' static str ,
@@ -206,8 +239,10 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
206239
207240 let entry = if oper. initial_value ( ) { usize:: MAX } else { 0 } ;
208241
209- let gens: Vec < _ > = repeat ( 0 ) . take ( num_nodes * words_per_id) . collect ( ) ;
210- let kills: Vec < _ > = repeat ( 0 ) . take ( num_nodes * words_per_id) . collect ( ) ;
242+ let zeroes: Vec < _ > = repeat ( 0 ) . take ( num_nodes * words_per_id) . collect ( ) ;
243+ let gens: Vec < _ > = zeroes. clone ( ) ;
244+ let kills1: Vec < _ > = zeroes. clone ( ) ;
245+ let kills2: Vec < _ > = zeroes;
211246 let on_entry: Vec < _ > = repeat ( entry) . take ( num_nodes * words_per_id) . collect ( ) ;
212247
213248 let nodeid_to_index = build_nodeid_to_index ( decl, cfg) ;
@@ -220,7 +255,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
220255 bits_per_id : bits_per_id,
221256 oper : oper,
222257 gens : gens,
223- kills : kills,
258+ action_kills : kills1,
259+ scope_kills : kills2,
224260 on_entry : on_entry
225261 }
226262 }
@@ -240,7 +276,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
240276 }
241277 }
242278
243- pub fn add_kill ( & mut self , id : ast:: NodeId , bit : usize ) {
279+ pub fn add_kill ( & mut self , kind : KillFrom , id : ast:: NodeId , bit : usize ) {
244280 //! Indicates that `id` kills `bit`
245281 debug ! ( "{} add_kill(id={}, bit={})" ,
246282 self . analysis_name, id, bit) ;
@@ -250,7 +286,10 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
250286 let indices = get_cfg_indices ( id, & self . nodeid_to_index ) ;
251287 for & cfgidx in indices {
252288 let ( start, end) = self . compute_id_range ( cfgidx) ;
253- let kills = & mut self . kills [ start.. end] ;
289+ let kills = match kind {
290+ KillFrom :: Execution => & mut self . action_kills [ start.. end] ,
291+ KillFrom :: ScopeEnd => & mut self . scope_kills [ start.. end] ,
292+ } ;
254293 set_bit ( kills, bit) ;
255294 }
256295 }
@@ -264,7 +303,9 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
264303 let ( start, end) = self . compute_id_range ( cfgidx) ;
265304 let gens = & self . gens [ start.. end] ;
266305 bitwise ( bits, gens, & Union ) ;
267- let kills = & self . kills [ start.. end] ;
306+ let kills = & self . action_kills [ start.. end] ;
307+ bitwise ( bits, kills, & Subtract ) ;
308+ let kills = & self . scope_kills [ start.. end] ;
268309 bitwise ( bits, kills, & Subtract ) ;
269310
270311 debug ! ( "{} apply_gen_kill(cfgidx={:?}, bits={}) [after]" ,
@@ -278,7 +319,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
278319
279320 assert ! ( start < self . gens. len( ) ) ;
280321 assert ! ( end <= self . gens. len( ) ) ;
281- assert ! ( self . gens. len( ) == self . kills. len( ) ) ;
322+ assert ! ( self . gens. len( ) == self . action_kills. len( ) ) ;
323+ assert ! ( self . gens. len( ) == self . scope_kills. len( ) ) ;
282324 assert ! ( self . gens. len( ) == self . on_entry. len( ) ) ;
283325
284326 ( start, end)
@@ -412,7 +454,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
412454 cfg. graph . each_edge ( |_edge_index, edge| {
413455 let flow_exit = edge. source ( ) ;
414456 let ( start, end) = self . compute_id_range ( flow_exit) ;
415- let mut orig_kills = self . kills [ start.. end] . to_vec ( ) ;
457+ let mut orig_kills = self . scope_kills [ start.. end] . to_vec ( ) ;
416458
417459 let mut changed = false ;
418460 for & node_id in & edge. data . exiting_scopes {
@@ -421,8 +463,12 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
421463 Some ( indices) => {
422464 for & cfg_idx in indices {
423465 let ( start, end) = self . compute_id_range ( cfg_idx) ;
424- let kills = & self . kills [ start.. end] ;
466+ let kills = & self . scope_kills [ start.. end] ;
425467 if bitwise ( & mut orig_kills, kills, & Union ) {
468+ debug ! ( "scope exits: scope id={} \
469+ (node={:?} of {:?}) added killset: {}",
470+ node_id, cfg_idx, indices,
471+ bits_to_string( kills) ) ;
426472 changed = true ;
427473 }
428474 }
@@ -436,7 +482,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
436482 }
437483
438484 if changed {
439- let bits = & mut self . kills [ start.. end] ;
485+ let bits = & mut self . scope_kills [ start.. end] ;
440486 debug ! ( "{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]" ,
441487 self . analysis_name, flow_exit, mut_bits_to_string( bits) ) ;
442488 bits. clone_from_slice ( & orig_kills[ ..] ) ;
0 commit comments