1
- use either:: Either ;
2
- use rustc_data_structures:: graph:: dominators:: Dominators ;
3
1
use rustc_index:: bit_set:: BitSet ;
4
2
use rustc_index:: vec:: IndexVec ;
5
- use rustc_middle:: middle:: resolve_lifetime:: Set1 ;
6
3
use rustc_middle:: mir:: visit:: * ;
7
4
use rustc_middle:: mir:: * ;
8
- use rustc_middle:: ty:: { ParamEnv , TyCtxt } ;
9
- use rustc_mir_dataflow:: impls:: borrowed_locals;
5
+ use rustc_middle:: ty:: TyCtxt ;
10
6
7
+ use crate :: ssa:: SsaLocals ;
11
8
use crate :: MirPass ;
12
9
13
10
/// Unify locals that copy each other.
@@ -38,123 +35,28 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
38
35
let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
39
36
let ssa = SsaLocals :: new ( tcx, param_env, body) ;
40
37
41
- let ( copy_classes , fully_moved) = compute_copy_classes ( & ssa, body) ;
42
- debug ! ( ?copy_classes ) ;
38
+ let fully_moved = fully_moved_locals ( & ssa, body) ;
39
+ debug ! ( ?fully_moved ) ;
43
40
44
41
let mut storage_to_remove = BitSet :: new_empty ( fully_moved. domain_size ( ) ) ;
45
- for ( local, & head) in copy_classes. iter_enumerated ( ) {
42
+ for ( local, & head) in ssa . copy_classes ( ) . iter_enumerated ( ) {
46
43
if local != head {
47
44
storage_to_remove. insert ( head) ;
48
45
storage_to_remove. insert ( local) ;
49
46
}
50
47
}
51
48
52
- let any_replacement = copy_classes. iter_enumerated ( ) . any ( |( l, & h) | l != h) ;
49
+ let any_replacement = ssa . copy_classes ( ) . iter_enumerated ( ) . any ( |( l, & h) | l != h) ;
53
50
54
- Replacer { tcx, copy_classes, fully_moved, storage_to_remove } . visit_body_preserves_cfg ( body) ;
51
+ Replacer { tcx, copy_classes : & ssa. copy_classes ( ) , fully_moved, storage_to_remove }
52
+ . visit_body_preserves_cfg ( body) ;
55
53
56
54
if any_replacement {
57
55
crate :: simplify:: remove_unused_definitions ( body) ;
58
56
}
59
57
}
60
58
61
- #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
62
- enum LocationExtended {
63
- Plain ( Location ) ,
64
- Arg ,
65
- }
66
-
67
- #[ derive( Debug ) ]
68
- struct SsaLocals {
69
- dominators : Dominators < BasicBlock > ,
70
- /// Assignments to each local. This defines whether the local is SSA.
71
- assignments : IndexVec < Local , Set1 < LocationExtended > > ,
72
- /// We visit the body in reverse postorder, to ensure each local is assigned before it is used.
73
- /// We remember the order in which we saw the assignments to compute the SSA values in a single
74
- /// pass.
75
- assignment_order : Vec < Local > ,
76
- }
77
-
78
- impl SsaLocals {
79
- fn new < ' tcx > ( tcx : TyCtxt < ' tcx > , param_env : ParamEnv < ' tcx > , body : & Body < ' tcx > ) -> SsaLocals {
80
- let assignment_order = Vec :: new ( ) ;
81
-
82
- let assignments = IndexVec :: from_elem ( Set1 :: Empty , & body. local_decls ) ;
83
- let dominators = body. basic_blocks . dominators ( ) ;
84
- let mut this = SsaLocals { assignments, assignment_order, dominators } ;
85
-
86
- let borrowed = borrowed_locals ( body) ;
87
- for ( local, decl) in body. local_decls . iter_enumerated ( ) {
88
- if matches ! ( body. local_kind( local) , LocalKind :: Arg ) {
89
- this. assignments [ local] = Set1 :: One ( LocationExtended :: Arg ) ;
90
- }
91
- if borrowed. contains ( local) && !decl. ty . is_freeze ( tcx, param_env) {
92
- this. assignments [ local] = Set1 :: Many ;
93
- }
94
- }
95
-
96
- for ( bb, data) in traversal:: reverse_postorder ( body) {
97
- this. visit_basic_block_data ( bb, data) ;
98
- }
99
-
100
- for var_debug_info in & body. var_debug_info {
101
- this. visit_var_debug_info ( var_debug_info) ;
102
- }
103
-
104
- debug ! ( ?this. assignments) ;
105
-
106
- this. assignment_order . retain ( |& local| matches ! ( this. assignments[ local] , Set1 :: One ( _) ) ) ;
107
- debug ! ( ?this. assignment_order) ;
108
-
109
- this
110
- }
111
- }
112
-
113
- impl < ' tcx > Visitor < ' tcx > for SsaLocals {
114
- fn visit_local ( & mut self , local : Local , ctxt : PlaceContext , loc : Location ) {
115
- match ctxt {
116
- PlaceContext :: MutatingUse ( MutatingUseContext :: Store ) => {
117
- self . assignments [ local] . insert ( LocationExtended :: Plain ( loc) ) ;
118
- self . assignment_order . push ( local) ;
119
- }
120
- // Anything can happen with raw pointers, so remove them.
121
- PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: AddressOf )
122
- | PlaceContext :: MutatingUse ( _) => self . assignments [ local] = Set1 :: Many ,
123
- // Immutable borrows are taken into account in `SsaLocals::new` by
124
- // removing non-freeze locals.
125
- PlaceContext :: NonMutatingUse ( _) => {
126
- let set = & mut self . assignments [ local] ;
127
- let assign_dominates = match * set {
128
- Set1 :: Empty | Set1 :: Many => false ,
129
- Set1 :: One ( LocationExtended :: Arg ) => true ,
130
- Set1 :: One ( LocationExtended :: Plain ( assign) ) => {
131
- assign. dominates ( loc, & self . dominators )
132
- }
133
- } ;
134
- // We are visiting a use that is not dominated by an assignment.
135
- // Either there is a cycle involved, or we are reading for uninitialized local.
136
- // Bail out.
137
- if !assign_dominates {
138
- * set = Set1 :: Many ;
139
- }
140
- }
141
- PlaceContext :: NonUse ( _) => { }
142
- }
143
- }
144
- }
145
-
146
- /// Compute the equivalence classes for locals, based on copy statements.
147
- ///
148
- /// The returned vector maps each local to the one it copies. In the following case:
149
- /// _a = &mut _0
150
- /// _b = move? _a
151
- /// _c = move? _a
152
- /// _d = move? _c
153
- /// We return the mapping
154
- /// _a => _a // not a copy so, represented by itself
155
- /// _b => _a
156
- /// _c => _a
157
- /// _d => _a // transitively through _c
59
+ /// `SsaLocals` computed equivalence classes between locals considering copy/move assignments.
158
60
///
159
61
/// This function also returns whether all the `move?` in the pattern are `move` and not copies.
160
62
/// A local which is in the bitset can be replaced by `move _a`. Otherwise, it must be
@@ -164,95 +66,38 @@ impl<'tcx> Visitor<'tcx> for SsaLocals {
164
66
/// This means that replacing it by a copy of `_a` if ok, since this copy happens before `_c` is
165
67
/// moved, and therefore that `_d` is moved.
166
68
#[ instrument( level = "trace" , skip( ssa, body) ) ]
167
- fn compute_copy_classes (
168
- ssa : & SsaLocals ,
169
- body : & Body < ' _ > ,
170
- ) -> ( IndexVec < Local , Local > , BitSet < Local > ) {
171
- let mut copies = IndexVec :: from_fn_n ( |l| l, body. local_decls . len ( ) ) ;
172
- let mut fully_moved = BitSet :: new_filled ( copies. len ( ) ) ;
173
-
174
- for & local in & ssa. assignment_order {
175
- debug ! ( ?local) ;
176
-
177
- if local == RETURN_PLACE {
178
- // `_0` is special, we cannot rename it.
179
- continue ;
180
- }
181
-
182
- // This is not SSA: mark that we don't know the value.
183
- debug ! ( assignments = ?ssa. assignments[ local] ) ;
184
- let Set1 :: One ( LocationExtended :: Plain ( loc) ) = ssa. assignments [ local] else { continue } ;
185
-
186
- // `loc` must point to a direct assignment to `local`.
187
- let Either :: Left ( stmt) = body. stmt_at ( loc) else { bug ! ( ) } ;
188
- let Some ( ( _target, rvalue) ) = stmt. kind . as_assign ( ) else { bug ! ( ) } ;
189
- assert_eq ! ( _target. as_local( ) , Some ( local) ) ;
69
+ fn fully_moved_locals ( ssa : & SsaLocals , body : & Body < ' _ > ) -> BitSet < Local > {
70
+ let mut fully_moved = BitSet :: new_filled ( body. local_decls . len ( ) ) ;
190
71
72
+ for ( _, rvalue) in ssa. assignments ( body) {
191
73
let ( Rvalue :: Use ( Operand :: Copy ( place) | Operand :: Move ( place) ) | Rvalue :: CopyForDeref ( place) )
192
74
= rvalue
193
75
else { continue } ;
194
76
195
77
let Some ( rhs) = place. as_local ( ) else { continue } ;
196
- let Set1 :: One ( _) = ssa. assignments [ rhs] else { continue } ;
197
-
198
- // We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been
199
- // visited before `local`, and we just have to copy the representing local.
200
- copies[ local] = copies[ rhs] ;
78
+ if !ssa. is_ssa ( rhs) {
79
+ continue ;
80
+ }
201
81
202
82
if let Rvalue :: Use ( Operand :: Copy ( _) ) | Rvalue :: CopyForDeref ( _) = rvalue {
203
83
fully_moved. remove ( rhs) ;
204
84
}
205
85
}
206
86
207
- debug ! ( ?copies ) ;
87
+ ssa . meet_copy_equivalence ( & mut fully_moved ) ;
208
88
209
- // Invariant: `copies` must point to the head of an equivalence class.
210
- #[ cfg( debug_assertions) ]
211
- for & head in copies. iter ( ) {
212
- assert_eq ! ( copies[ head] , head) ;
213
- }
214
-
215
- meet_copy_equivalence ( & copies, & mut fully_moved) ;
216
-
217
- ( copies, fully_moved)
218
- }
219
-
220
- /// Make a property uniform on a copy equivalence class by removing elements.
221
- fn meet_copy_equivalence ( copies : & IndexVec < Local , Local > , property : & mut BitSet < Local > ) {
222
- // Consolidate to have a local iff all its copies are.
223
- //
224
- // `copies` defines equivalence classes between locals. The `local`s that recursively
225
- // move/copy the same local all have the same `head`.
226
- for ( local, & head) in copies. iter_enumerated ( ) {
227
- // If any copy does not have `property`, then the head is not.
228
- if !property. contains ( local) {
229
- property. remove ( head) ;
230
- }
231
- }
232
- for ( local, & head) in copies. iter_enumerated ( ) {
233
- // If any copy does not have `property`, then the head doesn't either,
234
- // then no copy has `property`.
235
- if !property. contains ( head) {
236
- property. remove ( local) ;
237
- }
238
- }
239
-
240
- // Verify that we correctly computed equivalence classes.
241
- #[ cfg( debug_assertions) ]
242
- for ( local, & head) in copies. iter_enumerated ( ) {
243
- assert_eq ! ( property. contains( local) , property. contains( head) ) ;
244
- }
89
+ fully_moved
245
90
}
246
91
247
92
/// Utility to help performing subtitution of `*pattern` by `target`.
248
- struct Replacer < ' tcx > {
93
+ struct Replacer < ' a , ' tcx > {
249
94
tcx : TyCtxt < ' tcx > ,
250
95
fully_moved : BitSet < Local > ,
251
96
storage_to_remove : BitSet < Local > ,
252
- copy_classes : IndexVec < Local , Local > ,
97
+ copy_classes : & ' a IndexVec < Local , Local > ,
253
98
}
254
99
255
- impl < ' tcx > MutVisitor < ' tcx > for Replacer < ' tcx > {
100
+ impl < ' tcx > MutVisitor < ' tcx > for Replacer < ' _ , ' tcx > {
256
101
fn tcx ( & self ) -> TyCtxt < ' tcx > {
257
102
self . tcx
258
103
}
0 commit comments