@@ -423,7 +423,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
423423 // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
424424 // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
425425 // fixedpoint where there are no more unused locals.
426- remove_unused_definitions_helper ( & mut used_locals, body) ;
426+ remove_unused_definitions_helper ( & mut used_locals, body, tcx . sess . mir_opt_level ( ) ) ;
427427
428428 // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the
429429 // `Local`s.
@@ -444,7 +444,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
444444 }
445445}
446446
447- pub ( super ) fn remove_unused_definitions < ' tcx > ( body : & mut Body < ' tcx > ) {
447+ pub ( super ) fn remove_unused_definitions < ' tcx > ( body : & mut Body < ' tcx > , mir_opt_level : usize ) {
448448 // First, we're going to get a count of *actual* uses for every `Local`.
449449 let mut used_locals = UsedLocals :: new ( body) ;
450450
@@ -453,7 +453,7 @@ pub(super) fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) {
453453 // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
454454 // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
455455 // fixedpoint where there are no more unused locals.
456- remove_unused_definitions_helper ( & mut used_locals, body) ;
456+ remove_unused_definitions_helper ( & mut used_locals, body, mir_opt_level ) ;
457457}
458458
459459/// Construct the mapping while swapping out unused stuff out from the `vec`.
@@ -466,7 +466,7 @@ fn make_local_map<V>(
466466
467467 for alive_index in local_decls. indices ( ) {
468468 // `is_used` treats the `RETURN_PLACE` and arguments as used.
469- if !used_locals. is_used ( alive_index) {
469+ if !used_locals. is_used ( alive_index, true ) {
470470 continue ;
471471 }
472472
@@ -504,16 +504,14 @@ impl UsedLocals {
504504 /// Checks if local is used.
505505 ///
506506 /// Return place and arguments are always considered used.
507- fn is_used ( & self , local : Local ) -> bool {
507+ fn is_used ( & self , local : Local , debuginfo_is_used : bool ) -> bool {
508508 trace ! (
509509 "is_used({:?}): use_count: {:?}, debuginfo_use: {}" ,
510510 local, self . use_count[ local] , self . debuginfo_use[ local]
511511 ) ;
512- local. as_u32 ( ) <= self . arg_count || self . use_count [ local] != 0 || self . debuginfo_use [ local]
513- }
514-
515- fn is_only_debuginfo_used ( & self , local : Local ) -> bool {
516- local. as_u32 ( ) > self . arg_count && self . use_count [ local] == 0 && self . debuginfo_use [ local]
512+ local. as_u32 ( ) <= self . arg_count
513+ || self . use_count [ local] != 0
514+ || ( debuginfo_is_used && self . debuginfo_use [ local] )
517515 }
518516
519517 fn is_debuginfo_used ( & self , local : Local ) -> bool {
@@ -605,36 +603,46 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
605603}
606604
607605/// Removes unused definitions. Updates the used locals to reflect the changes made.
608- fn remove_unused_definitions_helper ( used_locals : & mut UsedLocals , body : & mut Body < ' _ > ) {
606+ fn remove_unused_definitions_helper (
607+ used_locals : & mut UsedLocals ,
608+ body : & mut Body < ' _ > ,
609+ mir_opt_level : usize ,
610+ ) {
609611 // The use counts are updated as we remove the statements. A local might become unused
610612 // during the retain operation, leading to a temporary inconsistency (storage statements or
611613 // definitions referencing the local might remain). For correctness it is crucial that this
612614 // computation reaches a fixed point.
613615
614616 let mut modified = true ;
617+ // Transform statements to debug information only when user requests more aggressive optimization.
618+ // This may degrade the debugging experience.
619+ let debuginfo_is_used = mir_opt_level < 2 ;
615620 while modified {
616621 modified = false ;
617622
618623 for data in body. basic_blocks . as_mut_preserves_cfg ( ) {
619624 // Remove unnecessary StorageLive and StorageDead annotations.
620625 for statement in data. statements . iter_mut ( ) {
621626 let ( keep_statement, drop_debuginfo) = match & statement. kind {
622- StatementKind :: StorageLive ( local) | StatementKind :: StorageDead ( local) => (
623- !used_locals. is_used ( * local) || used_locals. is_only_debuginfo_used ( * local) ,
624- true ,
625- ) ,
627+ StatementKind :: StorageLive ( local) | StatementKind :: StorageDead ( local) => {
628+ ( used_locals. is_used ( * local, debuginfo_is_used) , true )
629+ }
626630 StatementKind :: Assign ( box ( place, _) )
627631 | StatementKind :: SetDiscriminant { box place, .. }
628632 | StatementKind :: BackwardIncompatibleDropHint { box place, .. }
629633 | StatementKind :: Deinit ( box place) => (
630- !used_locals. is_used ( place. local )
631- || ( used_locals. is_only_debuginfo_used ( place. local )
632- && statement. kind . as_debuginfo ( ) . is_some ( ) ) ,
634+ used_locals. is_used (
635+ place. local ,
636+ debuginfo_is_used
637+ // FIXME: We are not sure how we should represent this debugging information for some statements,
638+ // keep it for now.
639+ || statement. kind . as_debuginfo ( ) . is_none ( ) ,
640+ ) ,
633641 !used_locals. is_debuginfo_used ( place. local ) ,
634642 ) ,
635643 _ => continue ,
636644 } ;
637- if ! keep_statement {
645+ if keep_statement {
638646 continue ;
639647 }
640648 trace ! ( "removing statement {:?}" , statement) ;
0 commit comments