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 } ;
@@ -115,18 +113,18 @@ impl Direction for Backward {
115113 }
116114
117115 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 {
116+ if let Some ( mut data ) = analysis . get_switch_int_data ( block , discr ) {
117+ let values = & body. basic_blocks . switch_sources ( ) [ & ( block , pred ) ] ;
118+ let targets =
119+ values . iter ( ) . map ( | & value| SwitchIntTarget { value , target : block } ) ;
120+
121+ let mut tmp = analysis . bottom_value ( body ) ;
122+ for target in targets {
123+ tmp . clone_from ( & exit_state ) ;
124+ analysis . apply_switch_int_edge_effect ( & mut data , & mut tmp , target ) ;
125+ propagate ( pred, & tmp ) ;
126+ }
127+ } else {
130128 propagate ( pred, exit_state)
131129 }
132130 }
@@ -245,37 +243,6 @@ impl Direction for Backward {
245243 }
246244}
247245
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-
279246/// Dataflow that runs from the entry of a block (the first statement), to its exit (terminator).
280247pub struct Forward ;
281248
@@ -284,7 +251,7 @@ impl Direction for Forward {
284251
285252 fn apply_effects_in_block < ' mir , ' tcx , A > (
286253 analysis : & mut A ,
287- _body : & mir:: Body < ' tcx > ,
254+ body : & mir:: Body < ' tcx > ,
288255 state : & mut A :: Domain ,
289256 block : BasicBlock ,
290257 block_data : & ' mir mir:: BasicBlockData < ' tcx > ,
@@ -324,23 +291,28 @@ impl Direction for Forward {
324291 }
325292 }
326293 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 {
294+ if let Some ( mut data) = analysis. get_switch_int_data ( block, discr) {
295+ let mut tmp = analysis. bottom_value ( body) ;
296+ for ( value, target) in targets. iter ( ) {
297+ tmp. clone_from ( & exit_state) ;
298+ analysis. apply_switch_int_edge_effect (
299+ & mut data,
300+ & mut tmp,
301+ SwitchIntTarget { value : Some ( value) , target } ,
302+ ) ;
303+ propagate ( target, & tmp) ;
304+ }
305+
306+ // Once we get to the final, "otherwise" branch, there is no need to preserve
307+ // `exit_state`, so pass it directly to `apply_switch_int_edge_effect` to save
308+ // a clone of the dataflow state.
309+ let otherwise = targets. otherwise ( ) ;
310+ analysis. apply_switch_int_edge_effect ( & mut data, exit_state, SwitchIntTarget {
311+ value : None ,
312+ target : otherwise,
313+ } ) ;
314+ propagate ( otherwise, exit_state) ;
315+ } else {
344316 for target in targets. all_targets ( ) {
345317 propagate ( * target, exit_state) ;
346318 }
@@ -454,54 +426,3 @@ impl Direction for Forward {
454426 vis. visit_block_end ( state) ;
455427 }
456428}
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