11use std:: ops:: RangeInclusive ;
22
3- use rustc_middle:: mir:: {
4- self , BasicBlock , CallReturnPlaces , Location , SwitchTargets , TerminatorEdges ,
5- } ;
3+ use rustc_middle:: mir:: { self , BasicBlock , CallReturnPlaces , Location , TerminatorEdges } ;
64
75use super :: visitor:: ResultsVisitor ;
86use super :: { Analysis , Effect , EffectIndex , Results , SwitchIntTarget } ;
@@ -78,8 +76,6 @@ impl Direction for Backward {
7876 for pred in body. basic_blocks . predecessors ( ) [ block] . iter ( ) . copied ( ) {
7977 match body[ pred] . terminator ( ) . kind {
8078 // Apply terminator-specific edge effects.
81- //
82- // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
8379 mir:: TerminatorKind :: Call { destination, target : Some ( dest) , .. }
8480 if dest == block =>
8581 {
@@ -115,18 +111,18 @@ impl Direction for Backward {
115111 }
116112
117113 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 {
130126 propagate ( pred, exit_state)
131127 }
132128 }
@@ -245,37 +241,6 @@ impl Direction for Backward {
245241 }
246242}
247243
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-
279244/// Dataflow that runs from the entry of a block (the first statement), to its exit (terminator).
280245pub struct Forward ;
281246
@@ -284,7 +249,7 @@ impl Direction for Forward {
284249
285250 fn apply_effects_in_block < ' mir , ' tcx , A > (
286251 analysis : & mut A ,
287- _body : & mir:: Body < ' tcx > ,
252+ body : & mir:: Body < ' tcx > ,
288253 state : & mut A :: Domain ,
289254 block : BasicBlock ,
290255 block_data : & ' mir mir:: BasicBlockData < ' tcx > ,
@@ -324,23 +289,28 @@ impl Direction for Forward {
324289 }
325290 }
326291 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 {
344314 for target in targets. all_targets ( ) {
345315 propagate ( * target, exit_state) ;
346316 }
@@ -454,54 +424,3 @@ impl Direction for Forward {
454424 vis. visit_block_end ( state) ;
455425 }
456426}
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