@@ -101,14 +101,15 @@ impl SsaLocals {
101101 . retain ( |& local| matches ! ( visitor. assignments[ local] , Set1 :: One ( _) ) ) ;
102102 debug ! ( ?visitor. assignment_order) ;
103103
104- let copy_classes = compute_copy_classes ( & mut visitor, body) ;
105-
106- SsaLocals {
104+ let mut ssa = SsaLocals {
107105 assignments : visitor. assignments ,
108106 assignment_order : visitor. assignment_order ,
109107 direct_uses : visitor. direct_uses ,
110- copy_classes,
111- }
108+ // This is filled by `compute_copy_classes`.
109+ copy_classes : IndexVec :: default ( ) ,
110+ } ;
111+ compute_copy_classes ( & mut ssa, body) ;
112+ ssa
112113 }
113114
114115 pub fn num_locals ( & self ) -> usize {
@@ -261,49 +262,54 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor {
261262}
262263
263264#[ instrument( level = "trace" , skip( ssa, body) ) ]
264- fn compute_copy_classes ( ssa : & mut SsaVisitor , body : & Body < ' _ > ) -> IndexVec < Local , Local > {
265+ fn compute_copy_classes ( ssa : & mut SsaLocals , body : & Body < ' _ > ) {
266+ let mut direct_uses = std:: mem:: take ( & mut ssa. direct_uses ) ;
265267 let mut copies = IndexVec :: from_fn_n ( |l| l, body. local_decls . len ( ) ) ;
266268
267- for & local in & ssa. assignment_order {
268- debug ! ( ?local) ;
269-
270- if local == RETURN_PLACE {
271- // `_0` is special, we cannot rename it.
272- continue ;
273- }
274-
275- // This is not SSA: mark that we don't know the value.
276- debug ! ( assignments = ?ssa. assignments[ local] ) ;
277- let Set1 :: One ( LocationExtended :: Plain ( loc) ) = ssa. assignments [ local] else { continue } ;
278-
279- // `loc` must point to a direct assignment to `local`.
280- let Either :: Left ( stmt) = body. stmt_at ( loc) else { bug ! ( ) } ;
281- let Some ( ( _target, rvalue) ) = stmt. kind . as_assign ( ) else { bug ! ( ) } ;
282- assert_eq ! ( _target. as_local( ) , Some ( local) ) ;
283-
269+ for ( local, rvalue, _) in ssa. assignments ( body) {
284270 let ( Rvalue :: Use ( Operand :: Copy ( place) | Operand :: Move ( place) ) | Rvalue :: CopyForDeref ( place) )
285271 = rvalue
286272 else { continue } ;
287273
288274 let Some ( rhs) = place. as_local ( ) else { continue } ;
289- let Set1 :: One ( _) = ssa. assignments [ rhs] else { continue } ;
275+ if !ssa. is_ssa ( rhs) {
276+ continue ;
277+ }
290278
291279 // We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been
292280 // visited before `local`, and we just have to copy the representing local.
293- copies[ local] = copies[ rhs] ;
294- ssa. direct_uses [ rhs] -= 1 ;
281+ let head = copies[ rhs] ;
282+
283+ if local == RETURN_PLACE {
284+ // `_0` is special, we cannot rename it. Instead, rename the class of `rhs` to
285+ // `RETURN_PLACE`. This is only possible if the class head is a temporary, not an
286+ // argument.
287+ if body. local_kind ( head) != LocalKind :: Temp {
288+ continue ;
289+ }
290+ for h in copies. iter_mut ( ) {
291+ if * h == head {
292+ * h = RETURN_PLACE ;
293+ }
294+ }
295+ } else {
296+ copies[ local] = head;
297+ }
298+ direct_uses[ rhs] -= 1 ;
295299 }
296300
297301 debug ! ( ?copies) ;
298- debug ! ( ?ssa . direct_uses) ;
302+ debug ! ( ?direct_uses) ;
299303
300304 // Invariant: `copies` must point to the head of an equivalence class.
301305 #[ cfg( debug_assertions) ]
302306 for & head in copies. iter ( ) {
303307 assert_eq ! ( copies[ head] , head) ;
304308 }
309+ debug_assert_eq ! ( copies[ RETURN_PLACE ] , RETURN_PLACE ) ;
305310
306- copies
311+ ssa. direct_uses = direct_uses;
312+ ssa. copy_classes = copies;
307313}
308314
309315#[ derive( Debug ) ]
0 commit comments