@@ -64,8 +64,14 @@ pub struct DataFlowContext<'a, 'tcx: 'a, O> {
64
64
/// bits generated as we exit the cfg node. Updated by `add_gen()`.
65
65
gens : Vec < usize > ,
66
66
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 > ,
69
75
70
76
/// bits that are valid on entry to the cfg node. Updated by
71
77
/// `propagate()`.
@@ -130,15 +136,23 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
130
136
"" . to_string ( )
131
137
} ;
132
138
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) )
136
149
} else {
137
150
"" . to_string ( )
138
151
} ;
139
152
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) ) ) ;
142
156
try!( pp:: space ( & mut ps. s ) ) ;
143
157
}
144
158
Ok ( ( ) )
@@ -187,6 +201,25 @@ fn build_nodeid_to_index(decl: Option<&ast::FnDecl>,
187
201
}
188
202
}
189
203
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
+
190
223
impl < ' a , ' tcx , O : DataFlowOperator > DataFlowContext < ' a , ' tcx , O > {
191
224
pub fn new ( tcx : & ' a ty:: ctxt < ' tcx > ,
192
225
analysis_name : & ' static str ,
@@ -206,8 +239,10 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
206
239
207
240
let entry = if oper. initial_value ( ) { usize:: MAX } else { 0 } ;
208
241
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;
211
246
let on_entry: Vec < _ > = repeat ( entry) . take ( num_nodes * words_per_id) . collect ( ) ;
212
247
213
248
let nodeid_to_index = build_nodeid_to_index ( decl, cfg) ;
@@ -220,7 +255,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
220
255
bits_per_id : bits_per_id,
221
256
oper : oper,
222
257
gens : gens,
223
- kills : kills,
258
+ action_kills : kills1,
259
+ scope_kills : kills2,
224
260
on_entry : on_entry
225
261
}
226
262
}
@@ -240,7 +276,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
240
276
}
241
277
}
242
278
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 ) {
244
280
//! Indicates that `id` kills `bit`
245
281
debug ! ( "{} add_kill(id={}, bit={})" ,
246
282
self . analysis_name, id, bit) ;
@@ -250,7 +286,10 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
250
286
let indices = get_cfg_indices ( id, & self . nodeid_to_index ) ;
251
287
for & cfgidx in indices {
252
288
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
+ } ;
254
293
set_bit ( kills, bit) ;
255
294
}
256
295
}
@@ -264,7 +303,9 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
264
303
let ( start, end) = self . compute_id_range ( cfgidx) ;
265
304
let gens = & self . gens [ start.. end] ;
266
305
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] ;
268
309
bitwise ( bits, kills, & Subtract ) ;
269
310
270
311
debug ! ( "{} apply_gen_kill(cfgidx={:?}, bits={}) [after]" ,
@@ -278,7 +319,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
278
319
279
320
assert ! ( start < self . gens. len( ) ) ;
280
321
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( ) ) ;
282
324
assert ! ( self . gens. len( ) == self . on_entry. len( ) ) ;
283
325
284
326
( start, end)
@@ -412,7 +454,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
412
454
cfg. graph . each_edge ( |_edge_index, edge| {
413
455
let flow_exit = edge. source ( ) ;
414
456
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 ( ) ;
416
458
417
459
let mut changed = false ;
418
460
for & node_id in & edge. data . exiting_scopes {
@@ -421,8 +463,12 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
421
463
Some ( indices) => {
422
464
for & cfg_idx in indices {
423
465
let ( start, end) = self . compute_id_range ( cfg_idx) ;
424
- let kills = & self . kills [ start.. end] ;
466
+ let kills = & self . scope_kills [ start.. end] ;
425
467
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) ) ;
426
472
changed = true ;
427
473
}
428
474
}
@@ -436,7 +482,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
436
482
}
437
483
438
484
if changed {
439
- let bits = & mut self . kills [ start.. end] ;
485
+ let bits = & mut self . scope_kills [ start.. end] ;
440
486
debug ! ( "{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]" ,
441
487
self . analysis_name, flow_exit, mut_bits_to_string( bits) ) ;
442
488
bits. clone_from_slice ( & orig_kills[ ..] ) ;
0 commit comments