@@ -31,7 +31,7 @@ use rustc_index::bit_set::BitSet;
3131use rustc_index:: vec:: { Idx , IndexVec } ;
3232use rustc:: ty:: TyCtxt ;
3333use rustc:: mir:: * ;
34- use rustc:: mir:: visit:: { MutVisitor , Visitor , PlaceContext } ;
34+ use rustc:: mir:: visit:: { MutVisitor , Visitor , PlaceContext , MutatingUseContext } ;
3535use rustc:: session:: config:: DebugInfo ;
3636use std:: borrow:: Cow ;
3737use crate :: transform:: { MirPass , MirSource } ;
@@ -293,23 +293,31 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
293293pub struct SimplifyLocals ;
294294
295295impl < ' 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+ }
304309
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+ }
309315 }
310- }
311316
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) ;
313321 // Update references to all vars and tmps now
314322 LocalUpdater { map } . visit_body ( body) ;
315323 body. local_decls . shrink_to_fit ( ) ;
@@ -334,18 +342,35 @@ fn make_local_map<V>(
334342 map
335343}
336344
337- struct DeclMarker {
345+ struct DeclMarker < ' a , ' tcx > {
338346 pub locals : BitSet < Local > ,
347+ pub body : & ' a Body < ' tcx > ,
339348}
340349
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 ) {
343352 // Ignore storage markers altogether, they get removed along with their otherwise unused
344353 // decls.
345354 // 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 ;
348357 }
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) ;
349374 }
350375}
351376
@@ -357,9 +382,16 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
357382 fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & mut BasicBlockData < ' tcx > ) {
358383 // Remove unnecessary StorageLive and StorageDead annotations.
359384 data. statements . retain ( |stmt| {
360- match stmt. kind {
385+ match & stmt. kind {
361386 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+ }
363395 }
364396 _ => true
365397 }
0 commit comments