@@ -16,7 +16,7 @@ use crate::ssa::SsaLocals;
1616///   _d = move? _c 
1717/// where each of the locals is only assigned once. 
1818/// 
19- /// We want to replace all those locals by `_a`, either copied or moved . 
19+ /// We want to replace all those locals by `copy  _a`. 
2020pub ( super )  struct  CopyProp ; 
2121
2222impl < ' tcx >  crate :: MirPass < ' tcx >  for  CopyProp  { 
@@ -34,23 +34,21 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
3434        debug ! ( copy_classes = ?ssa. copy_classes( ) ) ; 
3535
3636        let  mut  any_replacement = false ; 
37-         let  mut  storage_to_remove = DenseBitSet :: new_empty ( body. local_decls . len ( ) ) ; 
37+         // Locals that participate in copy propagation either as a source or a destination. 
38+         let  mut  unified = DenseBitSet :: new_empty ( body. local_decls . len ( ) ) ; 
3839        for  ( local,  & head)  in  ssa. copy_classes ( ) . iter_enumerated ( )  { 
3940            if  local != head { 
4041                any_replacement = true ; 
41-                 storage_to_remove. insert ( head) ; 
42+                 unified. insert ( head) ; 
43+                 unified. insert ( local) ; 
4244            } 
4345        } 
4446
4547        if  !any_replacement { 
4648            return ; 
4749        } 
4850
49-         let  fully_moved = fully_moved_locals ( & ssa,  body) ; 
50-         debug ! ( ?fully_moved) ; 
51- 
52-         Replacer  {  tcx,  copy_classes :  ssa. copy_classes ( ) ,  fully_moved,  storage_to_remove } 
53-             . visit_body_preserves_cfg ( body) ; 
51+         Replacer  {  tcx,  copy_classes :  ssa. copy_classes ( ) ,  unified } . visit_body_preserves_cfg ( body) ; 
5452
5553        crate :: simplify:: remove_unused_definitions ( body) ; 
5654    } 
@@ -60,44 +58,10 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
6058    } 
6159} 
6260
63- /// `SsaLocals` computed equivalence classes between locals considering copy/move assignments. 
64- /// 
65- /// This function also returns whether all the `move?` in the pattern are `move` and not copies. 
66- /// A local which is in the bitset can be replaced by `move _a`. Otherwise, it must be 
67- /// replaced by `copy _a`, as we cannot move multiple times from `_a`. 
68- /// 
69- /// If an operand copies `_c`, it must happen before the assignment `_d = _c`, otherwise it is UB. 
70- /// This means that replacing it by a copy of `_a` if ok, since this copy happens before `_c` is 
71- /// moved, and therefore that `_d` is moved. 
72- #[ instrument( level = "trace" ,  skip( ssa,  body) ) ]  
73- fn  fully_moved_locals ( ssa :  & SsaLocals ,  body :  & Body < ' _ > )  -> DenseBitSet < Local >  { 
74-     let  mut  fully_moved = DenseBitSet :: new_filled ( body. local_decls . len ( ) ) ; 
75- 
76-     for  ( _,  rvalue,  _)  in  ssa. assignments ( body)  { 
77-         let  Rvalue :: Use ( Operand :: Copy ( place)  | Operand :: Move ( place) )  = rvalue else  { 
78-             continue ; 
79-         } ; 
80- 
81-         let  Some ( rhs)  = place. as_local ( )  else  {  continue  } ; 
82-         if  !ssa. is_ssa ( rhs)  { 
83-             continue ; 
84-         } 
85- 
86-         if  let  Rvalue :: Use ( Operand :: Copy ( _) )  = rvalue { 
87-             fully_moved. remove ( rhs) ; 
88-         } 
89-     } 
90- 
91-     ssa. meet_copy_equivalence ( & mut  fully_moved) ; 
92- 
93-     fully_moved
94- } 
95- 
9661/// Utility to help performing substitution of `*pattern` by `target`. 
9762struct  Replacer < ' a ,  ' tcx >  { 
9863    tcx :  TyCtxt < ' tcx > , 
99-     fully_moved :  DenseBitSet < Local > , 
100-     storage_to_remove :  DenseBitSet < Local > , 
64+     unified :  DenseBitSet < Local > , 
10165    copy_classes :  & ' a  IndexSlice < Local ,  Local > , 
10266} 
10367
@@ -108,13 +72,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
10872
10973    #[ tracing:: instrument( level = "trace" ,  skip( self ) ) ]  
11074    fn  visit_local ( & mut  self ,  local :  & mut  Local ,  ctxt :  PlaceContext ,  _:  Location )  { 
111-         let  new_local = self . copy_classes [ * local] ; 
112-         match  ctxt { 
113-             // Do not modify the local in storage statements. 
114-             PlaceContext :: NonUse ( NonUseContext :: StorageLive  | NonUseContext :: StorageDead )  => { } 
115-             // We access the value. 
116-             _ => * local = new_local, 
117-         } 
75+         * local = self . copy_classes [ * local] ; 
11876    } 
11977
12078    #[ tracing:: instrument( level = "trace" ,  skip( self ) ) ]  
@@ -123,7 +81,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
12381            // A move out of a projection of a copy is equivalent to a copy of the original 
12482            // projection. 
12583            && !place. is_indirect_first_projection ( ) 
126-             && ! self . fully_moved . contains ( place. local ) 
84+             && self . unified . contains ( place. local ) 
12785        { 
12886            * operand = Operand :: Copy ( place) ; 
12987        } 
@@ -134,10 +92,9 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
13492    fn  visit_statement ( & mut  self ,  stmt :  & mut  Statement < ' tcx > ,  loc :  Location )  { 
13593        // When removing storage statements, we need to remove both (#107511). 
13694        if  let  StatementKind :: StorageLive ( l)  | StatementKind :: StorageDead ( l)  = stmt. kind 
137-             && self . storage_to_remove . contains ( l) 
95+             && self . unified . contains ( l) 
13896        { 
13997            stmt. make_nop ( true ) ; 
140-             return ; 
14198        } 
14299
143100        self . super_statement ( stmt,  loc) ; 
0 commit comments