@@ -31,10 +31,10 @@ use crate::transform::MirPass;
3131use rustc_index:: vec:: { Idx , IndexVec } ;
3232use rustc_middle:: mir:: visit:: { MutVisitor , MutatingUseContext , PlaceContext , Visitor } ;
3333use rustc_middle:: mir:: * ;
34+ use rustc_middle:: ty:: ParamEnv ;
3435use rustc_middle:: ty:: TyCtxt ;
3536use smallvec:: SmallVec ;
36- use std:: borrow:: Cow ;
37- use std:: convert:: TryInto ;
37+ use std:: { borrow:: Cow , convert:: TryInto } ;
3838
3939pub struct SimplifyCfg {
4040 label : String ,
@@ -326,7 +326,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals {
326326
327327pub fn simplify_locals < ' tcx > ( body : & mut Body < ' tcx > , tcx : TyCtxt < ' tcx > ) {
328328 // First, we're going to get a count of *actual* uses for every `Local`.
329- let mut used_locals = UsedLocals :: new ( body) ;
329+ let mut used_locals = UsedLocals :: new ( body, tcx ) ;
330330
331331 // Next, we're going to remove any `Local` with zero actual uses. When we remove those
332332 // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals`
@@ -336,7 +336,8 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
336336 remove_unused_definitions ( & mut used_locals, body) ;
337337
338338 // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s.
339- let map = make_local_map ( & mut body. local_decls , & used_locals) ;
339+ let arg_count = body. arg_count . try_into ( ) . unwrap ( ) ;
340+ let map = make_local_map ( & mut body. local_decls , & used_locals, arg_count) ;
340341
341342 // Only bother running the `LocalUpdater` if we actually found locals to remove.
342343 if map. iter ( ) . any ( Option :: is_none) {
@@ -349,54 +350,61 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
349350}
350351
351352/// Construct the mapping while swapping out unused stuff out from the `vec`.
352- fn make_local_map < V > (
353+ fn make_local_map < ' tcx , V > (
353354 local_decls : & mut IndexVec < Local , V > ,
354- used_locals : & UsedLocals ,
355+ used_locals : & UsedLocals < ' tcx > ,
356+ arg_count : u32 ,
355357) -> IndexVec < Local , Option < Local > > {
356- let mut map: IndexVec < Local , Option < Local > > = IndexVec :: from_elem ( None , & * local_decls) ;
358+ let mut map: IndexVec < Local , Option < Local > > = IndexVec :: from_elem ( None , local_decls) ;
357359 let mut used = Local :: new ( 0 ) ;
358360
359361 for alive_index in local_decls. indices ( ) {
360- // `is_used` treats the `RETURN_PLACE` and arguments as used.
361- if !used_locals. is_used ( alive_index) {
362- continue ;
363- }
364-
365- map[ alive_index] = Some ( used) ;
366- if alive_index != used {
367- local_decls. swap ( alive_index, used) ;
362+ // When creating the local map treat the `RETURN_PLACE` and arguments as used.
363+ if alive_index. as_u32 ( ) <= arg_count || used_locals. is_used ( alive_index) {
364+ map[ alive_index] = Some ( used) ;
365+ if alive_index != used {
366+ local_decls. swap ( alive_index, used) ;
367+ }
368+ used. increment_by ( 1 ) ;
368369 }
369- used. increment_by ( 1 ) ;
370370 }
371371 local_decls. truncate ( used. index ( ) ) ;
372372 map
373373}
374374
375375/// Keeps track of used & unused locals.
376- struct UsedLocals {
376+ struct UsedLocals < ' tcx > {
377377 increment : bool ,
378- arg_count : u32 ,
379378 use_count : IndexVec < Local , u32 > ,
379+ is_static : bool ,
380+ local_decls : IndexVec < Local , LocalDecl < ' tcx > > ,
381+ param_env : ParamEnv < ' tcx > ,
382+ tcx : TyCtxt < ' tcx > ,
380383}
381384
382- impl UsedLocals {
385+ impl UsedLocals < ' tcx > {
383386 /// Determines which locals are used & unused in the given body.
384- fn new ( body : & Body < ' _ > ) -> Self {
387+ fn new ( body : & Body < ' tcx > , tcx : TyCtxt < ' tcx > ) -> Self {
388+ let def_id = body. source . def_id ( ) ;
389+ let is_static = tcx. is_static ( def_id) ;
390+ let param_env = tcx. param_env ( def_id) ;
391+ let local_decls = body. local_decls . clone ( ) ;
385392 let mut this = Self {
386393 increment : true ,
387- arg_count : body. arg_count . try_into ( ) . unwrap ( ) ,
388394 use_count : IndexVec :: from_elem ( 0 , & body. local_decls ) ,
395+ is_static,
396+ local_decls,
397+ param_env,
398+ tcx,
389399 } ;
390400 this. visit_body ( body) ;
391401 this
392402 }
393403
394404 /// Checks if local is used.
395- ///
396- /// Return place and arguments are always considered used.
397405 fn is_used ( & self , local : Local ) -> bool {
398406 trace ! ( "is_used({:?}): use_count: {:?}" , local, self . use_count[ local] ) ;
399- local . as_u32 ( ) <= self . arg_count || self . use_count [ local] != 0
407+ self . use_count [ local] != 0
400408 }
401409
402410 /// Updates the use counts to reflect the removal of given statement.
@@ -424,7 +432,7 @@ impl UsedLocals {
424432 }
425433}
426434
427- impl Visitor < ' _ > for UsedLocals {
435+ impl Visitor < ' tcx > for UsedLocals < ' tcx > {
428436 fn visit_statement ( & mut self , statement : & Statement < ' tcx > , location : Location ) {
429437 match statement. kind {
430438 StatementKind :: LlvmInlineAsm ( ..)
@@ -451,7 +459,21 @@ impl Visitor<'_> for UsedLocals {
451459 }
452460 }
453461
454- fn visit_local ( & mut self , local : & Local , _ctx : PlaceContext , _location : Location ) {
462+ fn visit_local ( & mut self , local : & Local , ctx : PlaceContext , _location : Location ) {
463+ debug ! ( "local: {:?} is_static: {:?}, ctx: {:?}" , local, self . is_static, ctx) ;
464+ // Do not count _0 as a used in `return;` if it is a ZST.
465+ let return_place = * local == RETURN_PLACE
466+ && matches ! ( ctx, PlaceContext :: NonMutatingUse ( visit:: NonMutatingUseContext :: Move ) ) ;
467+ if !self . is_static && return_place {
468+ let ty = self . local_decls [ * local] . ty ;
469+ let param_env_and = self . param_env . and ( ty) ;
470+ if let Ok ( layout) = self . tcx . layout_of ( param_env_and) {
471+ debug ! ( "layout.is_zst: {:?}" , layout. is_zst( ) ) ;
472+ if layout. is_zst ( ) {
473+ return ;
474+ }
475+ }
476+ }
455477 if self . increment {
456478 self . use_count [ * local] += 1 ;
457479 } else {
@@ -462,7 +484,10 @@ impl Visitor<'_> for UsedLocals {
462484}
463485
464486/// Removes unused definitions. Updates the used locals to reflect the changes made.
465- fn remove_unused_definitions < ' a , ' tcx > ( used_locals : & ' a mut UsedLocals , body : & mut Body < ' tcx > ) {
487+ fn remove_unused_definitions < ' a , ' tcx > (
488+ used_locals : & ' a mut UsedLocals < ' tcx > ,
489+ body : & mut Body < ' tcx > ,
490+ ) {
466491 // The use counts are updated as we remove the statements. A local might become unused
467492 // during the retain operation, leading to a temporary inconsistency (storage statements or
468493 // definitions referencing the local might remain). For correctness it is crucial that this
0 commit comments