@@ -86,46 +86,37 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
8686 // Clone dominators as we need them while mutating the body.
8787 let dominators = body. basic_blocks . dominators ( ) . clone ( ) ;
8888
89- let mut state = VnState :: new ( tcx, param_env, & body. local_decls ) ;
89+ let mut state = VnState :: new ( tcx, param_env, & ssa , & dominators , & body. local_decls ) ;
9090 for arg in body. args_iter ( ) {
9191 if ssa. is_ssa ( arg) {
9292 let value = state. new_opaque ( ) . unwrap ( ) ;
9393 state. assign ( arg, value) ;
9494 }
9595 }
9696
97- for ( local, rvalue, _ ) in ssa . assignments ( body ) {
98- let value = state. insert_rvalue ( rvalue) . or_else ( || state. new_opaque ( ) ) . unwrap ( ) ;
97+ ssa . for_each_assignment_mut ( & mut body . basic_blocks , | local, rvalue, location| {
98+ let value = state. simplify_rvalue ( rvalue, location ) . or_else ( || state. new_opaque ( ) ) . unwrap ( ) ;
9999 // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark `local` as
100100 // reusable if we have an exact type match.
101101 if state. local_decls [ local] . ty == rvalue. ty ( state. local_decls , tcx) {
102102 state. assign ( local, value) ;
103103 }
104- }
104+ } ) ;
105105
106106 // Stop creating opaques during replacement as it is useless.
107107 state. next_opaque = None ;
108108
109- let mut any_replacement = false ;
110- let mut replacer = Replacer {
111- tcx,
112- ssa,
113- dominators,
114- state,
115- reused_locals : BitSet :: new_empty ( body. local_decls . len ( ) ) ,
116- any_replacement : & mut any_replacement,
117- } ;
118-
119109 let reverse_postorder = body. basic_blocks . reverse_postorder ( ) . to_vec ( ) ;
120110 for bb in reverse_postorder {
121111 let data = & mut body. basic_blocks . as_mut_preserves_cfg ( ) [ bb] ;
122- replacer . visit_basic_block_data ( bb, data) ;
112+ state . visit_basic_block_data ( bb, data) ;
123113 }
114+ let any_replacement = state. any_replacement ;
124115
125116 // For each local that is reused (`y` above), we remove its storage statements do avoid any
126117 // difficulty. Those locals are SSA, so should be easy to optimize by LLVM without storage
127118 // statements.
128- StorageRemover { tcx, reused_locals : replacer . reused_locals } . visit_body_preserves_cfg ( body) ;
119+ StorageRemover { tcx, reused_locals : state . reused_locals } . visit_body_preserves_cfg ( body) ;
129120
130121 if any_replacement {
131122 crate :: simplify:: remove_unused_definitions ( body) ;
@@ -189,12 +180,18 @@ struct VnState<'body, 'tcx> {
189180 /// Counter to generate different values.
190181 /// This is an option to stop creating opaques during replacement.
191182 next_opaque : Option < usize > ,
183+ ssa : & ' body SsaLocals ,
184+ dominators : & ' body Dominators < BasicBlock > ,
185+ reused_locals : BitSet < Local > ,
186+ any_replacement : bool ,
192187}
193188
194189impl < ' body , ' tcx > VnState < ' body , ' tcx > {
195190 fn new (
196191 tcx : TyCtxt < ' tcx > ,
197192 param_env : ty:: ParamEnv < ' tcx > ,
193+ ssa : & ' body SsaLocals ,
194+ dominators : & ' body Dominators < BasicBlock > ,
198195 local_decls : & ' body LocalDecls < ' tcx > ,
199196 ) -> Self {
200197 VnState {
@@ -205,6 +202,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
205202 rev_locals : FxHashMap :: default ( ) ,
206203 values : FxIndexSet :: default ( ) ,
207204 next_opaque : Some ( 0 ) ,
205+ ssa,
206+ dominators,
207+ reused_locals : BitSet :: new_empty ( local_decls. len ( ) ) ,
208+ any_replacement : false ,
208209 }
209210 }
210211
@@ -252,10 +253,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
252253
253254 /// Represent the *value* which would be read from `place`.
254255 #[ instrument( level = "trace" , skip( self ) , ret) ]
255- fn insert_place ( & mut self , place : Place < ' tcx > ) -> Option < VnIndex > {
256+ fn simplify_place ( & mut self , place : & mut Place < ' tcx > , location : Location ) -> Option < VnIndex > {
257+ // Another place that holds the same value.
258+ let mut place_ref = place. as_ref ( ) ;
256259 let mut value = self . locals [ place. local ] ?;
257260
258261 for ( index, proj) in place. projection . iter ( ) . enumerate ( ) {
262+ if let Some ( local) = self . try_as_local ( value, location) {
263+ place_ref = PlaceRef { local, projection : & place. projection [ index..] } ;
264+ }
265+
259266 let proj = match proj {
260267 ProjectionElem :: Deref => {
261268 let ty = Place :: ty_from (
@@ -293,31 +300,65 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
293300 value = self . insert ( Value :: Projection ( value, proj) ) ;
294301 }
295302
303+ if let Some ( local) = self . try_as_local ( value, location)
304+ && local != place. local
305+ {
306+ * place = local. into ( ) ;
307+ self . reused_locals . insert ( local) ;
308+ self . any_replacement = true ;
309+ } else if place_ref. local != place. local
310+ || place_ref. projection . len ( ) < place. projection . len ( )
311+ {
312+ * place = place_ref. project_deeper ( & [ ] , self . tcx ) ;
313+ self . reused_locals . insert ( place_ref. local ) ;
314+ self . any_replacement = true ;
315+ }
316+
296317 Some ( value)
297318 }
298319
299320 #[ instrument( level = "trace" , skip( self ) , ret) ]
300- fn insert_operand ( & mut self , operand : & Operand < ' tcx > ) -> Option < VnIndex > {
321+ fn simplify_operand (
322+ & mut self ,
323+ operand : & mut Operand < ' tcx > ,
324+ location : Location ,
325+ ) -> Option < VnIndex > {
301326 match * operand {
302327 Operand :: Constant ( ref constant) => Some ( self . insert ( Value :: Constant ( constant. const_ ) ) ) ,
303- Operand :: Copy ( place) | Operand :: Move ( place) => self . insert_place ( place) ,
328+ Operand :: Copy ( ref mut place) | Operand :: Move ( ref mut place) => {
329+ let value = self . simplify_place ( place, location) ?;
330+ if let Some ( const_) = self . try_as_constant ( value) {
331+ * operand = Operand :: Constant ( Box :: new ( const_) ) ;
332+ self . any_replacement = true ;
333+ }
334+ Some ( value)
335+ }
304336 }
305337 }
306338
307339 #[ instrument( level = "trace" , skip( self ) , ret) ]
308- fn insert_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > ) -> Option < VnIndex > {
340+ fn simplify_rvalue (
341+ & mut self ,
342+ rvalue : & mut Rvalue < ' tcx > ,
343+ location : Location ,
344+ ) -> Option < VnIndex > {
309345 let value = match * rvalue {
310346 // Forward values.
311- Rvalue :: Use ( ref operand) => return self . insert_operand ( operand) ,
312- Rvalue :: CopyForDeref ( place) => return self . insert_operand ( & Operand :: Copy ( place) ) ,
347+ Rvalue :: Use ( ref mut operand) => return self . simplify_operand ( operand, location) ,
348+ Rvalue :: CopyForDeref ( place) => {
349+ let mut operand = Operand :: Copy ( place) ;
350+ let val = self . simplify_operand ( & mut operand, location) ;
351+ * rvalue = Rvalue :: Use ( operand) ;
352+ return val;
353+ }
313354
314355 // Roots.
315- Rvalue :: Repeat ( ref op, amount) => {
316- let op = self . insert_operand ( op) ?;
356+ Rvalue :: Repeat ( ref mut op, amount) => {
357+ let op = self . simplify_operand ( op, location ) ?;
317358 Value :: Repeat ( op, amount)
318359 }
319360 Rvalue :: NullaryOp ( op, ty) => Value :: NullaryOp ( op, ty) ,
320- Rvalue :: Aggregate ( box ref kind, ref fields) => {
361+ Rvalue :: Aggregate ( box ref kind, ref mut fields) => {
321362 let variant_index = match * kind {
322363 AggregateKind :: Array ( ..)
323364 | AggregateKind :: Tuple
@@ -328,40 +369,40 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
328369 AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return None ,
329370 } ;
330371 let fields: Option < Vec < _ > > = fields
331- . iter ( )
332- . map ( |op| self . insert_operand ( op) . or_else ( || self . new_opaque ( ) ) )
372+ . iter_mut ( )
373+ . map ( |op| self . simplify_operand ( op, location ) . or_else ( || self . new_opaque ( ) ) )
333374 . collect ( ) ;
334375 let ty = rvalue. ty ( self . local_decls , self . tcx ) ;
335376 Value :: Aggregate ( ty, variant_index, fields?)
336377 }
337378 Rvalue :: Ref ( .., place) | Rvalue :: AddressOf ( _, place) => return self . new_pointer ( place) ,
338379
339380 // Operations.
340- Rvalue :: Len ( place) => {
341- let place = self . insert_place ( place) ?;
381+ Rvalue :: Len ( ref mut place) => {
382+ let place = self . simplify_place ( place, location ) ?;
342383 Value :: Len ( place)
343384 }
344- Rvalue :: Cast ( kind, ref value, to) => {
385+ Rvalue :: Cast ( kind, ref mut value, to) => {
345386 let from = value. ty ( self . local_decls , self . tcx ) ;
346- let value = self . insert_operand ( value) ?;
387+ let value = self . simplify_operand ( value, location ) ?;
347388 Value :: Cast { kind, value, from, to }
348389 }
349- Rvalue :: BinaryOp ( op, box ( ref lhs, ref rhs) ) => {
350- let lhs = self . insert_operand ( lhs) ? ;
351- let rhs = self . insert_operand ( rhs) ? ;
352- Value :: BinaryOp ( op, lhs, rhs)
390+ Rvalue :: BinaryOp ( op, box ( ref mut lhs, ref mut rhs) ) => {
391+ let lhs = self . simplify_operand ( lhs, location ) ;
392+ let rhs = self . simplify_operand ( rhs, location ) ;
393+ Value :: BinaryOp ( op, lhs? , rhs? )
353394 }
354- Rvalue :: CheckedBinaryOp ( op, box ( ref lhs, ref rhs) ) => {
355- let lhs = self . insert_operand ( lhs) ? ;
356- let rhs = self . insert_operand ( rhs) ? ;
357- Value :: CheckedBinaryOp ( op, lhs, rhs)
395+ Rvalue :: CheckedBinaryOp ( op, box ( ref mut lhs, ref mut rhs) ) => {
396+ let lhs = self . simplify_operand ( lhs, location ) ;
397+ let rhs = self . simplify_operand ( rhs, location ) ;
398+ Value :: CheckedBinaryOp ( op, lhs? , rhs? )
358399 }
359- Rvalue :: UnaryOp ( op, ref arg) => {
360- let arg = self . insert_operand ( arg) ?;
400+ Rvalue :: UnaryOp ( op, ref mut arg) => {
401+ let arg = self . simplify_operand ( arg, location ) ?;
361402 Value :: UnaryOp ( op, arg)
362403 }
363- Rvalue :: Discriminant ( place) => {
364- let place = self . insert_place ( place) ?;
404+ Rvalue :: Discriminant ( ref mut place) => {
405+ let place = self . simplify_place ( place, location ) ?;
365406 Value :: Discriminant ( place)
366407 }
367408
@@ -373,22 +414,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
373414 }
374415}
375416
376- struct Replacer < ' a , ' tcx > {
377- tcx : TyCtxt < ' tcx > ,
378- ssa : SsaLocals ,
379- dominators : Dominators < BasicBlock > ,
380- state : VnState < ' a , ' tcx > ,
381- /// Set of locals that are reused, and for which we should remove storage statements to avoid a
382- /// use-after-StorageDead.
383- reused_locals : BitSet < Local > ,
384- any_replacement : & ' a mut bool ,
385- }
386-
387- impl < ' tcx > Replacer < ' _ , ' tcx > {
417+ impl < ' tcx > VnState < ' _ , ' tcx > {
388418 /// If `index` is a `Value::Constant`, return the `Constant` to be put in the MIR.
389419 fn try_as_constant ( & mut self , index : VnIndex ) -> Option < ConstOperand < ' tcx > > {
390- if let Value :: Constant ( const_) = self . state . get ( index) {
391- Some ( ConstOperand { span : rustc_span:: DUMMY_SP , user_ty : None , const_ : const_ . clone ( ) } )
420+ if let Value :: Constant ( const_) = * self . get ( index) {
421+ Some ( ConstOperand { span : rustc_span:: DUMMY_SP , user_ty : None , const_ } )
392422 } else {
393423 None
394424 }
@@ -397,50 +427,37 @@ impl<'tcx> Replacer<'_, 'tcx> {
397427 /// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`,
398428 /// return it.
399429 fn try_as_local ( & mut self , index : VnIndex , loc : Location ) -> Option < Local > {
400- let other = self . state . rev_locals . get ( & index) ?;
430+ let other = self . rev_locals . get ( & index) ?;
401431 other
402432 . iter ( )
403433 . copied ( )
404- . find ( |& other| self . ssa . assignment_dominates ( & self . dominators , other, loc) )
434+ . find ( |& other| self . ssa . assignment_dominates ( self . dominators , other, loc) )
405435 }
406436}
407437
408- impl < ' tcx > MutVisitor < ' tcx > for Replacer < ' _ , ' tcx > {
438+ impl < ' tcx > MutVisitor < ' tcx > for VnState < ' _ , ' tcx > {
409439 fn tcx ( & self ) -> TyCtxt < ' tcx > {
410440 self . tcx
411441 }
412442
413443 fn visit_operand ( & mut self , operand : & mut Operand < ' tcx > , location : Location ) {
414- if let Some ( place) = operand. place ( )
415- && let Some ( value) = self . state . insert_place ( place)
416- {
417- if let Some ( const_) = self . try_as_constant ( value) {
418- * operand = Operand :: Constant ( Box :: new ( const_) ) ;
419- * self . any_replacement = true ;
420- } else if let Some ( local) = self . try_as_local ( value, location)
421- && * operand != Operand :: Move ( local. into ( ) )
422- {
423- * operand = Operand :: Copy ( local. into ( ) ) ;
424- self . reused_locals . insert ( local) ;
425- * self . any_replacement = true ;
426- }
427- }
444+ self . simplify_operand ( operand, location) ;
428445 }
429446
430447 fn visit_statement ( & mut self , stmt : & mut Statement < ' tcx > , location : Location ) {
431448 self . super_statement ( stmt, location) ;
432449 if let StatementKind :: Assign ( box ( _, ref mut rvalue) ) = stmt. kind
433- && let Some ( value) = self . state . insert_rvalue ( rvalue)
450+ && let Some ( value) = self . simplify_rvalue ( rvalue, location )
434451 {
435452 if let Some ( const_) = self . try_as_constant ( value) {
436453 * rvalue = Rvalue :: Use ( Operand :: Constant ( Box :: new ( const_) ) ) ;
437- * self . any_replacement = true ;
454+ self . any_replacement = true ;
438455 } else if let Some ( local) = self . try_as_local ( value, location)
439456 && * rvalue != Rvalue :: Use ( Operand :: Move ( local. into ( ) ) )
440457 {
441458 * rvalue = Rvalue :: Use ( Operand :: Copy ( local. into ( ) ) ) ;
442459 self . reused_locals . insert ( local) ;
443- * self . any_replacement = true ;
460+ self . any_replacement = true ;
444461 }
445462 }
446463 }
0 commit comments