@@ -370,21 +370,20 @@ impl<'tcx> Map<'tcx> {
370
370
inner_values : IndexVec :: new ( ) ,
371
371
inner_values_buffer : Vec :: new ( ) ,
372
372
} ;
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 ( ) ;
375
378
debug ! ( "registered {} places ({} nodes in total)" , map. value_count, map. places. len( ) ) ;
376
379
map
377
380
}
378
381
379
382
/// Register all non-excluded places that have scalar layout.
380
383
#[ 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
+
388
387
// Start by constructing the places for each bare local.
389
388
for ( local, decl) in body. local_decls . iter_enumerated ( ) {
390
389
if exclude. contains ( local) {
@@ -399,23 +398,79 @@ impl<'tcx> Map<'tcx> {
399
398
let place = self . places . push ( PlaceInfo :: new ( decl. ty , None ) ) ;
400
399
self . locals [ local] = Some ( place) ;
401
400
}
401
+ }
402
402
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 } ;
406
407
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
419
474
// all the assignments, and register places for children.
420
475
let mut num_places = 0 ;
421
476
while num_places < self . places . len ( ) {
@@ -428,8 +483,11 @@ impl<'tcx> Map<'tcx> {
428
483
let mut child = self . places [ lhs] . first_child ;
429
484
while let Some ( lhs_child) = child {
430
485
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
+ ) ;
433
491
assignments. insert ( ( lhs_child, rhs_child) ) ;
434
492
child = next_sibling;
435
493
}
@@ -438,16 +496,21 @@ impl<'tcx> Map<'tcx> {
438
496
let mut child = self . places [ rhs] . first_child ;
439
497
while let Some ( rhs_child) = child {
440
498
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
+ ) ;
443
504
assignments. insert ( ( lhs_child, rhs_child) ) ;
444
505
child = next_sibling;
445
506
}
446
507
}
447
508
}
448
- drop ( assignments ) ;
509
+ }
449
510
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 > ) {
451
514
let typing_env = body. typing_env ( tcx) ;
452
515
for place_info in self . places . iter_mut ( ) {
453
516
// The user requires a bound on the number of created values.
@@ -481,8 +544,11 @@ impl<'tcx> Map<'tcx> {
481
544
self . cache_preorder_invoke ( place) ;
482
545
}
483
546
}
547
+ }
484
548
485
- // Trim useless places.
549
+ /// Trim useless places.
550
+ #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
551
+ fn trim_useless_places ( & mut self ) {
486
552
for opt_place in self . locals . iter_mut ( ) {
487
553
if let Some ( place) = * opt_place
488
554
&& self . inner_values [ place] . is_empty ( )
@@ -495,7 +561,12 @@ impl<'tcx> Map<'tcx> {
495
561
}
496
562
497
563
#[ 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 {
499
570
* self . projections . entry ( ( base, elem) ) . or_insert_with ( || {
500
571
let next = self . places . push ( PlaceInfo :: new ( ty, Some ( elem) ) ) ;
501
572
self . places [ next] . next_sibling = self . places [ base] . first_child ;
@@ -504,6 +575,46 @@ impl<'tcx> Map<'tcx> {
504
575
} )
505
576
}
506
577
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
+
507
618
/// Precompute the list of values inside `root` and store it inside
508
619
/// as a slice within `inner_values_buffer`.
509
620
fn cache_preorder_invoke ( & mut self , root : PlaceIndex ) {
@@ -528,44 +639,6 @@ struct PlaceCollector<'a, 'tcx> {
528
639
tcx : TyCtxt < ' tcx > ,
529
640
body : & ' a Body < ' tcx > ,
530
641
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
- }
569
642
}
570
643
571
644
impl < ' tcx > Visitor < ' tcx > for PlaceCollector < ' _ , ' tcx > {
@@ -575,51 +648,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, 'tcx> {
575
648
return ;
576
649
}
577
650
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) ;
623
652
}
624
653
}
625
654
0 commit comments