1+ use  std:: assert_matches:: debug_assert_matches; 
12use  std:: fmt:: { Debug ,  Formatter } ; 
23use  std:: ops:: Range ; 
34
@@ -350,32 +351,47 @@ pub struct Map<'tcx> {
350351    projections :  FxHashMap < ( PlaceIndex ,  TrackElem ) ,  PlaceIndex > , 
351352    places :  IndexVec < PlaceIndex ,  PlaceInfo < ' tcx > > , 
352353    value_count :  usize , 
354+     mode :  PlaceCollectionMode , 
353355    // The Range corresponds to a slice into `inner_values_buffer`. 
354356    inner_values :  IndexVec < PlaceIndex ,  Range < usize > > , 
355357    inner_values_buffer :  Vec < ValueIndex > , 
356358} 
357359
360+ #[ derive( Copy ,  Clone ,  Debug ) ]  
361+ pub  enum  PlaceCollectionMode  { 
362+     Full  {  value_limit :  Option < usize >  } , 
363+     OnDemand , 
364+ } 
365+ 
358366impl < ' tcx >  Map < ' tcx >  { 
359367    /// Returns a map that only tracks places whose type has scalar layout. 
360368     /// 
361369     /// This is currently the only way to create a [`Map`]. The way in which the tracked places are 
362370     /// chosen is an implementation detail and may not be relied upon (other than that their type 
363371     /// are scalars). 
364-      pub  fn  new ( tcx :  TyCtxt < ' tcx > ,  body :  & Body < ' tcx > ,  value_limit :  Option < usize > )  -> Self  { 
365-         let  capacity = 4  *  body. local_decls . len ( )  + value_limit. unwrap_or ( body. local_decls . len ( ) ) ; 
372+      #[ tracing:: instrument( level = "trace" ,  skip( tcx,  body) ) ]  
373+     pub  fn  new ( tcx :  TyCtxt < ' tcx > ,  body :  & Body < ' tcx > ,  mode :  PlaceCollectionMode )  -> Self  { 
374+         tracing:: trace!( def_id=?body. source. def_id( ) ) ; 
375+         let  capacity = 4  *  body. local_decls . len ( ) ; 
366376        let  mut  map = Self  { 
367377            locals :  IndexVec :: from_elem ( None ,  & body. local_decls ) , 
368378            projections :  FxHashMap :: default ( ) , 
369379            places :  IndexVec :: with_capacity ( capacity) , 
370380            value_count :  0 , 
371-             inner_values :  IndexVec :: with_capacity ( capacity) , 
381+             mode, 
382+             inner_values :  IndexVec :: new ( ) , 
372383            inner_values_buffer :  Vec :: new ( ) , 
373384        } ; 
374385        map. register_locals ( tcx,  body) ; 
375-         map. collect_places ( tcx,  body) ; 
376-         map. propagate_assignments ( tcx,  body) ; 
377-         map. create_values ( tcx,  body,  value_limit) ; 
378-         map. trim_useless_places ( ) ; 
386+         match  mode { 
387+             PlaceCollectionMode :: Full  {  value_limit }  => { 
388+                 map. collect_places ( tcx,  body) ; 
389+                 map. propagate_assignments ( tcx,  body) ; 
390+                 map. create_values ( tcx,  body,  value_limit) ; 
391+                 map. trim_useless_places ( ) ; 
392+             } 
393+             PlaceCollectionMode :: OnDemand  => { } 
394+         } 
379395        debug ! ( "registered {} places ({} nodes in total)" ,  map. value_count,  map. places. len( ) ) ; 
380396        map
381397    } 
@@ -427,12 +443,18 @@ impl<'tcx> Map<'tcx> {
427443                match  rhs { 
428444                    Rvalue :: Use ( Operand :: Move ( rhs)  | Operand :: Copy ( rhs) ) 
429445                    | Rvalue :: CopyForDeref ( rhs)  => { 
430-                         let  Some ( lhs)  = self . register_place ( tcx,  body,  * lhs)  else  {  continue  } ; 
431-                         let  Some ( rhs)  = self . register_place ( tcx,  body,  * rhs)  else  {  continue  } ; 
446+                         let  Some ( lhs)  = self . register_place_and_discr ( tcx,  body,  * lhs)  else  { 
447+                             continue ; 
448+                         } ; 
449+                         let  Some ( rhs)  = self . register_place_and_discr ( tcx,  body,  * rhs)  else  { 
450+                             continue ; 
451+                         } ; 
432452                        assignments. insert ( ( lhs,  rhs) ) ; 
433453                    } 
434454                    Rvalue :: Aggregate ( kind,  fields)  => { 
435-                         let  Some ( mut  lhs)  = self . register_place ( tcx,  body,  * lhs)  else  {  continue  } ; 
455+                         let  Some ( mut  lhs)  = self . register_place_and_discr ( tcx,  body,  * lhs)  else  { 
456+                             continue ; 
457+                         } ; 
436458                        match  * * kind { 
437459                            // Do not propagate unions. 
438460                            AggregateKind :: Adt ( _,  _,  _,  _,  Some ( _) )  => continue , 
@@ -455,7 +477,7 @@ impl<'tcx> Map<'tcx> {
455477                        } 
456478                        for  ( index,  field)  in  fields. iter_enumerated ( )  { 
457479                            if  let  Some ( rhs)  = field. place ( ) 
458-                                 && let  Some ( rhs)  = self . register_place ( tcx,  body,  rhs) 
480+                                 && let  Some ( rhs)  = self . register_place_and_discr ( tcx,  body,  rhs) 
459481                            { 
460482                                let  lhs = self . register_place_index ( 
461483                                    self . places [ rhs] . ty , 
@@ -512,6 +534,7 @@ impl<'tcx> Map<'tcx> {
512534    /// Create values for places whose type have scalar layout. 
513535     #[ tracing:: instrument( level = "trace" ,  skip( self ,  tcx,  body) ) ]  
514536    fn  create_values ( & mut  self ,  tcx :  TyCtxt < ' tcx > ,  body :  & Body < ' tcx > ,  value_limit :  Option < usize > )  { 
537+         debug_assert_matches ! ( self . mode,  PlaceCollectionMode :: Full  {  .. } ) ; 
515538        let  typing_env = body. typing_env ( tcx) ; 
516539        for  place_info in  self . places . iter_mut ( )  { 
517540            // The user requires a bound on the number of created values. 
@@ -550,6 +573,7 @@ impl<'tcx> Map<'tcx> {
550573    /// Trim useless places. 
551574     #[ tracing:: instrument( level = "trace" ,  skip( self ) ) ]  
552575    fn  trim_useless_places ( & mut  self )  { 
576+         debug_assert_matches ! ( self . mode,  PlaceCollectionMode :: Full  {  .. } ) ; 
553577        for  opt_place in  self . locals . iter_mut ( )  { 
554578            if  let  Some ( place)  = * opt_place
555579                && self . inner_values [ place] . is_empty ( ) 
@@ -562,7 +586,7 @@ impl<'tcx> Map<'tcx> {
562586    } 
563587
564588    #[ tracing:: instrument( level = "trace" ,  skip( self ) ,  ret) ]  
565-     fn  register_place_index ( 
589+     pub   fn  register_place_index ( 
566590        & mut  self , 
567591        ty :  Ty < ' tcx > , 
568592        base :  PlaceIndex , 
@@ -576,49 +600,124 @@ impl<'tcx> Map<'tcx> {
576600        } ) 
577601    } 
578602
579-     #[ tracing:: instrument( level = "trace" ,  skip( self ,  tcx,  body) ) ]  
580-     fn  register_place ( 
603+     #[ tracing:: instrument( level = "trace" ,  skip( self ,  tcx,  body) ,  ret ) ]  
604+     pub   fn  register_place ( 
581605        & mut  self , 
582606        tcx :  TyCtxt < ' tcx > , 
583607        body :  & Body < ' tcx > , 
584608        place :  Place < ' tcx > , 
609+         tail :  Option < TrackElem > , 
585610    )  -> Option < PlaceIndex >  { 
586611        // Create a place for this projection. 
587612        let  mut  place_index = self . locals [ place. local ] ?; 
588613        let  mut  ty = PlaceTy :: from_ty ( body. local_decls [ place. local ] . ty ) ; 
589614        tracing:: trace!( ?place_index,  ?ty) ; 
590615
591-         if  let  ty:: Ref ( _,  ref_ty,  _)  | ty:: RawPtr ( ref_ty,  _)  = ty. ty . kind ( ) 
592-             && let  ty:: Slice ( ..)  = ref_ty. kind ( ) 
593-         { 
594-             self . register_place_index ( tcx. types . usize ,  place_index,  TrackElem :: DerefLen ) ; 
595-         }  else  if  ty. ty . is_enum ( )  { 
596-             let  discriminant_ty = ty. ty . discriminant_ty ( tcx) ; 
597-             self . register_place_index ( discriminant_ty,  place_index,  TrackElem :: Discriminant ) ; 
598-         } 
599- 
600616        for  proj in  place. projection  { 
601617            let  track_elem = proj. try_into ( ) . ok ( ) ?; 
602618            ty = ty. projection_ty ( tcx,  proj) ; 
603619            place_index = self . register_place_index ( ty. ty ,  place_index,  track_elem) ; 
604620            tracing:: trace!( ?proj,  ?place_index,  ?ty) ; 
621+         } 
605622
606-             if  let  ty:: Ref ( _,  ref_ty,  _)  | ty:: RawPtr ( ref_ty,  _)  = ty. ty . kind ( ) 
607-                 && let  ty:: Slice ( ..)  = ref_ty. kind ( ) 
608-             { 
609-                 self . register_place_index ( tcx. types . usize ,  place_index,  TrackElem :: DerefLen ) ; 
610-             }  else  if  ty. ty . is_enum ( )  { 
611-                 let  discriminant_ty = ty. ty . discriminant_ty ( tcx) ; 
612-                 self . register_place_index ( discriminant_ty,  place_index,  TrackElem :: Discriminant ) ; 
613-             } 
623+         if  let  Some ( tail)  = tail { 
624+             let  ty = match  tail { 
625+                 TrackElem :: Discriminant  => ty. ty . discriminant_ty ( tcx) , 
626+                 TrackElem :: Variant ( ..)  | TrackElem :: Field ( ..)  => todo ! ( ) , 
627+                 TrackElem :: DerefLen  => tcx. types . usize , 
628+             } ; 
629+             place_index = self . register_place_index ( ty,  place_index,  tail) ; 
614630        } 
615631
616632        Some ( place_index) 
617633    } 
618634
635+     #[ tracing:: instrument( level = "trace" ,  skip( self ,  tcx,  body) ,  ret) ]  
636+     fn  register_place_and_discr ( 
637+         & mut  self , 
638+         tcx :  TyCtxt < ' tcx > , 
639+         body :  & Body < ' tcx > , 
640+         place :  Place < ' tcx > , 
641+     )  -> Option < PlaceIndex >  { 
642+         let  place = self . register_place ( tcx,  body,  place,  None ) ?; 
643+         let  ty = self . places [ place] . ty ; 
644+ 
645+         if  let  ty:: Ref ( _,  ref_ty,  _)  | ty:: RawPtr ( ref_ty,  _)  = ty. kind ( ) 
646+             && let  ty:: Slice ( ..)  = ref_ty. kind ( ) 
647+         { 
648+             self . register_place_index ( tcx. types . usize ,  place,  TrackElem :: DerefLen ) ; 
649+         }  else  if  ty. is_enum ( )  { 
650+             let  discriminant_ty = ty. discriminant_ty ( tcx) ; 
651+             self . register_place_index ( discriminant_ty,  place,  TrackElem :: Discriminant ) ; 
652+         } 
653+ 
654+         Some ( place) 
655+     } 
656+ 
657+     #[ tracing:: instrument( level = "trace" ,  skip( self ,  tcx,  typing_env) ,  ret) ]  
658+     pub  fn  register_value ( 
659+         & mut  self , 
660+         tcx :  TyCtxt < ' tcx > , 
661+         typing_env :  ty:: TypingEnv < ' tcx > , 
662+         place :  PlaceIndex , 
663+     )  -> Option < ValueIndex >  { 
664+         let  place_info = & mut  self . places [ place] ; 
665+         if  let  Some ( value)  = place_info. value_index  { 
666+             return  Some ( value) ; 
667+         } 
668+ 
669+         if  let  Ok ( ty)  = tcx. try_normalize_erasing_regions ( typing_env,  place_info. ty )  { 
670+             place_info. ty  = ty; 
671+         } 
672+ 
673+         // Allocate a value slot if it doesn't have one, and the user requested one. 
674+         if  let  Ok ( layout)  = tcx. layout_of ( typing_env. as_query_input ( place_info. ty ) ) 
675+             && layout. backend_repr . is_scalar ( ) 
676+         { 
677+             place_info. value_index  = Some ( self . value_count . into ( ) ) ; 
678+             self . value_count  += 1 ; 
679+         } 
680+ 
681+         place_info. value_index 
682+     } 
683+ 
684+     #[ tracing:: instrument( level = "trace" ,  skip( self ,  f) ) ]  
685+     pub  fn  register_copy_tree ( 
686+         & mut  self , 
687+         // Tree to copy. 
688+         source :  PlaceIndex , 
689+         // Tree to build. 
690+         target :  PlaceIndex , 
691+         f :  & mut  impl  FnMut ( ValueIndex ,  ValueIndex ) , 
692+     )  { 
693+         if  let  Some ( source_value)  = self . places [ source] . value_index  { 
694+             let  target_value = * self . places [ target] . value_index . get_or_insert_with ( || { 
695+                 let  value_index = self . value_count . into ( ) ; 
696+                 self . value_count  += 1 ; 
697+                 value_index
698+             } ) ; 
699+             f ( source_value,  target_value) 
700+         } 
701+ 
702+         // Iterate over `source` children and recurse. 
703+         let  mut  source_child_iter = self . places [ source] . first_child ; 
704+         while  let  Some ( source_child)  = source_child_iter { 
705+             source_child_iter = self . places [ source_child] . next_sibling ; 
706+ 
707+             // Try to find corresponding child and recurse. Reasoning is similar as above. 
708+             let  source_info = & self . places [ source_child] ; 
709+             let  source_ty = source_info. ty ; 
710+             let  source_elem = source_info. proj_elem . unwrap ( ) ; 
711+             let  target_child = self . register_place_index ( source_ty,  target,  source_elem) ; 
712+             self . register_copy_tree ( source_child,  target_child,  f) ; 
713+         } 
714+     } 
715+ 
619716    /// Precompute the list of values inside `root` and store it inside 
620717     /// as a slice within `inner_values_buffer`. 
718+      #[ tracing:: instrument( level = "trace" ,  skip( self ) ) ]  
621719    fn  cache_preorder_invoke ( & mut  self ,  root :  PlaceIndex )  { 
720+         debug_assert_matches ! ( self . mode,  PlaceCollectionMode :: Full  {  .. } ) ; 
622721        let  start = self . inner_values_buffer . len ( ) ; 
623722        if  let  Some ( vi)  = self . places [ root] . value_index  { 
624723            self . inner_values_buffer . push ( vi) ; 
@@ -649,7 +748,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> {
649748            return ; 
650749        } 
651750
652-         self . map . register_place ( self . tcx ,  self . body ,  * place) ; 
751+         self . map . register_place_and_discr ( self . tcx ,  self . body ,  * place) ; 
653752    } 
654753} 
655754
@@ -724,6 +823,7 @@ impl<'tcx> Map<'tcx> {
724823     /// 
725824     /// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track 
726825     /// as such. 
826+      #[ tracing:: instrument( level = "trace" ,  skip( self ,  f) ) ]  
727827    pub  fn  for_each_aliasing_place ( 
728828        & self , 
729829        place :  PlaceRef < ' _ > , 
@@ -761,6 +861,7 @@ impl<'tcx> Map<'tcx> {
761861    } 
762862
763863    /// Invoke the given function on all the descendants of the given place, except one branch. 
864+      #[ tracing:: instrument( level = "trace" ,  skip( self ,  f) ) ]  
764865    fn  for_each_variant_sibling ( 
765866        & self , 
766867        parent :  PlaceIndex , 
@@ -781,11 +882,22 @@ impl<'tcx> Map<'tcx> {
781882    } 
782883
783884    /// Invoke a function on each value in the given place and all descendants. 
885+      #[ tracing:: instrument( level = "trace" ,  skip( self ,  f) ) ]  
784886    fn  for_each_value_inside ( & self ,  root :  PlaceIndex ,  f :  & mut  impl  FnMut ( ValueIndex ) )  { 
785-         let  range = self . inner_values [ root] . clone ( ) ; 
786-         let  values = & self . inner_values_buffer [ range] ; 
787-         for  & v in  values { 
788-             f ( v) 
887+         if  let  Some ( range)  = self . inner_values . get ( root)  { 
888+             // Optimized path: we have cached the inner values. 
889+             let  values = & self . inner_values_buffer [ range. clone ( ) ] ; 
890+             for  & v in  values { 
891+                 f ( v) 
892+             } 
893+         }  else  { 
894+             if  let  Some ( root)  = self . places [ root] . value_index  { 
895+                 f ( root) 
896+             } 
897+ 
898+             for  child in  self . children ( root)  { 
899+                 self . for_each_value_inside ( child,  f) ; 
900+             } 
789901        } 
790902    } 
791903
@@ -798,7 +910,9 @@ impl<'tcx> Map<'tcx> {
798910        f :  & mut  impl  FnMut ( PlaceIndex ,  & O ) , 
799911    )  { 
800912        // Fast path is there is nothing to do. 
801-         if  self . inner_values [ root] . is_empty ( )  { 
913+         if  let  Some ( value_range)  = self . inner_values . get ( root) 
914+             && value_range. is_empty ( ) 
915+         { 
802916            return ; 
803917        } 
804918
0 commit comments