1+ use rustc_data_structures:: fx:: FxIndexMap ;
12use rustc_index:: bit_set:: BitSet ;
23use rustc_index:: IndexSlice ;
34use rustc_middle:: mir:: visit:: * ;
@@ -37,6 +38,8 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
3738
3839 let fully_moved = fully_moved_locals ( & ssa, body) ;
3940 debug ! ( ?fully_moved) ;
41+ let const_locals = const_locals ( & ssa, body) ;
42+ debug ! ( ?const_locals) ;
4043
4144 let mut storage_to_remove = BitSet :: new_empty ( fully_moved. domain_size ( ) ) ;
4245 for ( local, & head) in ssa. copy_classes ( ) . iter_enumerated ( ) {
@@ -51,6 +54,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
5154 tcx,
5255 copy_classes : ssa. copy_classes ( ) ,
5356 fully_moved,
57+ const_locals,
5458 borrowed_locals,
5559 storage_to_remove,
5660 }
@@ -96,10 +100,28 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
96100 fully_moved
97101}
98102
103+ /// Finds all locals that are only assigned to once with a deterministic constant
104+ #[ instrument( level = "trace" , skip( ssa, body) ) ]
105+ fn const_locals < ' body , ' tcx > (
106+ ssa : & ' body SsaLocals ,
107+ body : & ' body Body < ' tcx > ,
108+ ) -> FxIndexMap < Local , ConstOperand < ' tcx > > {
109+ let mut const_locals = FxIndexMap :: default ( ) ;
110+ for ( local, rvalue, _) in ssa. assignments ( body) {
111+ let Rvalue :: Use ( Operand :: Constant ( val) ) = rvalue else { continue } ;
112+ if !val. const_ . is_deterministic ( ) {
113+ continue ;
114+ }
115+ const_locals. insert ( local, * * val) ;
116+ }
117+ const_locals
118+ }
119+
99120/// Utility to help performing substitution of `*pattern` by `target`.
100121struct Replacer < ' a , ' tcx > {
101122 tcx : TyCtxt < ' tcx > ,
102123 fully_moved : BitSet < Local > ,
124+ const_locals : FxIndexMap < Local , ConstOperand < ' tcx > > ,
103125 storage_to_remove : BitSet < Local > ,
104126 borrowed_locals : BitSet < Local > ,
105127 copy_classes : & ' a IndexSlice < Local , Local > ,
@@ -154,9 +176,14 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
154176 if let Operand :: Move ( place) = * operand
155177 // A move out of a projection of a copy is equivalent to a copy of the original projection.
156178 && !place. is_indirect_first_projection ( )
157- && !self . fully_moved . contains ( place. local )
158179 {
159- * operand = Operand :: Copy ( place) ;
180+ if !self . fully_moved . contains ( place. local ) {
181+ * operand = Operand :: Copy ( place) ;
182+ } else if let Some ( local) = place. as_local ( )
183+ && let Some ( val) = self . const_locals . get ( & local)
184+ {
185+ * operand = Operand :: Constant ( Box :: new ( * val) )
186+ }
160187 }
161188 self . super_operand ( operand, loc) ;
162189 }
0 commit comments