@@ -64,8 +64,12 @@ 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. Updated by `add_kill(KillFrom::Execution)`.
72
+ action_kills : Vec < usize > ,
69
73
70
74
/// bits that are valid on entry to the cfg node. Updated by
71
75
/// `propagate()`.
@@ -130,15 +134,23 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
130
134
"" . to_string ( )
131
135
} ;
132
136
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) )
137
+ let action_kills = & self . action_kills [ start .. end] ;
138
+ let action_kills_str = if action_kills. iter ( ) . any ( |& u| u != 0 ) {
139
+ format ! ( " action_kill: {}" , bits_to_string( action_kills) )
140
+ } else {
141
+ "" . to_string ( )
142
+ } ;
143
+
144
+ let scope_kills = & self . scope_kills [ start .. end] ;
145
+ let scope_kills_str = if scope_kills. iter ( ) . any ( |& u| u != 0 ) {
146
+ format ! ( " scope_kill: {}" , bits_to_string( scope_kills) )
136
147
} else {
137
148
"" . to_string ( )
138
149
} ;
139
150
140
- try!( ps. synth_comment ( format ! ( "id {}: {}{}{}" , id, entry_str,
141
- gens_str, kills_str) ) ) ;
151
+ try!( ps. synth_comment (
152
+ format ! ( "id {}: {}{}{}{}" , id, entry_str,
153
+ gens_str, action_kills_str, scope_kills_str) ) ) ;
142
154
try!( pp:: space ( & mut ps. s ) ) ;
143
155
}
144
156
Ok ( ( ) )
@@ -187,6 +199,25 @@ fn build_nodeid_to_index(decl: Option<&ast::FnDecl>,
187
199
}
188
200
}
189
201
202
+ /// Flag used by `add_kill` to indicate whether the provided kill
203
+ /// takes effect only when control flows directly through the node in
204
+ /// question, or if the kill's effect is associated with any
205
+ /// control-flow directly through or indirectly over the node.
206
+ #[ derive( Copy , Clone , PartialEq , Debug ) ]
207
+ pub enum KillFrom {
208
+ /// A `ScopeEnd` kill is one that takes effect when any control
209
+ /// flow goes over the node. A kill associated with the end of the
210
+ /// scope of a variable declaration `let x;` is an example of a
211
+ /// `ScopeEnd` kill.
212
+ ScopeEnd ,
213
+
214
+ /// An `Execution` kill is one that takes effect only when controw
215
+ /// flow goes through the node to completion. A kill associated
216
+ /// with an assignment statement `x = expr;` is an example of an
217
+ /// `Execution` kill.
218
+ Execution ,
219
+ }
220
+
190
221
impl < ' a , ' tcx , O : DataFlowOperator > DataFlowContext < ' a , ' tcx , O > {
191
222
pub fn new ( tcx : & ' a ty:: ctxt < ' tcx > ,
192
223
analysis_name : & ' static str ,
@@ -206,8 +237,10 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
206
237
207
238
let entry = if oper. initial_value ( ) { usize:: MAX } else { 0 } ;
208
239
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 ( ) ;
240
+ let zeroes: Vec < _ > = repeat ( 0 ) . take ( num_nodes * words_per_id) . collect ( ) ;
241
+ let gens: Vec < _ > = zeroes. clone ( ) ;
242
+ let kills1: Vec < _ > = zeroes. clone ( ) ;
243
+ let kills2: Vec < _ > = zeroes;
211
244
let on_entry: Vec < _ > = repeat ( entry) . take ( num_nodes * words_per_id) . collect ( ) ;
212
245
213
246
let nodeid_to_index = build_nodeid_to_index ( decl, cfg) ;
@@ -220,7 +253,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
220
253
bits_per_id : bits_per_id,
221
254
oper : oper,
222
255
gens : gens,
223
- kills : kills,
256
+ action_kills : kills1,
257
+ scope_kills : kills2,
224
258
on_entry : on_entry
225
259
}
226
260
}
@@ -240,7 +274,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
240
274
}
241
275
}
242
276
243
- pub fn add_kill ( & mut self , id : ast:: NodeId , bit : usize ) {
277
+ pub fn add_kill ( & mut self , kind : KillFrom , id : ast:: NodeId , bit : usize ) {
244
278
//! Indicates that `id` kills `bit`
245
279
debug ! ( "{} add_kill(id={}, bit={})" ,
246
280
self . analysis_name, id, bit) ;
@@ -250,7 +284,10 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
250
284
let indices = get_cfg_indices ( id, & self . nodeid_to_index ) ;
251
285
for & cfgidx in indices {
252
286
let ( start, end) = self . compute_id_range ( cfgidx) ;
253
- let kills = & mut self . kills [ start.. end] ;
287
+ let kills = match kind {
288
+ KillFrom :: Execution => & mut self . action_kills [ start.. end] ,
289
+ KillFrom :: ScopeEnd => & mut self . scope_kills [ start.. end] ,
290
+ } ;
254
291
set_bit ( kills, bit) ;
255
292
}
256
293
}
@@ -264,7 +301,9 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
264
301
let ( start, end) = self . compute_id_range ( cfgidx) ;
265
302
let gens = & self . gens [ start.. end] ;
266
303
bitwise ( bits, gens, & Union ) ;
267
- let kills = & self . kills [ start.. end] ;
304
+ let kills = & self . action_kills [ start.. end] ;
305
+ bitwise ( bits, kills, & Subtract ) ;
306
+ let kills = & self . scope_kills [ start.. end] ;
268
307
bitwise ( bits, kills, & Subtract ) ;
269
308
270
309
debug ! ( "{} apply_gen_kill(cfgidx={:?}, bits={}) [after]" ,
@@ -278,7 +317,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
278
317
279
318
assert ! ( start < self . gens. len( ) ) ;
280
319
assert ! ( end <= self . gens. len( ) ) ;
281
- assert ! ( self . gens. len( ) == self . kills. len( ) ) ;
320
+ assert ! ( self . gens. len( ) == self . action_kills. len( ) ) ;
321
+ assert ! ( self . gens. len( ) == self . scope_kills. len( ) ) ;
282
322
assert ! ( self . gens. len( ) == self . on_entry. len( ) ) ;
283
323
284
324
( start, end)
@@ -402,6 +442,11 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
402
442
//!
403
443
//! This is usually called (if it is called at all), after
404
444
//! all add_gen and add_kill calls, but before propagate.
445
+ //!
446
+ //! The callback predicate `p(b, e)` is invoked on each node
447
+ //! `e` that has been registered as an `exiting_scope` for a
448
+ //! given control-breaking node `b`, to determine whether to
449
+ //! include the associated kill-effects or not.
405
450
406
451
debug ! ( "{} add_kills_from_flow_exits" , self . analysis_name) ;
407
452
if self . bits_per_id == 0 {
@@ -412,7 +457,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
412
457
cfg. graph . each_edge ( |_edge_index, edge| {
413
458
let flow_exit = edge. source ( ) ;
414
459
let ( start, end) = self . compute_id_range ( flow_exit) ;
415
- let mut orig_kills = self . kills [ start.. end] . to_vec ( ) ;
460
+ let mut orig_kills = self . scope_kills [ start.. end] . to_vec ( ) ;
416
461
417
462
let mut changed = false ;
418
463
for & node_id in & edge. data . exiting_scopes {
@@ -421,8 +466,12 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
421
466
Some ( indices) => {
422
467
for & cfg_idx in indices {
423
468
let ( start, end) = self . compute_id_range ( cfg_idx) ;
424
- let kills = & self . kills [ start.. end] ;
469
+ let kills = & self . scope_kills [ start.. end] ;
425
470
if bitwise ( & mut orig_kills, kills, & Union ) {
471
+ debug ! ( "scope exits: scope id={} \
472
+ (node={:?} of {:?}) added killset: {}",
473
+ node_id, cfg_idx, indices,
474
+ bits_to_string( kills) ) ;
426
475
changed = true ;
427
476
}
428
477
}
@@ -436,7 +485,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
436
485
}
437
486
438
487
if changed {
439
- let bits = & mut self . kills [ start.. end] ;
488
+ let bits = & mut self . scope_kills [ start.. end] ;
440
489
debug ! ( "{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]" ,
441
490
self . analysis_name, flow_exit, mut_bits_to_string( bits) ) ;
442
491
bits. clone_from_slice ( & orig_kills[ ..] ) ;
0 commit comments