@@ -79,6 +79,7 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
7979 #[ instrument( level = "trace" , skip( self , tcx, body) ) ]
8080 fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
8181 debug ! ( def_id = ?body. source. def_id( ) ) ;
82+ move_to_copy_pointers ( tcx, body) ;
8283 while propagate_ssa ( tcx, body) { }
8384 }
8485
@@ -87,11 +88,43 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
8788 }
8889}
8990
91+ /// The SSA analysis done by [`SsaLocals`] treats [`Operand::Move`] as a read, even though in
92+ /// general [`Operand::Move`] represents pass-by-pointer where the callee can overwrite the
93+ /// pointee (Miri always considers the place deinitialized). CopyProp has a similar trick to
94+ /// turn [`Operand::Move`] into [`Operand::Copy`] when required for an optimization, but in this
95+ /// pass we just turn all moves of pointers into copies because pointers should be by-value anyway.
96+ fn move_to_copy_pointers < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
97+ let mut visitor = MoveToCopyVisitor { tcx, local_decls : & body. local_decls } ;
98+ for ( bb, data) in body. basic_blocks . as_mut_preserves_cfg ( ) . iter_enumerated_mut ( ) {
99+ visitor. visit_basic_block_data ( bb, data) ;
100+ }
101+
102+ struct MoveToCopyVisitor < ' a , ' tcx > {
103+ tcx : TyCtxt < ' tcx > ,
104+ local_decls : & ' a IndexVec < Local , LocalDecl < ' tcx > > ,
105+ }
106+
107+ impl < ' a , ' tcx > MutVisitor < ' tcx > for MoveToCopyVisitor < ' a , ' tcx > {
108+ fn tcx ( & self ) -> TyCtxt < ' tcx > {
109+ self . tcx
110+ }
111+
112+ fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , loc : Location ) {
113+ if let Operand :: Move ( place) = * operand {
114+ if place. ty ( self . local_decls , self . tcx ) . ty . is_any_ptr ( ) {
115+ * operand = Operand :: Copy ( place) ;
116+ }
117+ }
118+ self . super_operand ( operand, loc) ;
119+ }
120+ }
121+ }
122+
90123fn propagate_ssa < ' tcx > ( tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) -> bool {
91124 let typing_env = body. typing_env ( tcx) ;
92125 let ssa = SsaLocals :: new ( tcx, body, typing_env) ;
93126
94- let mut replacer = compute_replacement ( tcx, body, & ssa) ;
127+ let mut replacer = compute_replacement ( tcx, body, ssa) ;
95128 debug ! ( ?replacer. targets) ;
96129 debug ! ( ?replacer. allowed_replacements) ;
97130 debug ! ( ?replacer. storage_to_remove) ;
@@ -119,7 +152,7 @@ enum Value<'tcx> {
119152fn compute_replacement < ' tcx > (
120153 tcx : TyCtxt < ' tcx > ,
121154 body : & Body < ' tcx > ,
122- ssa : & SsaLocals ,
155+ ssa : SsaLocals ,
123156) -> Replacer < ' tcx > {
124157 let always_live_locals = always_storage_live_locals ( body) ;
125158
@@ -138,7 +171,7 @@ fn compute_replacement<'tcx>(
138171 // reborrowed references.
139172 let mut storage_to_remove = DenseBitSet :: new_empty ( body. local_decls . len ( ) ) ;
140173
141- let fully_replaceable_locals = fully_replaceable_locals ( ssa) ;
174+ let fully_replaceable_locals = fully_replaceable_locals ( & ssa) ;
142175
143176 // Returns true iff we can use `place` as a pointee.
144177 //
0 commit comments