140140use  rustc_data_structures:: fx:: FxIndexMap ; 
141141use  rustc_index:: bit_set:: DenseBitSet ; 
142142use  rustc_index:: interval:: SparseIntervalMatrix ; 
143- use  rustc_index:: { IndexSlice ,   IndexVec ,  newtype_index} ; 
143+ use  rustc_index:: { IndexVec ,  newtype_index} ; 
144144use  rustc_middle:: mir:: visit:: { MutVisitor ,  NonMutatingUseContext ,  PlaceContext ,  Visitor } ; 
145145use  rustc_middle:: mir:: * ; 
146146use  rustc_middle:: ty:: TyCtxt ; 
147- use  rustc_mir_dataflow:: impls:: DefUse ; 
147+ use  rustc_mir_dataflow:: impls:: { DefUse ,   MaybeLiveLocals } ; 
148148use  rustc_mir_dataflow:: points:: { DenseLocationMap ,  PointIndex } ; 
149- use  rustc_mir_dataflow:: { Analysis ,  Backward ,   Results } ; 
149+ use  rustc_mir_dataflow:: { Analysis ,  Results } ; 
150150use  tracing:: { debug,  trace} ; 
151151
152152pub ( super )  struct  DestinationPropagation ; 
@@ -169,12 +169,11 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
169169            return ; 
170170        } 
171171
172-         let  live =
173-             MaybeTwoStepLiveLocals . iterate_to_fixpoint ( tcx,  body,  Some ( "MaybeLiveLocals-DestProp" ) ) ; 
172+         let  live = MaybeLiveLocals . iterate_to_fixpoint ( tcx,  body,  Some ( "MaybeLiveLocals-DestProp" ) ) ; 
174173
175174        let  points = DenseLocationMap :: new ( body) ; 
176175        let  mut  relevant = RelevantLocals :: compute ( & candidates,  body. local_decls . len ( ) ) ; 
177-         let  mut  live = save_as_intervals ( & points,  body,  & relevant. original ,  live. results ) ; 
176+         let  mut  live = save_as_intervals ( & points,  body,  & relevant,  live. results ) ; 
178177
179178        dest_prop_mir_dump ( tcx,  body,  & points,  & live,  & relevant) ; 
180179
@@ -515,8 +514,6 @@ fn dest_prop_mir_dump<'tcx>(
515514    } ) ; 
516515} 
517516
518- struct  MaybeTwoStepLiveLocals ; 
519- 
520517#[ derive( Copy ,  Clone ,  Debug ) ]  
521518enum  Effect  { 
522519    Before , 
@@ -567,137 +564,29 @@ where
567564    } 
568565} 
569566
570- impl < ' tcx >  Analysis < ' tcx >  for  MaybeTwoStepLiveLocals  { 
571-     type  Domain  = DenseBitSet < Local > ; 
572-     type  Direction  = Backward ; 
573- 
574-     const  NAME :  & ' static  str  = "transitive liveness" ; 
575- 
576-     fn  bottom_value ( & self ,  body :  & Body < ' tcx > )  -> DenseBitSet < Local >  { 
577-         // bottom = not live 
578-         DenseBitSet :: new_empty ( body. local_decls . len ( ) ) 
579-     } 
580- 
581-     fn  initialize_start_block ( & self ,  _:  & Body < ' tcx > ,  _:  & mut  DenseBitSet < Local > )  { 
582-         // No variables are live until we observe a use 
583-     } 
584- 
585-     // This happens between the previous statement and this one. 
586-     #[ tracing:: instrument( level = "trace" ,  skip( self ,  statement) ) ]  
587-     fn  apply_primary_statement_effect ( 
588-         & mut  self , 
589-         state :  & mut  DenseBitSet < Local > , 
590-         statement :  & Statement < ' tcx > , 
591-         location :  Location , 
592-     )  { 
593-         VisitPlacesWith ( |place,  ctxt| match  DefUse :: for_place ( place,  ctxt)  { 
594-             DefUse :: Def  => { 
595-                 state. remove ( place. local ) ; 
596-             } 
597-             DefUse :: Use  => { 
598-                 state. insert ( place. local ) ; 
599-             } 
600-             DefUse :: PartialWrite  | DefUse :: NonUse  => { } 
601-         } ) 
602-         . visit_statement ( statement,  location) ; 
603-     } 
604- 
605-     // This happens between this statement and the next one. 
606-     #[ tracing:: instrument( level = "trace" ,  skip( self ,  statement) ) ]  
607-     fn  apply_early_statement_effect ( 
608-         & mut  self , 
609-         state :  & mut  DenseBitSet < Local > , 
610-         statement :  & Statement < ' tcx > , 
611-         location :  Location , 
612-     )  { 
613-         // We need to ensure we have a non-zero live range even for dead stores. This is done by 
614-         // marking all the writes locals as live in the second half of the statement. 
615-         VisitPlacesWith ( |place :  Place < ' tcx > ,  ctxt| match  DefUse :: for_place ( place,  ctxt)  { 
616-             DefUse :: Def  | DefUse :: PartialWrite  => { 
617-                 state. insert ( place. local ) ; 
618-             } 
619-             // We already perform the reads in the first part of the statement. As statements are 
620-             // not splittable, we do not need to re-read the same values. 
621-             DefUse :: Use  | DefUse :: NonUse  => { } 
622-         } ) 
623-         . visit_statement ( statement,  location) ; 
624-     } 
625- 
626-     // We model terminator as a special case in this two-step analysis. Consider the terminator 
627-     // `destination = func(arg0...)`. 
628-     // 
629-     // -- state at (location, Effect::Before) 
630-     // read(arg0)... 
631-     // write(destination) 
632-     // -- state at (location, Effect::After) 
633-     // read(arg0)... 
634- 
635-     // This happens between the last statement and the terminator. 
636-     #[ tracing:: instrument( level = "trace" ,  skip( self ,  terminator) ) ]  
637-     fn  apply_primary_terminator_effect < ' mir > ( 
638-         & mut  self , 
639-         state :  & mut  DenseBitSet < Local > , 
640-         terminator :  & ' mir  Terminator < ' tcx > , 
641-         location :  Location , 
642-     )  -> TerminatorEdges < ' mir ,  ' tcx >  { 
643-         // Consider that all writes in this terminator happen at the start of the execution of the 
644-         // terminator. For instance if we pass a return-pointer to a `Call` terminator. 
645-         VisitPlacesWith ( |place :  Place < ' tcx > ,  ctxt| match  DefUse :: for_place ( place,  ctxt)  { 
646-             DefUse :: Def  => { 
647-                 state. remove ( place. local ) ; 
648-             } 
649-             DefUse :: Use  => { 
650-                 state. insert ( place. local ) ; 
651-             } 
652-             DefUse :: PartialWrite  | DefUse :: NonUse  => { } 
653-         } ) 
654-         . visit_terminator ( terminator,  location) ; 
655-         terminator. edges ( ) 
656-     } 
657- 
658-     // This happens between the terminator and the end of the block. 
659-     #[ tracing:: instrument( level = "trace" ,  skip( self ,  terminator) ) ]  
660-     fn  apply_early_terminator_effect < ' mir > ( 
661-         & mut  self , 
662-         state :  & mut  DenseBitSet < Local > , 
663-         terminator :  & ' mir  Terminator < ' tcx > , 
664-         location :  Location , 
665-     )  { 
666-         // Consider that all reads in this terminator happen at the end of the execution of the 
667-         // terminator, even after it may have written to the destination local. For instance if we 
668-         // pass arguments as pointers to a `Call` terminator. 
669-         VisitPlacesWith ( |place :  Place < ' tcx > ,  ctxt| match  DefUse :: for_place ( place,  ctxt)  { 
670-             DefUse :: Def  | DefUse :: Use  | DefUse :: PartialWrite  => { 
671-                 state. insert ( place. local ) ; 
672-             } 
673-             DefUse :: NonUse  => { } 
674-         } ) 
675-         . visit_terminator ( terminator,  location) ; 
676-     } 
677- } 
678- 
679567/// Add points depending on the result of the given dataflow analysis. 
680568fn  save_as_intervals < ' tcx > ( 
681569    elements :  & DenseLocationMap , 
682570    body :  & Body < ' tcx > , 
683-     relevant :  & IndexSlice < RelevantLocal ,   Local > , 
571+     relevant :  & RelevantLocals , 
684572    results :  Results < DenseBitSet < Local > > , 
685573)  -> SparseIntervalMatrix < RelevantLocal ,  TwoStepIndex >  { 
686574    let  mut  values = SparseIntervalMatrix :: new ( 2  *  elements. num_points ( ) ) ; 
687-     let  mut  state = MaybeTwoStepLiveLocals . bottom_value ( body) ; 
575+     let  mut  state = MaybeLiveLocals . bottom_value ( body) ; 
688576    let  reachable_blocks = traversal:: reachable_as_bitset ( body) ; 
689577
690578    let  two_step_loc = |location,  effect| { 
691579        let  point = elements. point_from_location ( location) ; 
692580        TwoStepIndex :: new ( point,  effect) 
693581    } ; 
694-     let  mut  prepend_at = |state :  & mut  DenseBitSet < Local > ,  twostep| { 
695-         for  ( relevant,  & original)  in  relevant. iter_enumerated ( )  { 
696-             if  state. contains ( original)  { 
697-                 values. prepend ( relevant,  twostep) ; 
582+     let  prepend_at =
583+         |values :  & mut  SparseIntervalMatrix < _ ,  _ > ,  state :  & DenseBitSet < Local > ,  twostep| { 
584+             for  ( relevant,  & original)  in  relevant. original . iter_enumerated ( )  { 
585+                 if  state. contains ( original)  { 
586+                     values. prepend ( relevant,  twostep) ; 
587+                 } 
698588            } 
699-         } 
700-     } ; 
589+         } ; 
701590
702591    // Iterate blocks in decreasing order, to visit locations in decreasing order. This 
703592    // allows to use the more efficient `prepend` method to interval sets. 
@@ -713,25 +602,51 @@ fn save_as_intervals<'tcx>(
713602
714603        let  term = block_data. terminator ( ) ; 
715604        let  mut  twostep = two_step_loc ( loc,  Effect :: After ) ; 
716-         MaybeTwoStepLiveLocals . apply_early_terminator_effect ( & mut  state,  term,  loc) ; 
717-         prepend_at ( & mut  state,  twostep) ; 
605+         prepend_at ( & mut  values,  & state,  twostep) ; 
606+         // Ensure we have a non-zero live range even for dead stores. This is done by marking all 
607+         // the writes locals as live in the second half of the statement. 
608+         // We also ensure that operands read by terminators conflict with reads by that terminator. 
609+         // For instance a function call may read args after having written to the destination. 
610+         VisitPlacesWith ( |place,  ctxt| match  DefUse :: for_place ( place,  ctxt)  { 
611+             DefUse :: Def  | DefUse :: Use  | DefUse :: PartialWrite  => { 
612+                 if  let  Some ( relevant)  = relevant. shrink [ place. local ]  { 
613+                     values. insert ( relevant,  twostep) ; 
614+                 } 
615+             } 
616+             DefUse :: NonUse  => { } 
617+         } ) 
618+         . visit_terminator ( term,  loc) ; 
718619
719620        twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( )  - 1 ) ; 
720621        debug_assert_eq ! ( twostep,  two_step_loc( loc,  Effect :: Before ) ) ; 
721-         MaybeTwoStepLiveLocals . apply_primary_terminator_effect ( & mut  state,  term,  loc) ; 
722-         prepend_at ( & mut  state,  twostep) ; 
622+         MaybeLiveLocals . apply_early_terminator_effect ( & mut  state,  term,  loc) ; 
623+         MaybeLiveLocals . apply_primary_terminator_effect ( & mut  state,  term,  loc) ; 
624+         prepend_at ( & mut  values,  & state,  twostep) ; 
723625
724626        for  ( statement_index,  stmt)  in  block_data. statements . iter ( ) . enumerate ( ) . rev ( )  { 
725627            let  loc = Location  {  block,  statement_index } ; 
726628            twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( )  - 1 ) ; 
727629            debug_assert_eq ! ( twostep,  two_step_loc( loc,  Effect :: After ) ) ; 
728-             MaybeTwoStepLiveLocals . apply_early_statement_effect ( & mut  state,  stmt,  loc) ; 
729-             prepend_at ( & mut  state,  twostep) ; 
630+             prepend_at ( & mut  values,  & state,  twostep) ; 
631+             // Ensure we have a non-zero live range even for dead stores. This is done by marking 
632+             // all the writes locals as live in the second half of the statement. 
633+             VisitPlacesWith ( |place,  ctxt| match  DefUse :: for_place ( place,  ctxt)  { 
634+                 DefUse :: Def  | DefUse :: PartialWrite  => { 
635+                     if  let  Some ( relevant)  = relevant. shrink [ place. local ]  { 
636+                         values. insert ( relevant,  twostep) ; 
637+                     } 
638+                 } 
639+                 DefUse :: Use  | DefUse :: NonUse  => { } 
640+             } ) 
641+             . visit_statement ( stmt,  loc) ; 
730642
731643            twostep = TwoStepIndex :: from_u32 ( twostep. as_u32 ( )  - 1 ) ; 
732644            debug_assert_eq ! ( twostep,  two_step_loc( loc,  Effect :: Before ) ) ; 
733-             MaybeTwoStepLiveLocals . apply_primary_statement_effect ( & mut  state,  stmt,  loc) ; 
734-             prepend_at ( & mut  state,  twostep) ; 
645+             MaybeLiveLocals . apply_early_statement_effect ( & mut  state,  stmt,  loc) ; 
646+             MaybeLiveLocals . apply_primary_statement_effect ( & mut  state,  stmt,  loc) ; 
647+             // ... but reads from operands are marked as live here so they do not conflict with 
648+             // the all the writes locals as live in the second half of the statement. 
649+             prepend_at ( & mut  values,  & state,  twostep) ; 
735650        } 
736651    } 
737652
0 commit comments