1
+ use rustc_data_structures:: fx:: FxIndexMap ;
1
2
use rustc_index:: bit_set:: BitSet ;
2
3
use rustc_index:: IndexSlice ;
3
4
use rustc_middle:: mir:: visit:: * ;
@@ -37,6 +38,8 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
37
38
38
39
let fully_moved = fully_moved_locals ( & ssa, body) ;
39
40
debug ! ( ?fully_moved) ;
41
+ let const_locals = const_locals ( & ssa, body) ;
42
+ debug ! ( ?const_locals) ;
40
43
41
44
let mut storage_to_remove = BitSet :: new_empty ( fully_moved. domain_size ( ) ) ;
42
45
for ( local, & head) in ssa. copy_classes ( ) . iter_enumerated ( ) {
@@ -51,6 +54,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
51
54
tcx,
52
55
copy_classes : ssa. copy_classes ( ) ,
53
56
fully_moved,
57
+ const_locals,
54
58
borrowed_locals,
55
59
storage_to_remove,
56
60
}
@@ -96,10 +100,28 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
96
100
fully_moved
97
101
}
98
102
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
+
99
120
/// Utility to help performing substitution of `*pattern` by `target`.
100
121
struct Replacer < ' a , ' tcx > {
101
122
tcx : TyCtxt < ' tcx > ,
102
123
fully_moved : BitSet < Local > ,
124
+ const_locals : FxIndexMap < Local , ConstOperand < ' tcx > > ,
103
125
storage_to_remove : BitSet < Local > ,
104
126
borrowed_locals : BitSet < Local > ,
105
127
copy_classes : & ' a IndexSlice < Local , Local > ,
@@ -154,9 +176,14 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
154
176
if let Operand :: Move ( place) = * operand
155
177
// A move out of a projection of a copy is equivalent to a copy of the original projection.
156
178
&& !place. is_indirect_first_projection ( )
157
- && !self . fully_moved . contains ( place. local )
158
179
{
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
+ }
160
187
}
161
188
self . super_operand ( operand, loc) ;
162
189
}
0 commit comments