1
1
use crate :: MirPass ;
2
- use rustc_data_structures:: fx:: { FxIndexMap , IndexEntry } ;
2
+ use rustc_data_structures:: fx:: FxIndexMap ;
3
3
use rustc_index:: bit_set:: BitSet ;
4
4
use rustc_index:: vec:: IndexVec ;
5
5
use rustc_middle:: mir:: patch:: MirPatch ;
6
6
use rustc_middle:: mir:: visit:: * ;
7
7
use rustc_middle:: mir:: * ;
8
8
use rustc_middle:: ty:: TyCtxt ;
9
+ use rustc_mir_dataflow:: value_analysis:: iter_fields;
9
10
10
11
pub struct ScalarReplacementOfAggregates ;
11
12
@@ -125,6 +126,36 @@ fn escaping_locals(body: &Body<'_>) -> BitSet<Local> {
125
126
#[ derive( Default , Debug ) ]
126
127
struct ReplacementMap < ' tcx > {
127
128
fields : FxIndexMap < PlaceRef < ' tcx > , Local > ,
129
+ /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage
130
+ /// and deinit statement and debuginfo.
131
+ fragments : IndexVec < Local , Option < Vec < ( & ' tcx [ PlaceElem < ' tcx > ] , Local ) > > > ,
132
+ }
133
+
134
+ impl < ' tcx > ReplacementMap < ' tcx > {
135
+ fn gather_debug_info_fragments (
136
+ & self ,
137
+ place : PlaceRef < ' tcx > ,
138
+ ) -> Option < Vec < VarDebugInfoFragment < ' tcx > > > {
139
+ let mut fragments = Vec :: new ( ) ;
140
+ let Some ( parts) = & self . fragments [ place. local ] else { return None } ;
141
+ for ( proj, replacement_local) in parts {
142
+ if proj. starts_with ( place. projection ) {
143
+ fragments. push ( VarDebugInfoFragment {
144
+ projection : proj[ place. projection . len ( ) ..] . to_vec ( ) ,
145
+ contents : Place :: from ( * replacement_local) ,
146
+ } ) ;
147
+ }
148
+ }
149
+ Some ( fragments)
150
+ }
151
+
152
+ fn place_fragments (
153
+ & self ,
154
+ place : Place < ' tcx > ,
155
+ ) -> Option < & Vec < ( & ' tcx [ PlaceElem < ' tcx > ] , Local ) > > {
156
+ let local = place. as_local ( ) ?;
157
+ self . fragments [ local] . as_ref ( )
158
+ }
128
159
}
129
160
130
161
/// Compute the replacement of flattened places into locals.
@@ -136,53 +167,30 @@ fn compute_flattening<'tcx>(
136
167
body : & mut Body < ' tcx > ,
137
168
escaping : BitSet < Local > ,
138
169
) -> ReplacementMap < ' tcx > {
139
- let mut visitor = PreFlattenVisitor {
140
- tcx,
141
- escaping,
142
- local_decls : & mut body. local_decls ,
143
- map : Default :: default ( ) ,
144
- } ;
145
- for ( block, bbdata) in body. basic_blocks . iter_enumerated ( ) {
146
- visitor. visit_basic_block_data ( block, bbdata) ;
147
- }
148
- return visitor. map ;
149
-
150
- struct PreFlattenVisitor < ' tcx , ' ll > {
151
- tcx : TyCtxt < ' tcx > ,
152
- local_decls : & ' ll mut LocalDecls < ' tcx > ,
153
- escaping : BitSet < Local > ,
154
- map : ReplacementMap < ' tcx > ,
155
- }
170
+ let mut fields = FxIndexMap :: default ( ) ;
171
+ let mut fragments = IndexVec :: from_elem ( None :: < Vec < _ > > , & body. local_decls ) ;
156
172
157
- impl < ' tcx , ' ll > PreFlattenVisitor < ' tcx , ' ll > {
158
- fn create_place ( & mut self , place : PlaceRef < ' tcx > ) {
159
- if self . escaping . contains ( place. local ) {
160
- return ;
161
- }
162
-
163
- match self . map . fields . entry ( place) {
164
- IndexEntry :: Occupied ( _) => { }
165
- IndexEntry :: Vacant ( v) => {
166
- let ty = place. ty ( & * self . local_decls , self . tcx ) . ty ;
167
- let local = self . local_decls . push ( LocalDecl {
168
- ty,
169
- user_ty : None ,
170
- ..self . local_decls [ place. local ] . clone ( )
171
- } ) ;
172
- v. insert ( local) ;
173
- }
174
- }
175
- }
176
- }
177
-
178
- impl < ' tcx , ' ll > Visitor < ' tcx > for PreFlattenVisitor < ' tcx , ' ll > {
179
- fn visit_place ( & mut self , place : & Place < ' tcx > , _: PlaceContext , _: Location ) {
180
- if let & [ PlaceElem :: Field ( ..) , ..] = & place. projection [ ..] {
181
- let pr = PlaceRef { local : place. local , projection : & place. projection [ ..1 ] } ;
182
- self . create_place ( pr)
183
- }
173
+ for local in body. local_decls . indices ( ) {
174
+ if escaping. contains ( local) {
175
+ continue ;
184
176
}
177
+ let decl = body. local_decls [ local] . clone ( ) ;
178
+ let ty = decl. ty ;
179
+ iter_fields ( ty, tcx, |variant, field, field_ty| {
180
+ if variant. is_some ( ) {
181
+ // Downcasts are currently not supported.
182
+ return ;
183
+ } ;
184
+ let new_local =
185
+ body. local_decls . push ( LocalDecl { ty : field_ty, user_ty : None , ..decl. clone ( ) } ) ;
186
+ let place = Place :: from ( local)
187
+ . project_deeper ( & [ PlaceElem :: Field ( field, field_ty) ] , tcx)
188
+ . as_ref ( ) ;
189
+ fields. insert ( place, new_local) ;
190
+ fragments[ local] . get_or_insert_default ( ) . push ( ( place. projection , new_local) ) ;
191
+ } ) ;
185
192
}
193
+ ReplacementMap { fields, fragments }
186
194
}
187
195
188
196
/// Perform the replacement computed by `compute_flattening`.
@@ -200,18 +208,11 @@ fn replace_flattened_locals<'tcx>(
200
208
return ;
201
209
}
202
210
203
- let mut fragments = IndexVec :: < _ , Option < Vec < _ > > > :: from_elem ( None , & body. local_decls ) ;
204
- for ( k, v) in & replacements. fields {
205
- fragments[ k. local ] . get_or_insert_default ( ) . push ( ( k. projection , * v) ) ;
206
- }
207
- debug ! ( ?fragments) ;
208
-
209
211
let mut visitor = ReplacementVisitor {
210
212
tcx,
211
213
local_decls : & body. local_decls ,
212
214
replacements,
213
215
all_dead_locals,
214
- fragments : & fragments,
215
216
patch : MirPatch :: new ( body) ,
216
217
} ;
217
218
for ( bb, data) in body. basic_blocks . as_mut_preserves_cfg ( ) . iter_enumerated_mut ( ) {
@@ -237,30 +238,10 @@ struct ReplacementVisitor<'tcx, 'll> {
237
238
replacements : ReplacementMap < ' tcx > ,
238
239
/// This is used to check that we are not leaving references to replaced locals behind.
239
240
all_dead_locals : BitSet < Local > ,
240
- /// Pre-computed list of all "new" locals for each "old" local. This is used to expand storage
241
- /// and deinit statement and debuginfo.
242
- fragments : & ' ll IndexVec < Local , Option < Vec < ( & ' tcx [ PlaceElem < ' tcx > ] , Local ) > > > ,
243
241
patch : MirPatch < ' tcx > ,
244
242
}
245
243
246
244
impl < ' tcx , ' ll > ReplacementVisitor < ' tcx , ' ll > {
247
- fn gather_debug_info_fragments (
248
- & self ,
249
- place : PlaceRef < ' tcx > ,
250
- ) -> Option < Vec < VarDebugInfoFragment < ' tcx > > > {
251
- let mut fragments = Vec :: new ( ) ;
252
- let Some ( parts) = & self . fragments [ place. local ] else { return None } ;
253
- for ( proj, replacement_local) in parts {
254
- if proj. starts_with ( place. projection ) {
255
- fragments. push ( VarDebugInfoFragment {
256
- projection : proj[ place. projection . len ( ) ..] . to_vec ( ) ,
257
- contents : Place :: from ( * replacement_local) ,
258
- } ) ;
259
- }
260
- }
261
- Some ( fragments)
262
- }
263
-
264
245
fn replace_place ( & self , place : PlaceRef < ' tcx > ) -> Option < Place < ' tcx > > {
265
246
if let & [ PlaceElem :: Field ( ..) , ref rest @ ..] = place. projection {
266
247
let pr = PlaceRef { local : place. local , projection : & place. projection [ ..1 ] } ;
@@ -270,25 +251,18 @@ impl<'tcx, 'll> ReplacementVisitor<'tcx, 'll> {
270
251
None
271
252
}
272
253
}
273
-
274
- fn place_fragments (
275
- & self ,
276
- place : Place < ' tcx > ,
277
- ) -> Option < & ' ll Vec < ( & ' tcx [ PlaceElem < ' tcx > ] , Local ) > > {
278
- let local = place. as_local ( ) ?;
279
- self . fragments [ local] . as_ref ( )
280
- }
281
254
}
282
255
283
256
impl < ' tcx , ' ll > MutVisitor < ' tcx > for ReplacementVisitor < ' tcx , ' ll > {
284
257
fn tcx ( & self ) -> TyCtxt < ' tcx > {
285
258
self . tcx
286
259
}
287
260
261
+ #[ instrument( level = "trace" , skip( self ) ) ]
288
262
fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
289
263
match statement. kind {
290
264
StatementKind :: StorageLive ( l) => {
291
- if let Some ( final_locals) = & self . fragments [ l] {
265
+ if let Some ( final_locals) = & self . replacements . fragments [ l] {
292
266
for & ( _, fl) in final_locals {
293
267
self . patch . add_statement ( location, StatementKind :: StorageLive ( fl) ) ;
294
268
}
@@ -297,7 +271,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
297
271
return ;
298
272
}
299
273
StatementKind :: StorageDead ( l) => {
300
- if let Some ( final_locals) = & self . fragments [ l] {
274
+ if let Some ( final_locals) = & self . replacements . fragments [ l] {
301
275
for & ( _, fl) in final_locals {
302
276
self . patch . add_statement ( location, StatementKind :: StorageDead ( fl) ) ;
303
277
}
@@ -306,7 +280,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
306
280
return ;
307
281
}
308
282
StatementKind :: Deinit ( box place) => {
309
- if let Some ( final_locals) = self . place_fragments ( place) {
283
+ if let Some ( final_locals) = self . replacements . place_fragments ( place) {
310
284
for & ( _, fl) in final_locals {
311
285
self . patch
312
286
. add_statement ( location, StatementKind :: Deinit ( Box :: new ( fl. into ( ) ) ) ) ;
@@ -317,7 +291,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
317
291
}
318
292
319
293
StatementKind :: Assign ( box ( place, Rvalue :: Aggregate ( _, ref operands) ) ) => {
320
- if let Some ( final_locals) = self . place_fragments ( place) {
294
+ if let Some ( final_locals) = self . replacements . place_fragments ( place) {
321
295
for & ( projection, fl) in final_locals {
322
296
let & [ PlaceElem :: Field ( index, _) ] = projection else { bug ! ( ) } ;
323
297
let index = index. as_usize ( ) ;
@@ -333,7 +307,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
333
307
}
334
308
335
309
StatementKind :: Assign ( box ( place, Rvalue :: Use ( Operand :: Constant ( _) ) ) ) => {
336
- if let Some ( final_locals) = self . place_fragments ( place) {
310
+ if let Some ( final_locals) = self . replacements . place_fragments ( place) {
337
311
for & ( projection, fl) in final_locals {
338
312
let rvalue =
339
313
Rvalue :: Use ( Operand :: Move ( place. project_deeper ( projection, self . tcx ) ) ) ;
@@ -353,9 +327,12 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
353
327
Operand :: Move ( rplace) => ( rplace, false ) ,
354
328
Operand :: Constant ( _) => bug ! ( ) ,
355
329
} ;
356
- if let Some ( final_locals) = self . place_fragments ( lhs) {
330
+ if let Some ( final_locals) = self . replacements . place_fragments ( lhs) {
357
331
for & ( projection, fl) in final_locals {
358
332
let rplace = rplace. project_deeper ( projection, self . tcx ) ;
333
+ debug ! ( ?rplace) ;
334
+ let rplace = self . replace_place ( rplace. as_ref ( ) ) . unwrap_or ( rplace) ;
335
+ debug ! ( ?rplace) ;
359
336
let rvalue = if copy {
360
337
Rvalue :: Use ( Operand :: Copy ( rplace) )
361
338
} else {
@@ -389,7 +366,9 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
389
366
VarDebugInfoContents :: Place ( ref mut place) => {
390
367
if let Some ( repl) = self . replace_place ( place. as_ref ( ) ) {
391
368
* place = repl;
392
- } else if let Some ( fragments) = self . gather_debug_info_fragments ( place. as_ref ( ) ) {
369
+ } else if let Some ( fragments) =
370
+ self . replacements . gather_debug_info_fragments ( place. as_ref ( ) )
371
+ {
393
372
let ty = place. ty ( self . local_decls , self . tcx ) . ty ;
394
373
var_debug_info. value = VarDebugInfoContents :: Composite { ty, fragments } ;
395
374
}
@@ -401,8 +380,9 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
401
380
if let Some ( repl) = self . replace_place ( fragment. contents . as_ref ( ) ) {
402
381
fragment. contents = repl;
403
382
true
404
- } else if let Some ( frg) =
405
- self . gather_debug_info_fragments ( fragment. contents . as_ref ( ) )
383
+ } else if let Some ( frg) = self
384
+ . replacements
385
+ . gather_debug_info_fragments ( fragment. contents . as_ref ( ) )
406
386
{
407
387
new_fragments. extend ( frg. into_iter ( ) . map ( |mut f| {
408
388
f. projection . splice ( 0 ..0 , fragment. projection . iter ( ) . copied ( ) ) ;
0 commit comments