1
1
use std:: ops:: RangeInclusive ;
2
2
3
- use rustc_middle:: mir:: {
4
- self , BasicBlock , CallReturnPlaces , Location , SwitchTargets , TerminatorEdges ,
5
- } ;
3
+ use rustc_middle:: mir:: { self , BasicBlock , CallReturnPlaces , Location , TerminatorEdges } ;
6
4
7
5
use super :: visitor:: ResultsVisitor ;
8
6
use super :: { Analysis , Effect , EffectIndex , Results , SwitchIntTarget } ;
@@ -78,8 +76,6 @@ impl Direction for Backward {
78
76
for pred in body. basic_blocks . predecessors ( ) [ block] . iter ( ) . copied ( ) {
79
77
match body[ pred] . terminator ( ) . kind {
80
78
// Apply terminator-specific edge effects.
81
- //
82
- // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
83
79
mir:: TerminatorKind :: Call { destination, target : Some ( dest) , .. }
84
80
if dest == block =>
85
81
{
@@ -115,18 +111,18 @@ impl Direction for Backward {
115
111
}
116
112
117
113
mir:: TerminatorKind :: SwitchInt { targets : _, ref discr } => {
118
- let mut applier = BackwardSwitchIntEdgeEffectsApplier {
119
- body,
120
- pred ,
121
- exit_state ,
122
- block ,
123
- propagate : & mut propagate ,
124
- effects_applied : false ,
125
- } ;
126
-
127
- analysis . apply_switch_int_edge_effects ( pred, discr , & mut applier ) ;
128
-
129
- if !applier . effects_applied {
114
+ if let Some ( mut data ) = analysis . get_switch_int_data ( block , discr ) {
115
+ let values = & body. basic_blocks . switch_sources ( ) [ & ( block , pred ) ] ;
116
+ let targets =
117
+ values . iter ( ) . map ( | & value| SwitchIntTarget { value , target : block } ) ;
118
+
119
+ let mut tmp = analysis . bottom_value ( body ) ;
120
+ for target in targets {
121
+ tmp . clone_from ( & exit_state ) ;
122
+ analysis . apply_switch_int_edge_effect ( & mut data , & mut tmp , target ) ;
123
+ propagate ( pred, & tmp ) ;
124
+ }
125
+ } else {
130
126
propagate ( pred, exit_state)
131
127
}
132
128
}
@@ -245,37 +241,6 @@ impl Direction for Backward {
245
241
}
246
242
}
247
243
248
- struct BackwardSwitchIntEdgeEffectsApplier < ' mir , ' tcx , D , F > {
249
- body : & ' mir mir:: Body < ' tcx > ,
250
- pred : BasicBlock ,
251
- exit_state : & ' mir mut D ,
252
- block : BasicBlock ,
253
- propagate : & ' mir mut F ,
254
- effects_applied : bool ,
255
- }
256
-
257
- impl < D , F > super :: SwitchIntEdgeEffects < D > for BackwardSwitchIntEdgeEffectsApplier < ' _ , ' _ , D , F >
258
- where
259
- D : Clone ,
260
- F : FnMut ( BasicBlock , & D ) ,
261
- {
262
- fn apply ( & mut self , mut apply_edge_effect : impl FnMut ( & mut D , SwitchIntTarget ) ) {
263
- assert ! ( !self . effects_applied) ;
264
-
265
- let values = & self . body . basic_blocks . switch_sources ( ) [ & ( self . block , self . pred ) ] ;
266
- let targets = values. iter ( ) . map ( |& value| SwitchIntTarget { value, target : self . block } ) ;
267
-
268
- let mut tmp = None ;
269
- for target in targets {
270
- let tmp = opt_clone_from_or_clone ( & mut tmp, self . exit_state ) ;
271
- apply_edge_effect ( tmp, target) ;
272
- ( self . propagate ) ( self . pred , tmp) ;
273
- }
274
-
275
- self . effects_applied = true ;
276
- }
277
- }
278
-
279
244
/// Dataflow that runs from the entry of a block (the first statement), to its exit (terminator).
280
245
pub struct Forward ;
281
246
@@ -284,7 +249,7 @@ impl Direction for Forward {
284
249
285
250
fn apply_effects_in_block < ' mir , ' tcx , A > (
286
251
analysis : & mut A ,
287
- _body : & mir:: Body < ' tcx > ,
252
+ body : & mir:: Body < ' tcx > ,
288
253
state : & mut A :: Domain ,
289
254
block : BasicBlock ,
290
255
block_data : & ' mir mir:: BasicBlockData < ' tcx > ,
@@ -324,23 +289,28 @@ impl Direction for Forward {
324
289
}
325
290
}
326
291
TerminatorEdges :: SwitchInt { targets, discr } => {
327
- let mut applier = ForwardSwitchIntEdgeEffectsApplier {
328
- exit_state,
329
- targets,
330
- propagate,
331
- effects_applied : false ,
332
- } ;
333
-
334
- analysis. apply_switch_int_edge_effects ( block, discr, & mut applier) ;
335
-
336
- let ForwardSwitchIntEdgeEffectsApplier {
337
- exit_state,
338
- mut propagate,
339
- effects_applied,
340
- ..
341
- } = applier;
342
-
343
- if !effects_applied {
292
+ if let Some ( mut data) = analysis. get_switch_int_data ( block, discr) {
293
+ let mut tmp = analysis. bottom_value ( body) ;
294
+ for ( value, target) in targets. iter ( ) {
295
+ tmp. clone_from ( & exit_state) ;
296
+ analysis. apply_switch_int_edge_effect (
297
+ & mut data,
298
+ & mut tmp,
299
+ SwitchIntTarget { value : Some ( value) , target } ,
300
+ ) ;
301
+ propagate ( target, & tmp) ;
302
+ }
303
+
304
+ // Once we get to the final, "otherwise" branch, there is no need to preserve
305
+ // `exit_state`, so pass it directly to `apply_switch_int_edge_effect` to save
306
+ // a clone of the dataflow state.
307
+ let otherwise = targets. otherwise ( ) ;
308
+ analysis. apply_switch_int_edge_effect ( & mut data, exit_state, SwitchIntTarget {
309
+ value : None ,
310
+ target : otherwise,
311
+ } ) ;
312
+ propagate ( otherwise, exit_state) ;
313
+ } else {
344
314
for target in targets. all_targets ( ) {
345
315
propagate ( * target, exit_state) ;
346
316
}
@@ -454,54 +424,3 @@ impl Direction for Forward {
454
424
vis. visit_block_end ( state) ;
455
425
}
456
426
}
457
-
458
- struct ForwardSwitchIntEdgeEffectsApplier < ' mir , D , F > {
459
- exit_state : & ' mir mut D ,
460
- targets : & ' mir SwitchTargets ,
461
- propagate : F ,
462
-
463
- effects_applied : bool ,
464
- }
465
-
466
- impl < D , F > super :: SwitchIntEdgeEffects < D > for ForwardSwitchIntEdgeEffectsApplier < ' _ , D , F >
467
- where
468
- D : Clone ,
469
- F : FnMut ( BasicBlock , & D ) ,
470
- {
471
- fn apply ( & mut self , mut apply_edge_effect : impl FnMut ( & mut D , SwitchIntTarget ) ) {
472
- assert ! ( !self . effects_applied) ;
473
-
474
- let mut tmp = None ;
475
- for ( value, target) in self . targets . iter ( ) {
476
- let tmp = opt_clone_from_or_clone ( & mut tmp, self . exit_state ) ;
477
- apply_edge_effect ( tmp, SwitchIntTarget { value : Some ( value) , target } ) ;
478
- ( self . propagate ) ( target, tmp) ;
479
- }
480
-
481
- // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`,
482
- // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state.
483
- let otherwise = self . targets . otherwise ( ) ;
484
- apply_edge_effect ( self . exit_state , SwitchIntTarget { value : None , target : otherwise } ) ;
485
- ( self . propagate ) ( otherwise, self . exit_state ) ;
486
-
487
- self . effects_applied = true ;
488
- }
489
- }
490
-
491
- /// An analogue of `Option::get_or_insert_with` that stores a clone of `val` into `opt`, but uses
492
- /// the more efficient `clone_from` if `opt` was `Some`.
493
- ///
494
- /// Returns a mutable reference to the new clone that resides in `opt`.
495
- //
496
- // FIXME: Figure out how to express this using `Option::clone_from`, or maybe lift it into the
497
- // standard library?
498
- fn opt_clone_from_or_clone < ' a , T : Clone > ( opt : & ' a mut Option < T > , val : & T ) -> & ' a mut T {
499
- if opt. is_some ( ) {
500
- let ret = opt. as_mut ( ) . unwrap ( ) ;
501
- ret. clone_from ( val) ;
502
- ret
503
- } else {
504
- * opt = Some ( val. clone ( ) ) ;
505
- opt. as_mut ( ) . unwrap ( )
506
- }
507
- }
0 commit comments