1+ use  std:: assert_matches:: debug_assert_matches; 
12use  std:: fmt:: { Debug ,  Formatter } ; 
23use  std:: ops:: Range ; 
34
@@ -352,32 +353,47 @@ pub struct Map<'tcx> {
352353    projections :  FxHashMap < ( PlaceIndex ,  TrackElem ) ,  PlaceIndex > , 
353354    places :  IndexVec < PlaceIndex ,  PlaceInfo < ' tcx > > , 
354355    value_count :  usize , 
356+     mode :  PlaceCollectionMode , 
355357    // The Range corresponds to a slice into `inner_values_buffer`. 
356358    inner_values :  IndexVec < PlaceIndex ,  Range < usize > > , 
357359    inner_values_buffer :  Vec < ValueIndex > , 
358360} 
359361
362+ #[ derive( Copy ,  Clone ,  Debug ) ]  
363+ pub  enum  PlaceCollectionMode  { 
364+     Full  {  value_limit :  Option < usize >  } , 
365+     OnDemand , 
366+ } 
367+ 
360368impl < ' tcx >  Map < ' tcx >  { 
361369    /// Returns a map that only tracks places whose type has scalar layout. 
362370     /// 
363371     /// This is currently the only way to create a [`Map`]. The way in which the tracked places are 
364372     /// chosen is an implementation detail and may not be relied upon (other than that their type 
365373     /// are scalars). 
366-      pub  fn  new ( tcx :  TyCtxt < ' tcx > ,  body :  & Body < ' tcx > ,  value_limit :  Option < usize > )  -> Self  { 
367-         let  capacity = 4  *  body. local_decls . len ( )  + value_limit. unwrap_or ( body. local_decls . len ( ) ) ; 
374+      #[ tracing:: instrument( level = "trace" ,  skip( tcx,  body) ) ]  
375+     pub  fn  new ( tcx :  TyCtxt < ' tcx > ,  body :  & Body < ' tcx > ,  mode :  PlaceCollectionMode )  -> Self  { 
376+         tracing:: trace!( def_id=?body. source. def_id( ) ) ; 
377+         let  capacity = 4  *  body. local_decls . len ( ) ; 
368378        let  mut  map = Self  { 
369379            locals :  IndexVec :: from_elem ( None ,  & body. local_decls ) , 
370380            projections :  FxHashMap :: default ( ) , 
371381            places :  IndexVec :: with_capacity ( capacity) , 
372382            value_count :  0 , 
373-             inner_values :  IndexVec :: with_capacity ( capacity) , 
383+             mode, 
384+             inner_values :  IndexVec :: new ( ) , 
374385            inner_values_buffer :  Vec :: new ( ) , 
375386        } ; 
376387        map. register_locals ( tcx,  body) ; 
377-         map. collect_places ( tcx,  body) ; 
378-         map. propagate_assignments ( tcx,  body) ; 
379-         map. create_values ( tcx,  body,  value_limit) ; 
380-         map. trim_useless_places ( ) ; 
388+         match  mode { 
389+             PlaceCollectionMode :: Full  {  value_limit }  => { 
390+                 map. collect_places ( tcx,  body) ; 
391+                 map. propagate_assignments ( tcx,  body) ; 
392+                 map. create_values ( tcx,  body,  value_limit) ; 
393+                 map. trim_useless_places ( ) ; 
394+             } 
395+             PlaceCollectionMode :: OnDemand  => { } 
396+         } 
381397        debug ! ( "registered {} places ({} nodes in total)" ,  map. value_count,  map. places. len( ) ) ; 
382398        map
383399    } 
@@ -429,12 +445,18 @@ impl<'tcx> Map<'tcx> {
429445                match  rhs { 
430446                    Rvalue :: Use ( Operand :: Move ( rhs)  | Operand :: Copy ( rhs) ) 
431447                    | Rvalue :: CopyForDeref ( rhs)  => { 
432-                         let  Some ( lhs)  = self . register_place ( tcx,  body,  * lhs)  else  {  continue  } ; 
433-                         let  Some ( rhs)  = self . register_place ( tcx,  body,  * rhs)  else  {  continue  } ; 
448+                         let  Some ( lhs)  = self . register_place_and_discr ( tcx,  body,  * lhs)  else  { 
449+                             continue ; 
450+                         } ; 
451+                         let  Some ( rhs)  = self . register_place_and_discr ( tcx,  body,  * rhs)  else  { 
452+                             continue ; 
453+                         } ; 
434454                        assignments. insert ( ( lhs,  rhs) ) ; 
435455                    } 
436456                    Rvalue :: Aggregate ( kind,  fields)  => { 
437-                         let  Some ( mut  lhs)  = self . register_place ( tcx,  body,  * lhs)  else  {  continue  } ; 
457+                         let  Some ( mut  lhs)  = self . register_place_and_discr ( tcx,  body,  * lhs)  else  { 
458+                             continue ; 
459+                         } ; 
438460                        match  * * kind { 
439461                            // Do not propagate unions. 
440462                            AggregateKind :: Adt ( _,  _,  _,  _,  Some ( _) )  => continue , 
@@ -457,7 +479,7 @@ impl<'tcx> Map<'tcx> {
457479                        } 
458480                        for  ( index,  field)  in  fields. iter_enumerated ( )  { 
459481                            if  let  Some ( rhs)  = field. place ( ) 
460-                                 && let  Some ( rhs)  = self . register_place ( tcx,  body,  rhs) 
482+                                 && let  Some ( rhs)  = self . register_place_and_discr ( tcx,  body,  rhs) 
461483                            { 
462484                                let  lhs = self . register_place_index ( 
463485                                    self . places [ rhs] . ty , 
@@ -514,6 +536,7 @@ impl<'tcx> Map<'tcx> {
514536    /// Create values for places whose type have scalar layout. 
515537     #[ tracing:: instrument( level = "trace" ,  skip( self ,  tcx,  body) ) ]  
516538    fn  create_values ( & mut  self ,  tcx :  TyCtxt < ' tcx > ,  body :  & Body < ' tcx > ,  value_limit :  Option < usize > )  { 
539+         debug_assert_matches ! ( self . mode,  PlaceCollectionMode :: Full  {  .. } ) ; 
517540        let  typing_env = body. typing_env ( tcx) ; 
518541        for  place_info in  self . places . iter_mut ( )  { 
519542            // The user requires a bound on the number of created values. 
@@ -552,6 +575,7 @@ impl<'tcx> Map<'tcx> {
552575    /// Trim useless places. 
553576     #[ tracing:: instrument( level = "trace" ,  skip( self ) ) ]  
554577    fn  trim_useless_places ( & mut  self )  { 
578+         debug_assert_matches ! ( self . mode,  PlaceCollectionMode :: Full  {  .. } ) ; 
555579        for  opt_place in  self . locals . iter_mut ( )  { 
556580            if  let  Some ( place)  = * opt_place
557581                && self . inner_values [ place] . is_empty ( ) 
@@ -564,7 +588,7 @@ impl<'tcx> Map<'tcx> {
564588    } 
565589
566590    #[ tracing:: instrument( level = "trace" ,  skip( self ) ,  ret) ]  
567-     fn  register_place_index ( 
591+     pub   fn  register_place_index ( 
568592        & mut  self , 
569593        ty :  Ty < ' tcx > , 
570594        base :  PlaceIndex , 
@@ -578,49 +602,124 @@ impl<'tcx> Map<'tcx> {
578602        } ) 
579603    } 
580604
581-     #[ tracing:: instrument( level = "trace" ,  skip( self ,  tcx,  body) ) ]  
582-     fn  register_place ( 
605+     #[ tracing:: instrument( level = "trace" ,  skip( self ,  tcx,  body) ,  ret ) ]  
606+     pub   fn  register_place ( 
583607        & mut  self , 
584608        tcx :  TyCtxt < ' tcx > , 
585609        body :  & Body < ' tcx > , 
586610        place :  Place < ' tcx > , 
611+         tail :  Option < TrackElem > , 
587612    )  -> Option < PlaceIndex >  { 
588613        // Create a place for this projection. 
589614        let  mut  place_index = self . locals [ place. local ] ?; 
590615        let  mut  ty = PlaceTy :: from_ty ( body. local_decls [ place. local ] . ty ) ; 
591616        tracing:: trace!( ?place_index,  ?ty) ; 
592617
593-         if  let  ty:: Ref ( _,  ref_ty,  _)  | ty:: RawPtr ( ref_ty,  _)  = ty. ty . kind ( ) 
594-             && let  ty:: Slice ( ..)  = ref_ty. kind ( ) 
595-         { 
596-             self . register_place_index ( tcx. types . usize ,  place_index,  TrackElem :: DerefLen ) ; 
597-         }  else  if  ty. ty . is_enum ( )  { 
598-             let  discriminant_ty = ty. ty . discriminant_ty ( tcx) ; 
599-             self . register_place_index ( discriminant_ty,  place_index,  TrackElem :: Discriminant ) ; 
600-         } 
601- 
602618        for  proj in  place. projection  { 
603619            let  track_elem = proj. try_into ( ) . ok ( ) ?; 
604620            ty = ty. projection_ty ( tcx,  proj) ; 
605621            place_index = self . register_place_index ( ty. ty ,  place_index,  track_elem) ; 
606622            tracing:: trace!( ?proj,  ?place_index,  ?ty) ; 
623+         } 
607624
608-             if  let  ty:: Ref ( _,  ref_ty,  _)  | ty:: RawPtr ( ref_ty,  _)  = ty. ty . kind ( ) 
609-                 && let  ty:: Slice ( ..)  = ref_ty. kind ( ) 
610-             { 
611-                 self . register_place_index ( tcx. types . usize ,  place_index,  TrackElem :: DerefLen ) ; 
612-             }  else  if  ty. ty . is_enum ( )  { 
613-                 let  discriminant_ty = ty. ty . discriminant_ty ( tcx) ; 
614-                 self . register_place_index ( discriminant_ty,  place_index,  TrackElem :: Discriminant ) ; 
615-             } 
625+         if  let  Some ( tail)  = tail { 
626+             let  ty = match  tail { 
627+                 TrackElem :: Discriminant  => ty. ty . discriminant_ty ( tcx) , 
628+                 TrackElem :: Variant ( ..)  | TrackElem :: Field ( ..)  => todo ! ( ) , 
629+                 TrackElem :: DerefLen  => tcx. types . usize , 
630+             } ; 
631+             place_index = self . register_place_index ( ty,  place_index,  tail) ; 
616632        } 
617633
618634        Some ( place_index) 
619635    } 
620636
637+     #[ tracing:: instrument( level = "trace" ,  skip( self ,  tcx,  body) ,  ret) ]  
638+     fn  register_place_and_discr ( 
639+         & mut  self , 
640+         tcx :  TyCtxt < ' tcx > , 
641+         body :  & Body < ' tcx > , 
642+         place :  Place < ' tcx > , 
643+     )  -> Option < PlaceIndex >  { 
644+         let  place = self . register_place ( tcx,  body,  place,  None ) ?; 
645+         let  ty = self . places [ place] . ty ; 
646+ 
647+         if  let  ty:: Ref ( _,  ref_ty,  _)  | ty:: RawPtr ( ref_ty,  _)  = ty. kind ( ) 
648+             && let  ty:: Slice ( ..)  = ref_ty. kind ( ) 
649+         { 
650+             self . register_place_index ( tcx. types . usize ,  place,  TrackElem :: DerefLen ) ; 
651+         }  else  if  ty. is_enum ( )  { 
652+             let  discriminant_ty = ty. discriminant_ty ( tcx) ; 
653+             self . register_place_index ( discriminant_ty,  place,  TrackElem :: Discriminant ) ; 
654+         } 
655+ 
656+         Some ( place) 
657+     } 
658+ 
659+     #[ tracing:: instrument( level = "trace" ,  skip( self ,  tcx,  typing_env) ,  ret) ]  
660+     pub  fn  register_value ( 
661+         & mut  self , 
662+         tcx :  TyCtxt < ' tcx > , 
663+         typing_env :  ty:: TypingEnv < ' tcx > , 
664+         place :  PlaceIndex , 
665+     )  -> Option < ValueIndex >  { 
666+         let  place_info = & mut  self . places [ place] ; 
667+         if  let  Some ( value)  = place_info. value_index  { 
668+             return  Some ( value) ; 
669+         } 
670+ 
671+         if  let  Ok ( ty)  = tcx. try_normalize_erasing_regions ( typing_env,  place_info. ty )  { 
672+             place_info. ty  = ty; 
673+         } 
674+ 
675+         // Allocate a value slot if it doesn't have one, and the user requested one. 
676+         if  let  Ok ( layout)  = tcx. layout_of ( typing_env. as_query_input ( place_info. ty ) ) 
677+             && layout. backend_repr . is_scalar ( ) 
678+         { 
679+             place_info. value_index  = Some ( self . value_count . into ( ) ) ; 
680+             self . value_count  += 1 ; 
681+         } 
682+ 
683+         place_info. value_index 
684+     } 
685+ 
686+     #[ tracing:: instrument( level = "trace" ,  skip( self ,  f) ) ]  
687+     pub  fn  register_copy_tree ( 
688+         & mut  self , 
689+         // Tree to copy. 
690+         source :  PlaceIndex , 
691+         // Tree to build. 
692+         target :  PlaceIndex , 
693+         f :  & mut  impl  FnMut ( ValueIndex ,  ValueIndex ) , 
694+     )  { 
695+         if  let  Some ( source_value)  = self . places [ source] . value_index  { 
696+             let  target_value = * self . places [ target] . value_index . get_or_insert_with ( || { 
697+                 let  value_index = self . value_count . into ( ) ; 
698+                 self . value_count  += 1 ; 
699+                 value_index
700+             } ) ; 
701+             f ( source_value,  target_value) 
702+         } 
703+ 
704+         // Iterate over `source` children and recurse. 
705+         let  mut  source_child_iter = self . places [ source] . first_child ; 
706+         while  let  Some ( source_child)  = source_child_iter { 
707+             source_child_iter = self . places [ source_child] . next_sibling ; 
708+ 
709+             // Try to find corresponding child and recurse. Reasoning is similar as above. 
710+             let  source_info = & self . places [ source_child] ; 
711+             let  source_ty = source_info. ty ; 
712+             let  source_elem = source_info. proj_elem . unwrap ( ) ; 
713+             let  target_child = self . register_place_index ( source_ty,  target,  source_elem) ; 
714+             self . register_copy_tree ( source_child,  target_child,  f) ; 
715+         } 
716+     } 
717+ 
621718    /// Precompute the list of values inside `root` and store it inside 
622719     /// as a slice within `inner_values_buffer`. 
720+      #[ tracing:: instrument( level = "trace" ,  skip( self ) ) ]  
623721    fn  cache_preorder_invoke ( & mut  self ,  root :  PlaceIndex )  { 
722+         debug_assert_matches ! ( self . mode,  PlaceCollectionMode :: Full  {  .. } ) ; 
624723        let  start = self . inner_values_buffer . len ( ) ; 
625724        if  let  Some ( vi)  = self . places [ root] . value_index  { 
626725            self . inner_values_buffer . push ( vi) ; 
@@ -651,7 +750,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> {
651750            return ; 
652751        } 
653752
654-         self . map . register_place ( self . tcx ,  self . body ,  * place) ; 
753+         self . map . register_place_and_discr ( self . tcx ,  self . body ,  * place) ; 
655754    } 
656755} 
657756
@@ -726,6 +825,7 @@ impl<'tcx> Map<'tcx> {
726825     /// 
727826     /// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track 
728827     /// as such. 
828+      #[ tracing:: instrument( level = "trace" ,  skip( self ,  f) ) ]  
729829    pub  fn  for_each_aliasing_place ( 
730830        & self , 
731831        place :  PlaceRef < ' _ > , 
@@ -763,6 +863,7 @@ impl<'tcx> Map<'tcx> {
763863    } 
764864
765865    /// Invoke the given function on all the descendants of the given place, except one branch. 
866+      #[ tracing:: instrument( level = "trace" ,  skip( self ,  f) ) ]  
766867    fn  for_each_variant_sibling ( 
767868        & self , 
768869        parent :  PlaceIndex , 
@@ -783,11 +884,22 @@ impl<'tcx> Map<'tcx> {
783884    } 
784885
785886    /// Invoke a function on each value in the given place and all descendants. 
887+      #[ tracing:: instrument( level = "trace" ,  skip( self ,  f) ) ]  
786888    fn  for_each_value_inside ( & self ,  root :  PlaceIndex ,  f :  & mut  impl  FnMut ( ValueIndex ) )  { 
787-         let  range = self . inner_values [ root] . clone ( ) ; 
788-         let  values = & self . inner_values_buffer [ range] ; 
789-         for  & v in  values { 
790-             f ( v) 
889+         if  let  Some ( range)  = self . inner_values . get ( root)  { 
890+             // Optimized path: we have cached the inner values. 
891+             let  values = & self . inner_values_buffer [ range. clone ( ) ] ; 
892+             for  & v in  values { 
893+                 f ( v) 
894+             } 
895+         }  else  { 
896+             if  let  Some ( root)  = self . places [ root] . value_index  { 
897+                 f ( root) 
898+             } 
899+ 
900+             for  child in  self . children ( root)  { 
901+                 self . for_each_value_inside ( child,  f) ; 
902+             } 
791903        } 
792904    } 
793905
@@ -800,7 +912,9 @@ impl<'tcx> Map<'tcx> {
800912        f :  & mut  impl  FnMut ( PlaceIndex ,  & O ) , 
801913    )  { 
802914        // Fast path is there is nothing to do. 
803-         if  self . inner_values [ root] . is_empty ( )  { 
915+         if  let  Some ( value_range)  = self . inner_values . get ( root) 
916+             && value_range. is_empty ( ) 
917+         { 
804918            return ; 
805919        } 
806920
0 commit comments