@@ -370,21 +370,20 @@ impl<'tcx> Map<'tcx> {
370370 inner_values : IndexVec :: new ( ) ,
371371 inner_values_buffer : Vec :: new ( ) ,
372372 } ;
373- let exclude = excluded_locals ( body) ;
374- map. register ( tcx, body, exclude, value_limit) ;
373+ map. register_locals ( tcx, body) ;
374+ map. collect_places ( tcx, body) ;
375+ map. propagate_assignments ( tcx, body) ;
376+ map. create_values ( tcx, body, value_limit) ;
377+ map. trim_useless_places ( ) ;
375378 debug ! ( "registered {} places ({} nodes in total)" , map. value_count, map. places. len( ) ) ;
376379 map
377380 }
378381
379382 /// Register all non-excluded places that have scalar layout.
380383 #[ tracing:: instrument( level = "trace" , skip( self , tcx, body) ) ]
381- fn register (
382- & mut self ,
383- tcx : TyCtxt < ' tcx > ,
384- body : & Body < ' tcx > ,
385- exclude : DenseBitSet < Local > ,
386- value_limit : Option < usize > ,
387- ) {
384+ fn register_locals ( & mut self , tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > ) {
385+ let exclude = excluded_locals ( body) ;
386+
388387 // Start by constructing the places for each bare local.
389388 for ( local, decl) in body. local_decls . iter_enumerated ( ) {
390389 if exclude. contains ( local) {
@@ -399,23 +398,79 @@ impl<'tcx> Map<'tcx> {
399398 let place = self . places . push ( PlaceInfo :: new ( decl. ty , None ) ) ;
400399 self . locals [ local] = Some ( place) ;
401400 }
401+ }
402402
403- // Collect syntactic places and assignments between them.
404- let mut collector =
405- PlaceCollector { tcx, body, map : self , assignments : Default :: default ( ) } ;
403+ /// Collect syntactic places from body, and create `PlaceIndex` for them.
404+ #[ tracing:: instrument( level = "trace" , skip( self , tcx, body) ) ]
405+ fn collect_places ( & mut self , tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > ) {
406+ let mut collector = PlaceCollector { tcx, body, map : self } ;
406407 collector. visit_body ( body) ;
407- let PlaceCollector { mut assignments, .. } = collector;
408-
409- // Just collecting syntactic places is not enough. We may need to propagate this pattern:
410- // _1 = (const 5u32, const 13i64);
411- // _2 = _1;
412- // _3 = (_2.0 as u32);
413- //
414- // `_1.0` does not appear, but we still need to track it. This is achieved by propagating
415- // projections from assignments. We recorded an assignment between `_2` and `_1`, so we
416- // want `_1` and `_2` to have the same sub-places.
417- //
418- // This is what this fixpoint loop does. While we are still creating places, run through
408+ }
409+
410+ /// Just collecting syntactic places is not enough. We may need to propagate this pattern:
411+ /// _1 = (const 5u32, const 13i64);
412+ /// _2 = _1;
413+ /// _3 = (_2.0 as u32);
414+ ///
415+ /// `_1.0` does not appear, but we still need to track it. This is achieved by propagating
416+ /// projections from assignments. We recorded an assignment between `_2` and `_1`, so we
417+ /// want `_1` and `_2` to have the same sub-places.
418+ #[ tracing:: instrument( level = "trace" , skip( self , tcx, body) ) ]
419+ fn propagate_assignments ( & mut self , tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > ) {
420+ // Collect syntactic places and assignments between them.
421+ let mut assignments = FxIndexSet :: default ( ) ;
422+
423+ for bbdata in body. basic_blocks . iter ( ) {
424+ for stmt in bbdata. statements . iter ( ) {
425+ let Some ( ( lhs, rhs) ) = stmt. kind . as_assign ( ) else { continue } ;
426+ match rhs {
427+ Rvalue :: Use ( Operand :: Move ( rhs) | Operand :: Copy ( rhs) )
428+ | Rvalue :: CopyForDeref ( rhs) => {
429+ let Some ( lhs) = self . register_place ( tcx, body, * lhs) else { continue } ;
430+ let Some ( rhs) = self . register_place ( tcx, body, * rhs) else { continue } ;
431+ assignments. insert ( ( lhs, rhs) ) ;
432+ }
433+ Rvalue :: Aggregate ( kind, fields) => {
434+ let Some ( mut lhs) = self . register_place ( tcx, body, * lhs) else { continue } ;
435+ match * * kind {
436+ // Do not propagate unions.
437+ AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => continue ,
438+ AggregateKind :: Adt ( _, variant, _, _, None ) => {
439+ let ty = self . places [ lhs] . ty ;
440+ if ty. is_enum ( ) {
441+ lhs = self . register_place_index (
442+ ty,
443+ lhs,
444+ TrackElem :: Variant ( variant) ,
445+ ) ;
446+ }
447+ }
448+ AggregateKind :: RawPtr ( ..)
449+ | AggregateKind :: Array ( _)
450+ | AggregateKind :: Tuple
451+ | AggregateKind :: Closure ( ..)
452+ | AggregateKind :: Coroutine ( ..)
453+ | AggregateKind :: CoroutineClosure ( ..) => { }
454+ }
455+ for ( index, field) in fields. iter_enumerated ( ) {
456+ if let Some ( rhs) = field. place ( )
457+ && let Some ( rhs) = self . register_place ( tcx, body, rhs)
458+ {
459+ let lhs = self . register_place_index (
460+ self . places [ rhs] . ty ,
461+ lhs,
462+ TrackElem :: Field ( index) ,
463+ ) ;
464+ assignments. insert ( ( lhs, rhs) ) ;
465+ }
466+ }
467+ }
468+ _ => { }
469+ }
470+ }
471+ }
472+
473+ // This is a fixpoint loop does. While we are still creating places, run through
419474 // all the assignments, and register places for children.
420475 let mut num_places = 0 ;
421476 while num_places < self . places . len ( ) {
@@ -428,8 +483,11 @@ impl<'tcx> Map<'tcx> {
428483 let mut child = self . places [ lhs] . first_child ;
429484 while let Some ( lhs_child) = child {
430485 let PlaceInfo { ty, proj_elem, next_sibling, .. } = self . places [ lhs_child] ;
431- let rhs_child =
432- self . register_place ( ty, rhs, proj_elem. expect ( "child is not a projection" ) ) ;
486+ let rhs_child = self . register_place_index (
487+ ty,
488+ rhs,
489+ proj_elem. expect ( "child is not a projection" ) ,
490+ ) ;
433491 assignments. insert ( ( lhs_child, rhs_child) ) ;
434492 child = next_sibling;
435493 }
@@ -438,16 +496,21 @@ impl<'tcx> Map<'tcx> {
438496 let mut child = self . places [ rhs] . first_child ;
439497 while let Some ( rhs_child) = child {
440498 let PlaceInfo { ty, proj_elem, next_sibling, .. } = self . places [ rhs_child] ;
441- let lhs_child =
442- self . register_place ( ty, lhs, proj_elem. expect ( "child is not a projection" ) ) ;
499+ let lhs_child = self . register_place_index (
500+ ty,
501+ lhs,
502+ proj_elem. expect ( "child is not a projection" ) ,
503+ ) ;
443504 assignments. insert ( ( lhs_child, rhs_child) ) ;
444505 child = next_sibling;
445506 }
446507 }
447508 }
448- drop ( assignments ) ;
509+ }
449510
450- // Create values for places whose type have scalar layout.
511+ /// Create values for places whose type have scalar layout.
512+ #[ tracing:: instrument( level = "trace" , skip( self , tcx, body) ) ]
513+ fn create_values ( & mut self , tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > , value_limit : Option < usize > ) {
451514 let typing_env = body. typing_env ( tcx) ;
452515 for place_info in self . places . iter_mut ( ) {
453516 // The user requires a bound on the number of created values.
@@ -481,8 +544,11 @@ impl<'tcx> Map<'tcx> {
481544 self . cache_preorder_invoke ( place) ;
482545 }
483546 }
547+ }
484548
485- // Trim useless places.
549+ /// Trim useless places.
550+ #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
551+ fn trim_useless_places ( & mut self ) {
486552 for opt_place in self . locals . iter_mut ( ) {
487553 if let Some ( place) = * opt_place
488554 && self . inner_values [ place] . is_empty ( )
@@ -495,7 +561,12 @@ impl<'tcx> Map<'tcx> {
495561 }
496562
497563 #[ tracing:: instrument( level = "trace" , skip( self ) , ret) ]
498- fn register_place ( & mut self , ty : Ty < ' tcx > , base : PlaceIndex , elem : TrackElem ) -> PlaceIndex {
564+ fn register_place_index (
565+ & mut self ,
566+ ty : Ty < ' tcx > ,
567+ base : PlaceIndex ,
568+ elem : TrackElem ,
569+ ) -> PlaceIndex {
499570 * self . projections . entry ( ( base, elem) ) . or_insert_with ( || {
500571 let next = self . places . push ( PlaceInfo :: new ( ty, Some ( elem) ) ) ;
501572 self . places [ next] . next_sibling = self . places [ base] . first_child ;
@@ -504,6 +575,46 @@ impl<'tcx> Map<'tcx> {
504575 } )
505576 }
506577
578+ #[ tracing:: instrument( level = "trace" , skip( self , tcx, body) ) ]
579+ fn register_place (
580+ & mut self ,
581+ tcx : TyCtxt < ' tcx > ,
582+ body : & Body < ' tcx > ,
583+ place : Place < ' tcx > ,
584+ ) -> Option < PlaceIndex > {
585+ // Create a place for this projection.
586+ let mut place_index = self . locals [ place. local ] ?;
587+ let mut ty = PlaceTy :: from_ty ( body. local_decls [ place. local ] . ty ) ;
588+ tracing:: trace!( ?place_index, ?ty) ;
589+
590+ if let ty:: Ref ( _, ref_ty, _) | ty:: RawPtr ( ref_ty, _) = ty. ty . kind ( )
591+ && let ty:: Slice ( ..) = ref_ty. kind ( )
592+ {
593+ self . register_place_index ( tcx. types . usize , place_index, TrackElem :: DerefLen ) ;
594+ } else if ty. ty . is_enum ( ) {
595+ let discriminant_ty = ty. ty . discriminant_ty ( tcx) ;
596+ self . register_place_index ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
597+ }
598+
599+ for proj in place. projection {
600+ let track_elem = proj. try_into ( ) . ok ( ) ?;
601+ ty = ty. projection_ty ( tcx, proj) ;
602+ place_index = self . register_place_index ( ty. ty , place_index, track_elem) ;
603+ tracing:: trace!( ?proj, ?place_index, ?ty) ;
604+
605+ if let ty:: Ref ( _, ref_ty, _) | ty:: RawPtr ( ref_ty, _) = ty. ty . kind ( )
606+ && let ty:: Slice ( ..) = ref_ty. kind ( )
607+ {
608+ self . register_place_index ( tcx. types . usize , place_index, TrackElem :: DerefLen ) ;
609+ } else if ty. ty . is_enum ( ) {
610+ let discriminant_ty = ty. ty . discriminant_ty ( tcx) ;
611+ self . register_place_index ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
612+ }
613+ }
614+
615+ Some ( place_index)
616+ }
617+
507618 /// Precompute the list of values inside `root` and store it inside
508619 /// as a slice within `inner_values_buffer`.
509620 fn cache_preorder_invoke ( & mut self , root : PlaceIndex ) {
@@ -528,44 +639,6 @@ struct PlaceCollector<'a, 'tcx> {
528639 tcx : TyCtxt < ' tcx > ,
529640 body : & ' a Body < ' tcx > ,
530641 map : & ' a mut Map < ' tcx > ,
531- assignments : FxIndexSet < ( PlaceIndex , PlaceIndex ) > ,
532- }
533-
534- impl < ' tcx > PlaceCollector < ' _ , ' tcx > {
535- #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
536- fn register_place ( & mut self , place : Place < ' tcx > ) -> Option < PlaceIndex > {
537- // Create a place for this projection.
538- let mut place_index = self . map . locals [ place. local ] ?;
539- let mut ty = PlaceTy :: from_ty ( self . body . local_decls [ place. local ] . ty ) ;
540- tracing:: trace!( ?place_index, ?ty) ;
541-
542- if let ty:: Ref ( _, ref_ty, _) | ty:: RawPtr ( ref_ty, _) = ty. ty . kind ( )
543- && let ty:: Slice ( ..) = ref_ty. kind ( )
544- {
545- self . map . register_place ( self . tcx . types . usize , place_index, TrackElem :: DerefLen ) ;
546- } else if ty. ty . is_enum ( ) {
547- let discriminant_ty = ty. ty . discriminant_ty ( self . tcx ) ;
548- self . map . register_place ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
549- }
550-
551- for proj in place. projection {
552- let track_elem = proj. try_into ( ) . ok ( ) ?;
553- ty = ty. projection_ty ( self . tcx , proj) ;
554- place_index = self . map . register_place ( ty. ty , place_index, track_elem) ;
555- tracing:: trace!( ?proj, ?place_index, ?ty) ;
556-
557- if let ty:: Ref ( _, ref_ty, _) | ty:: RawPtr ( ref_ty, _) = ty. ty . kind ( )
558- && let ty:: Slice ( ..) = ref_ty. kind ( )
559- {
560- self . map . register_place ( self . tcx . types . usize , place_index, TrackElem :: DerefLen ) ;
561- } else if ty. ty . is_enum ( ) {
562- let discriminant_ty = ty. ty . discriminant_ty ( self . tcx ) ;
563- self . map . register_place ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
564- }
565- }
566-
567- Some ( place_index)
568- }
569642}
570643
571644impl < ' tcx > Visitor < ' tcx > for PlaceCollector < ' _ , ' tcx > {
@@ -575,51 +648,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> {
575648 return ;
576649 }
577650
578- self . register_place ( * place) ;
579- }
580-
581- fn visit_assign ( & mut self , lhs : & Place < ' tcx > , rhs : & Rvalue < ' tcx > , location : Location ) {
582- self . super_assign ( lhs, rhs, location) ;
583-
584- match rhs {
585- Rvalue :: Use ( Operand :: Move ( rhs) | Operand :: Copy ( rhs) ) | Rvalue :: CopyForDeref ( rhs) => {
586- let Some ( lhs) = self . register_place ( * lhs) else { return } ;
587- let Some ( rhs) = self . register_place ( * rhs) else { return } ;
588- self . assignments . insert ( ( lhs, rhs) ) ;
589- }
590- Rvalue :: Aggregate ( kind, fields) => {
591- let Some ( mut lhs) = self . register_place ( * lhs) else { return } ;
592- match * * kind {
593- // Do not propagate unions.
594- AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return ,
595- AggregateKind :: Adt ( _, variant, _, _, None ) => {
596- let ty = self . map . places [ lhs] . ty ;
597- if ty. is_enum ( ) {
598- lhs = self . map . register_place ( ty, lhs, TrackElem :: Variant ( variant) ) ;
599- }
600- }
601- AggregateKind :: RawPtr ( ..)
602- | AggregateKind :: Array ( _)
603- | AggregateKind :: Tuple
604- | AggregateKind :: Closure ( ..)
605- | AggregateKind :: Coroutine ( ..)
606- | AggregateKind :: CoroutineClosure ( ..) => { }
607- }
608- for ( index, field) in fields. iter_enumerated ( ) {
609- if let Some ( rhs) = field. place ( )
610- && let Some ( rhs) = self . register_place ( rhs)
611- {
612- let lhs = self . map . register_place (
613- self . map . places [ rhs] . ty ,
614- lhs,
615- TrackElem :: Field ( index) ,
616- ) ;
617- self . assignments . insert ( ( lhs, rhs) ) ;
618- }
619- }
620- }
621- _ => { }
622- }
651+ self . map . register_place ( self . tcx , self . body , * place) ;
623652 }
624653}
625654
0 commit comments