@@ -31,7 +31,7 @@ use rustc_index::bit_set::BitSet;
31
31
use rustc_index:: vec:: { Idx , IndexVec } ;
32
32
use rustc:: ty:: TyCtxt ;
33
33
use rustc:: mir:: * ;
34
- use rustc:: mir:: visit:: { MutVisitor , Visitor , PlaceContext } ;
34
+ use rustc:: mir:: visit:: { MutVisitor , Visitor , PlaceContext , MutatingUseContext } ;
35
35
use rustc:: session:: config:: DebugInfo ;
36
36
use std:: borrow:: Cow ;
37
37
use crate :: transform:: { MirPass , MirSource } ;
@@ -293,23 +293,31 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
293
293
pub struct SimplifyLocals ;
294
294
295
295
impl < ' tcx > MirPass < ' tcx > for SimplifyLocals {
296
- fn run_pass ( & self , tcx : TyCtxt < ' tcx > , _: MirSource < ' tcx > , body : & mut Body < ' tcx > ) {
297
- let mut marker = DeclMarker { locals : BitSet :: new_empty ( body. local_decls . len ( ) ) } ;
298
- marker. visit_body ( body) ;
299
- // Return pointer and arguments are always live
300
- marker. locals . insert ( RETURN_PLACE ) ;
301
- for arg in body. args_iter ( ) {
302
- marker. locals . insert ( arg) ;
303
- }
296
+ fn run_pass ( & self , tcx : TyCtxt < ' tcx > , source : MirSource < ' tcx > , body : & mut Body < ' tcx > ) {
297
+ trace ! ( "running SimplifyLocals on {:?}" , source) ;
298
+ let locals = {
299
+ let mut marker = DeclMarker {
300
+ locals : BitSet :: new_empty ( body. local_decls . len ( ) ) ,
301
+ body,
302
+ } ;
303
+ marker. visit_body ( body) ;
304
+ // Return pointer and arguments are always live
305
+ marker. locals . insert ( RETURN_PLACE ) ;
306
+ for arg in body. args_iter ( ) {
307
+ marker. locals . insert ( arg) ;
308
+ }
304
309
305
- // We may need to keep dead user variables live for debuginfo.
306
- if tcx. sess . opts . debuginfo == DebugInfo :: Full {
307
- for local in body. vars_iter ( ) {
308
- marker. locals . insert ( local) ;
310
+ // We may need to keep dead user variables live for debuginfo.
311
+ if tcx. sess . opts . debuginfo == DebugInfo :: Full {
312
+ for local in body. vars_iter ( ) {
313
+ marker. locals . insert ( local) ;
314
+ }
309
315
}
310
- }
311
316
312
- let map = make_local_map ( & mut body. local_decls , marker. locals ) ;
317
+ marker. locals
318
+ } ;
319
+
320
+ let map = make_local_map ( & mut body. local_decls , locals) ;
313
321
// Update references to all vars and tmps now
314
322
LocalUpdater { map } . visit_body ( body) ;
315
323
body. local_decls . shrink_to_fit ( ) ;
@@ -334,18 +342,35 @@ fn make_local_map<V>(
334
342
map
335
343
}
336
344
337
- struct DeclMarker {
345
+ struct DeclMarker < ' a , ' tcx > {
338
346
pub locals : BitSet < Local > ,
347
+ pub body : & ' a Body < ' tcx > ,
339
348
}
340
349
341
- impl < ' tcx > Visitor < ' tcx > for DeclMarker {
342
- fn visit_local ( & mut self , local : & Local , ctx : PlaceContext , _ : Location ) {
350
+ impl < ' a , ' tcx > Visitor < ' tcx > for DeclMarker < ' a , ' tcx > {
351
+ fn visit_local ( & mut self , local : & Local , ctx : PlaceContext , location : Location ) {
343
352
// Ignore storage markers altogether, they get removed along with their otherwise unused
344
353
// decls.
345
354
// FIXME: Extend this to all non-uses.
346
- if ! ctx. is_storage_marker ( ) {
347
- self . locals . insert ( * local ) ;
355
+ if ctx. is_storage_marker ( ) {
356
+ return ;
348
357
}
358
+
359
+ // Ignore stores of constants because `ConstProp` and `CopyProp` can remove uses of many
360
+ // of these locals. However, if the local is still needed, then it will be referenced in
361
+ // another place and we'll mark it as being used there.
362
+ if ctx == PlaceContext :: MutatingUse ( MutatingUseContext :: Store ) {
363
+ let stmt =
364
+ & self . body . basic_blocks ( ) [ location. block ] . statements [ location. statement_index ] ;
365
+ if let StatementKind :: Assign ( box ( p, Rvalue :: Use ( Operand :: Constant ( c) ) ) ) = & stmt. kind {
366
+ if p. as_local ( ) . is_some ( ) {
367
+ trace ! ( "skipping store of const value {:?} to {:?}" , c, local) ;
368
+ return ;
369
+ }
370
+ }
371
+ }
372
+
373
+ self . locals . insert ( * local) ;
349
374
}
350
375
}
351
376
@@ -357,9 +382,16 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
357
382
fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & mut BasicBlockData < ' tcx > ) {
358
383
// Remove unnecessary StorageLive and StorageDead annotations.
359
384
data. statements . retain ( |stmt| {
360
- match stmt. kind {
385
+ match & stmt. kind {
361
386
StatementKind :: StorageLive ( l) | StatementKind :: StorageDead ( l) => {
362
- self . map [ l] . is_some ( )
387
+ self . map [ * l] . is_some ( )
388
+ }
389
+ StatementKind :: Assign ( box ( place, _) ) => {
390
+ if let Some ( local) = place. as_local ( ) {
391
+ self . map [ local] . is_some ( )
392
+ } else {
393
+ true
394
+ }
363
395
}
364
396
_ => true
365
397
}
0 commit comments