@@ -372,21 +372,20 @@ impl<'tcx> Map<'tcx> {
372372 inner_values : IndexVec :: new ( ) ,
373373 inner_values_buffer : Vec :: new ( ) ,
374374 } ;
375- let exclude = excluded_locals ( body) ;
376- map. register ( tcx, body, exclude, value_limit) ;
375+ map. register_locals ( tcx, body) ;
376+ map. collect_places ( tcx, body) ;
377+ map. propagate_assignments ( tcx, body) ;
378+ map. create_values ( tcx, body, value_limit) ;
379+ map. trim_useless_places ( ) ;
377380 debug ! ( "registered {} places ({} nodes in total)" , map. value_count, map. places. len( ) ) ;
378381 map
379382 }
380383
381384 /// Register all non-excluded places that have scalar layout.
382385 #[ tracing:: instrument( level = "trace" , skip( self , tcx, body) ) ]
383- fn register (
384- & mut self ,
385- tcx : TyCtxt < ' tcx > ,
386- body : & Body < ' tcx > ,
387- exclude : DenseBitSet < Local > ,
388- value_limit : Option < usize > ,
389- ) {
386+ fn register_locals ( & mut self , tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > ) {
387+ let exclude = excluded_locals ( body) ;
388+
390389 // Start by constructing the places for each bare local.
391390 for ( local, decl) in body. local_decls . iter_enumerated ( ) {
392391 if exclude. contains ( local) {
@@ -401,23 +400,79 @@ impl<'tcx> Map<'tcx> {
401400 let place = self . places . push ( PlaceInfo :: new ( decl. ty , None ) ) ;
402401 self . locals [ local] = Some ( place) ;
403402 }
403+ }
404404
405- // Collect syntactic places and assignments between them.
406- let mut collector =
407- PlaceCollector { tcx, body, map : self , assignments : Default :: default ( ) } ;
405+ /// Collect syntactic places from body, and create `PlaceIndex` for them.
406+ #[ tracing:: instrument( level = "trace" , skip( self , tcx, body) ) ]
407+ fn collect_places ( & mut self , tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > ) {
408+ let mut collector = PlaceCollector { tcx, body, map : self } ;
408409 collector. visit_body ( body) ;
409- let PlaceCollector { mut assignments, .. } = collector;
410-
411- // Just collecting syntactic places is not enough. We may need to propagate this pattern:
412- // _1 = (const 5u32, const 13i64);
413- // _2 = _1;
414- // _3 = (_2.0 as u32);
415- //
416- // `_1.0` does not appear, but we still need to track it. This is achieved by propagating
417- // projections from assignments. We recorded an assignment between `_2` and `_1`, so we
418- // want `_1` and `_2` to have the same sub-places.
419- //
420- // This is what this fixpoint loop does. While we are still creating places, run through
410+ }
411+
412+ /// Just collecting syntactic places is not enough. We may need to propagate this pattern:
413+ /// _1 = (const 5u32, const 13i64);
414+ /// _2 = _1;
415+ /// _3 = (_2.0 as u32);
416+ ///
417+ /// `_1.0` does not appear, but we still need to track it. This is achieved by propagating
418+ /// projections from assignments. We recorded an assignment between `_2` and `_1`, so we
419+ /// want `_1` and `_2` to have the same sub-places.
420+ #[ tracing:: instrument( level = "trace" , skip( self , tcx, body) ) ]
421+ fn propagate_assignments ( & mut self , tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > ) {
422+ // Collect syntactic places and assignments between them.
423+ let mut assignments = FxIndexSet :: default ( ) ;
424+
425+ for bbdata in body. basic_blocks . iter ( ) {
426+ for stmt in bbdata. statements . iter ( ) {
427+ let Some ( ( lhs, rhs) ) = stmt. kind . as_assign ( ) else { continue } ;
428+ match rhs {
429+ Rvalue :: Use ( Operand :: Move ( rhs) | Operand :: Copy ( rhs) )
430+ | Rvalue :: CopyForDeref ( rhs) => {
431+ let Some ( lhs) = self . register_place ( tcx, body, * lhs) else { continue } ;
432+ let Some ( rhs) = self . register_place ( tcx, body, * rhs) else { continue } ;
433+ assignments. insert ( ( lhs, rhs) ) ;
434+ }
435+ Rvalue :: Aggregate ( kind, fields) => {
436+ let Some ( mut lhs) = self . register_place ( tcx, body, * lhs) else { continue } ;
437+ match * * kind {
438+ // Do not propagate unions.
439+ AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => continue ,
440+ AggregateKind :: Adt ( _, variant, _, _, None ) => {
441+ let ty = self . places [ lhs] . ty ;
442+ if ty. is_enum ( ) {
443+ lhs = self . register_place_index (
444+ ty,
445+ lhs,
446+ TrackElem :: Variant ( variant) ,
447+ ) ;
448+ }
449+ }
450+ AggregateKind :: RawPtr ( ..)
451+ | AggregateKind :: Array ( _)
452+ | AggregateKind :: Tuple
453+ | AggregateKind :: Closure ( ..)
454+ | AggregateKind :: Coroutine ( ..)
455+ | AggregateKind :: CoroutineClosure ( ..) => { }
456+ }
457+ for ( index, field) in fields. iter_enumerated ( ) {
458+ if let Some ( rhs) = field. place ( )
459+ && let Some ( rhs) = self . register_place ( tcx, body, rhs)
460+ {
461+ let lhs = self . register_place_index (
462+ self . places [ rhs] . ty ,
463+ lhs,
464+ TrackElem :: Field ( index) ,
465+ ) ;
466+ assignments. insert ( ( lhs, rhs) ) ;
467+ }
468+ }
469+ }
470+ _ => { }
471+ }
472+ }
473+ }
474+
475+ // This is a fixpoint loop does. While we are still creating places, run through
421476 // all the assignments, and register places for children.
422477 let mut num_places = 0 ;
423478 while num_places < self . places . len ( ) {
@@ -430,8 +485,11 @@ impl<'tcx> Map<'tcx> {
430485 let mut child = self . places [ lhs] . first_child ;
431486 while let Some ( lhs_child) = child {
432487 let PlaceInfo { ty, proj_elem, next_sibling, .. } = self . places [ lhs_child] ;
433- let rhs_child =
434- self . register_place ( ty, rhs, proj_elem. expect ( "child is not a projection" ) ) ;
488+ let rhs_child = self . register_place_index (
489+ ty,
490+ rhs,
491+ proj_elem. expect ( "child is not a projection" ) ,
492+ ) ;
435493 assignments. insert ( ( lhs_child, rhs_child) ) ;
436494 child = next_sibling;
437495 }
@@ -440,16 +498,21 @@ impl<'tcx> Map<'tcx> {
440498 let mut child = self . places [ rhs] . first_child ;
441499 while let Some ( rhs_child) = child {
442500 let PlaceInfo { ty, proj_elem, next_sibling, .. } = self . places [ rhs_child] ;
443- let lhs_child =
444- self . register_place ( ty, lhs, proj_elem. expect ( "child is not a projection" ) ) ;
501+ let lhs_child = self . register_place_index (
502+ ty,
503+ lhs,
504+ proj_elem. expect ( "child is not a projection" ) ,
505+ ) ;
445506 assignments. insert ( ( lhs_child, rhs_child) ) ;
446507 child = next_sibling;
447508 }
448509 }
449510 }
450- drop ( assignments ) ;
511+ }
451512
452- // Create values for places whose type have scalar layout.
513+ /// Create values for places whose type have scalar layout.
514+ #[ tracing:: instrument( level = "trace" , skip( self , tcx, body) ) ]
515+ fn create_values ( & mut self , tcx : TyCtxt < ' tcx > , body : & Body < ' tcx > , value_limit : Option < usize > ) {
453516 let typing_env = body. typing_env ( tcx) ;
454517 for place_info in self . places . iter_mut ( ) {
455518 // The user requires a bound on the number of created values.
@@ -483,8 +546,11 @@ impl<'tcx> Map<'tcx> {
483546 self . cache_preorder_invoke ( place) ;
484547 }
485548 }
549+ }
486550
487- // Trim useless places.
551+ /// Trim useless places.
552+ #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
553+ fn trim_useless_places ( & mut self ) {
488554 for opt_place in self . locals . iter_mut ( ) {
489555 if let Some ( place) = * opt_place
490556 && self . inner_values [ place] . is_empty ( )
@@ -497,7 +563,12 @@ impl<'tcx> Map<'tcx> {
497563 }
498564
499565 #[ tracing:: instrument( level = "trace" , skip( self ) , ret) ]
500- fn register_place ( & mut self , ty : Ty < ' tcx > , base : PlaceIndex , elem : TrackElem ) -> PlaceIndex {
566+ fn register_place_index (
567+ & mut self ,
568+ ty : Ty < ' tcx > ,
569+ base : PlaceIndex ,
570+ elem : TrackElem ,
571+ ) -> PlaceIndex {
501572 * self . projections . entry ( ( base, elem) ) . or_insert_with ( || {
502573 let next = self . places . push ( PlaceInfo :: new ( ty, Some ( elem) ) ) ;
503574 self . places [ next] . next_sibling = self . places [ base] . first_child ;
@@ -506,6 +577,46 @@ impl<'tcx> Map<'tcx> {
506577 } )
507578 }
508579
580+ #[ tracing:: instrument( level = "trace" , skip( self , tcx, body) ) ]
581+ fn register_place (
582+ & mut self ,
583+ tcx : TyCtxt < ' tcx > ,
584+ body : & Body < ' tcx > ,
585+ place : Place < ' tcx > ,
586+ ) -> Option < PlaceIndex > {
587+ // Create a place for this projection.
588+ let mut place_index = self . locals [ place. local ] ?;
589+ let mut ty = PlaceTy :: from_ty ( body. local_decls [ place. local ] . ty ) ;
590+ tracing:: trace!( ?place_index, ?ty) ;
591+
592+ if let ty:: Ref ( _, ref_ty, _) | ty:: RawPtr ( ref_ty, _) = ty. ty . kind ( )
593+ && let ty:: Slice ( ..) = ref_ty. kind ( )
594+ {
595+ self . register_place_index ( tcx. types . usize , place_index, TrackElem :: DerefLen ) ;
596+ } else if ty. ty . is_enum ( ) {
597+ let discriminant_ty = ty. ty . discriminant_ty ( tcx) ;
598+ self . register_place_index ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
599+ }
600+
601+ for proj in place. projection {
602+ let track_elem = proj. try_into ( ) . ok ( ) ?;
603+ ty = ty. projection_ty ( tcx, proj) ;
604+ place_index = self . register_place_index ( ty. ty , place_index, track_elem) ;
605+ tracing:: trace!( ?proj, ?place_index, ?ty) ;
606+
607+ if let ty:: Ref ( _, ref_ty, _) | ty:: RawPtr ( ref_ty, _) = ty. ty . kind ( )
608+ && let ty:: Slice ( ..) = ref_ty. kind ( )
609+ {
610+ self . register_place_index ( tcx. types . usize , place_index, TrackElem :: DerefLen ) ;
611+ } else if ty. ty . is_enum ( ) {
612+ let discriminant_ty = ty. ty . discriminant_ty ( tcx) ;
613+ self . register_place_index ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
614+ }
615+ }
616+
617+ Some ( place_index)
618+ }
619+
509620 /// Precompute the list of values inside `root` and store it inside
510621 /// as a slice within `inner_values_buffer`.
511622 fn cache_preorder_invoke ( & mut self , root : PlaceIndex ) {
@@ -530,44 +641,6 @@ struct PlaceCollector<'a, 'tcx> {
530641 tcx : TyCtxt < ' tcx > ,
531642 body : & ' a Body < ' tcx > ,
532643 map : & ' a mut Map < ' tcx > ,
533- assignments : FxIndexSet < ( PlaceIndex , PlaceIndex ) > ,
534- }
535-
536- impl < ' tcx > PlaceCollector < ' _ , ' tcx > {
537- #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
538- fn register_place ( & mut self , place : Place < ' tcx > ) -> Option < PlaceIndex > {
539- // Create a place for this projection.
540- let mut place_index = self . map . locals [ place. local ] ?;
541- let mut ty = PlaceTy :: from_ty ( self . body . local_decls [ place. local ] . ty ) ;
542- tracing:: trace!( ?place_index, ?ty) ;
543-
544- if let ty:: Ref ( _, ref_ty, _) | ty:: RawPtr ( ref_ty, _) = ty. ty . kind ( )
545- && let ty:: Slice ( ..) = ref_ty. kind ( )
546- {
547- self . map . register_place ( self . tcx . types . usize , place_index, TrackElem :: DerefLen ) ;
548- } else if ty. ty . is_enum ( ) {
549- let discriminant_ty = ty. ty . discriminant_ty ( self . tcx ) ;
550- self . map . register_place ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
551- }
552-
553- for proj in place. projection {
554- let track_elem = proj. try_into ( ) . ok ( ) ?;
555- ty = ty. projection_ty ( self . tcx , proj) ;
556- place_index = self . map . register_place ( ty. ty , place_index, track_elem) ;
557- tracing:: trace!( ?proj, ?place_index, ?ty) ;
558-
559- if let ty:: Ref ( _, ref_ty, _) | ty:: RawPtr ( ref_ty, _) = ty. ty . kind ( )
560- && let ty:: Slice ( ..) = ref_ty. kind ( )
561- {
562- self . map . register_place ( self . tcx . types . usize , place_index, TrackElem :: DerefLen ) ;
563- } else if ty. ty . is_enum ( ) {
564- let discriminant_ty = ty. ty . discriminant_ty ( self . tcx ) ;
565- self . map . register_place ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
566- }
567- }
568-
569- Some ( place_index)
570- }
571644}
572645
573646impl < ' tcx > Visitor < ' tcx > for PlaceCollector < ' _ , ' tcx > {
@@ -577,51 +650,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> {
577650 return ;
578651 }
579652
580- self . register_place ( * place) ;
581- }
582-
583- fn visit_assign ( & mut self , lhs : & Place < ' tcx > , rhs : & Rvalue < ' tcx > , location : Location ) {
584- self . super_assign ( lhs, rhs, location) ;
585-
586- match rhs {
587- Rvalue :: Use ( Operand :: Move ( rhs) | Operand :: Copy ( rhs) ) | Rvalue :: CopyForDeref ( rhs) => {
588- let Some ( lhs) = self . register_place ( * lhs) else { return } ;
589- let Some ( rhs) = self . register_place ( * rhs) else { return } ;
590- self . assignments . insert ( ( lhs, rhs) ) ;
591- }
592- Rvalue :: Aggregate ( kind, fields) => {
593- let Some ( mut lhs) = self . register_place ( * lhs) else { return } ;
594- match * * kind {
595- // Do not propagate unions.
596- AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return ,
597- AggregateKind :: Adt ( _, variant, _, _, None ) => {
598- let ty = self . map . places [ lhs] . ty ;
599- if ty. is_enum ( ) {
600- lhs = self . map . register_place ( ty, lhs, TrackElem :: Variant ( variant) ) ;
601- }
602- }
603- AggregateKind :: RawPtr ( ..)
604- | AggregateKind :: Array ( _)
605- | AggregateKind :: Tuple
606- | AggregateKind :: Closure ( ..)
607- | AggregateKind :: Coroutine ( ..)
608- | AggregateKind :: CoroutineClosure ( ..) => { }
609- }
610- for ( index, field) in fields. iter_enumerated ( ) {
611- if let Some ( rhs) = field. place ( )
612- && let Some ( rhs) = self . register_place ( rhs)
613- {
614- let lhs = self . map . register_place (
615- self . map . places [ rhs] . ty ,
616- lhs,
617- TrackElem :: Field ( index) ,
618- ) ;
619- self . assignments . insert ( ( lhs, rhs) ) ;
620- }
621- }
622- }
623- _ => { }
624- }
653+ self . map . register_place ( self . tcx , self . body , * place) ;
625654 }
626655}
627656
0 commit comments