@@ -372,21 +372,20 @@ impl<'tcx> Map<'tcx> {
372
372
inner_values : IndexVec :: new ( ) ,
373
373
inner_values_buffer : Vec :: new ( ) ,
374
374
} ;
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 ( ) ;
377
380
debug ! ( "registered {} places ({} nodes in total)" , map. value_count, map. places. len( ) ) ;
378
381
map
379
382
}
380
383
381
384
/// Register all non-excluded places that have scalar layout.
382
385
#[ 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
+
390
389
// Start by constructing the places for each bare local.
391
390
for ( local, decl) in body. local_decls . iter_enumerated ( ) {
392
391
if exclude. contains ( local) {
@@ -401,23 +400,79 @@ impl<'tcx> Map<'tcx> {
401
400
let place = self . places . push ( PlaceInfo :: new ( decl. ty , None ) ) ;
402
401
self . locals [ local] = Some ( place) ;
403
402
}
403
+ }
404
404
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 } ;
408
409
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
421
476
// all the assignments, and register places for children.
422
477
let mut num_places = 0 ;
423
478
while num_places < self . places . len ( ) {
@@ -430,8 +485,11 @@ impl<'tcx> Map<'tcx> {
430
485
let mut child = self . places [ lhs] . first_child ;
431
486
while let Some ( lhs_child) = child {
432
487
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
+ ) ;
435
493
assignments. insert ( ( lhs_child, rhs_child) ) ;
436
494
child = next_sibling;
437
495
}
@@ -440,16 +498,21 @@ impl<'tcx> Map<'tcx> {
440
498
let mut child = self . places [ rhs] . first_child ;
441
499
while let Some ( rhs_child) = child {
442
500
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
+ ) ;
445
506
assignments. insert ( ( lhs_child, rhs_child) ) ;
446
507
child = next_sibling;
447
508
}
448
509
}
449
510
}
450
- drop ( assignments ) ;
511
+ }
451
512
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 > ) {
453
516
let typing_env = body. typing_env ( tcx) ;
454
517
for place_info in self . places . iter_mut ( ) {
455
518
// The user requires a bound on the number of created values.
@@ -483,8 +546,11 @@ impl<'tcx> Map<'tcx> {
483
546
self . cache_preorder_invoke ( place) ;
484
547
}
485
548
}
549
+ }
486
550
487
- // Trim useless places.
551
+ /// Trim useless places.
552
+ #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
553
+ fn trim_useless_places ( & mut self ) {
488
554
for opt_place in self . locals . iter_mut ( ) {
489
555
if let Some ( place) = * opt_place
490
556
&& self . inner_values [ place] . is_empty ( )
@@ -497,7 +563,12 @@ impl<'tcx> Map<'tcx> {
497
563
}
498
564
499
565
#[ 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 {
501
572
* self . projections . entry ( ( base, elem) ) . or_insert_with ( || {
502
573
let next = self . places . push ( PlaceInfo :: new ( ty, Some ( elem) ) ) ;
503
574
self . places [ next] . next_sibling = self . places [ base] . first_child ;
@@ -506,6 +577,46 @@ impl<'tcx> Map<'tcx> {
506
577
} )
507
578
}
508
579
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
+
509
620
/// Precompute the list of values inside `root` and store it inside
510
621
/// as a slice within `inner_values_buffer`.
511
622
fn cache_preorder_invoke ( & mut self , root : PlaceIndex ) {
@@ -530,44 +641,6 @@ struct PlaceCollector<'a, 'tcx> {
530
641
tcx : TyCtxt < ' tcx > ,
531
642
body : & ' a Body < ' tcx > ,
532
643
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
- }
571
644
}
572
645
573
646
impl < ' tcx > Visitor < ' tcx > for PlaceCollector < ' _ , ' tcx > {
@@ -577,51 +650,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> {
577
650
return ;
578
651
}
579
652
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) ;
625
654
}
626
655
}
627
656
0 commit comments