@@ -56,12 +56,13 @@ use crate::transform::simplify;
56
56
use crate :: transform:: { MirPass , MirSource } ;
57
57
use crate :: util:: dump_mir;
58
58
use crate :: util:: liveness;
59
+ use crate :: util:: storage;
59
60
use rustc_data_structures:: fx:: FxHashMap ;
60
61
use rustc_hir as hir;
61
62
use rustc_hir:: def_id:: DefId ;
62
63
use rustc_index:: bit_set:: { BitMatrix , BitSet } ;
63
64
use rustc_index:: vec:: { Idx , IndexVec } ;
64
- use rustc_middle:: mir:: visit:: { MutVisitor , PlaceContext , Visitor } ;
65
+ use rustc_middle:: mir:: visit:: { MutVisitor , PlaceContext } ;
65
66
use rustc_middle:: mir:: * ;
66
67
use rustc_middle:: ty:: subst:: SubstsRef ;
67
68
use rustc_middle:: ty:: GeneratorSubsts ;
@@ -222,6 +223,9 @@ struct TransformVisitor<'tcx> {
222
223
// A list of suspension points, generated during the transform
223
224
suspension_points : Vec < SuspensionPoint < ' tcx > > ,
224
225
226
+ // The set of locals that have no `StorageLive`/`StorageDead` annotations.
227
+ always_live_locals : storage:: AlwaysLiveLocals ,
228
+
225
229
// The original RETURN_PLACE local
226
230
new_ret_local : Local ,
227
231
}
@@ -416,19 +420,6 @@ fn replace_local<'tcx>(
416
420
new_local
417
421
}
418
422
419
- struct StorageIgnored ( liveness:: LiveVarSet ) ;
420
-
421
- impl < ' tcx > Visitor < ' tcx > for StorageIgnored {
422
- fn visit_statement ( & mut self , statement : & Statement < ' tcx > , _location : Location ) {
423
- match statement. kind {
424
- StatementKind :: StorageLive ( l) | StatementKind :: StorageDead ( l) => {
425
- self . 0 . remove ( l) ;
426
- }
427
- _ => ( ) ,
428
- }
429
- }
430
- }
431
-
432
423
struct LivenessInfo {
433
424
/// Which locals are live across any suspension point.
434
425
///
@@ -454,23 +445,19 @@ fn locals_live_across_suspend_points(
454
445
tcx : TyCtxt < ' tcx > ,
455
446
body : ReadOnlyBodyAndCache < ' _ , ' tcx > ,
456
447
source : MirSource < ' tcx > ,
448
+ always_live_locals : & storage:: AlwaysLiveLocals ,
457
449
movable : bool ,
458
450
) -> LivenessInfo {
459
451
let def_id = source. def_id ( ) ;
460
452
let body_ref: & Body < ' _ > = & body;
461
453
462
454
// Calculate when MIR locals have live storage. This gives us an upper bound of their
463
455
// lifetimes.
464
- let mut storage_live = MaybeStorageLive
456
+ let mut storage_live = MaybeStorageLive :: new ( always_live_locals . clone ( ) )
465
457
. into_engine ( tcx, body_ref, def_id)
466
458
. iterate_to_fixpoint ( )
467
459
. into_results_cursor ( body_ref) ;
468
460
469
- // Find the MIR locals which do not use StorageLive/StorageDead statements.
470
- // The storage of these locals are always live.
471
- let mut ignored = StorageIgnored ( BitSet :: new_filled ( body. local_decls . len ( ) ) ) ;
472
- ignored. visit_body ( & body) ;
473
-
474
461
// Calculate the MIR locals which have been previously
475
462
// borrowed (even if they are still active).
476
463
let borrowed_locals_results =
@@ -515,11 +502,13 @@ fn locals_live_across_suspend_points(
515
502
}
516
503
517
504
storage_live. seek_before ( loc) ;
518
- let storage_liveness = storage_live. get ( ) ;
505
+ let mut storage_liveness = storage_live. get ( ) . clone ( ) ;
506
+
507
+ storage_liveness. remove ( SELF_ARG ) ;
519
508
520
509
// Store the storage liveness for later use so we can restore the state
521
510
// after a suspension point
522
- storage_liveness_map. insert ( block, storage_liveness. clone ( ) ) ;
511
+ storage_liveness_map. insert ( block, storage_liveness) ;
523
512
524
513
requires_storage_cursor. seek_before ( loc) ;
525
514
let storage_required = requires_storage_cursor. get ( ) . clone ( ) ;
@@ -551,8 +540,12 @@ fn locals_live_across_suspend_points(
551
540
. map ( |live_here| renumber_bitset ( & live_here, & live_locals) )
552
541
. collect ( ) ;
553
542
554
- let storage_conflicts =
555
- compute_storage_conflicts ( body_ref, & live_locals, & ignored, requires_storage_results) ;
543
+ let storage_conflicts = compute_storage_conflicts (
544
+ body_ref,
545
+ & live_locals,
546
+ always_live_locals. clone ( ) ,
547
+ requires_storage_results,
548
+ ) ;
556
549
557
550
LivenessInfo {
558
551
live_locals,
@@ -590,18 +583,18 @@ fn renumber_bitset(
590
583
fn compute_storage_conflicts (
591
584
body : & ' mir Body < ' tcx > ,
592
585
stored_locals : & liveness:: LiveVarSet ,
593
- ignored : & StorageIgnored ,
586
+ always_live_locals : storage :: AlwaysLiveLocals ,
594
587
requires_storage : dataflow:: Results < ' tcx , MaybeRequiresStorage < ' mir , ' tcx > > ,
595
588
) -> BitMatrix < GeneratorSavedLocal , GeneratorSavedLocal > {
596
- assert_eq ! ( body. local_decls. len( ) , ignored. 0 . domain_size( ) ) ;
597
589
assert_eq ! ( body. local_decls. len( ) , stored_locals. domain_size( ) ) ;
590
+
598
591
debug ! ( "compute_storage_conflicts({:?})" , body. span) ;
599
- debug ! ( "ignored = {:?}" , ignored . 0 ) ;
592
+ debug ! ( "always_live = {:?}" , always_live_locals ) ;
600
593
601
- // Storage ignored locals are not eligible for overlap, since their storage
602
- // is always live .
603
- let mut ineligible_locals = ignored . 0 . clone ( ) ;
604
- ineligible_locals. intersect ( & stored_locals) ;
594
+ // Locals that are always live or ones that need to be stored across
595
+ // suspension points are not eligible for overlap .
596
+ let mut ineligible_locals = always_live_locals . into_inner ( ) ;
597
+ ineligible_locals. intersect ( stored_locals) ;
605
598
606
599
// Compute the storage conflicts for all eligible locals.
607
600
let mut visitor = StorageConflictVisitor {
@@ -697,6 +690,7 @@ fn compute_layout<'tcx>(
697
690
source : MirSource < ' tcx > ,
698
691
upvars : & Vec < Ty < ' tcx > > ,
699
692
interior : Ty < ' tcx > ,
693
+ always_live_locals : & storage:: AlwaysLiveLocals ,
700
694
movable : bool ,
701
695
body : & mut BodyAndCache < ' tcx > ,
702
696
) -> (
@@ -710,7 +704,13 @@ fn compute_layout<'tcx>(
710
704
live_locals_at_suspension_points,
711
705
storage_conflicts,
712
706
storage_liveness,
713
- } = locals_live_across_suspend_points ( tcx, read_only ! ( body) , source, movable) ;
707
+ } = locals_live_across_suspend_points (
708
+ tcx,
709
+ read_only ! ( body) ,
710
+ source,
711
+ always_live_locals,
712
+ movable,
713
+ ) ;
714
714
715
715
// Erase regions from the types passed in from typeck so we can compare them with
716
716
// MIR types
@@ -1180,7 +1180,10 @@ fn create_cases<'tcx>(
1180
1180
}
1181
1181
1182
1182
let l = Local :: new ( i) ;
1183
- if point. storage_liveness . contains ( l) && !transform. remap . contains_key ( & l) {
1183
+ let needs_storage_live = point. storage_liveness . contains ( l)
1184
+ && !transform. remap . contains_key ( & l)
1185
+ && !transform. always_live_locals . contains ( l) ;
1186
+ if needs_storage_live {
1184
1187
statements
1185
1188
. push ( Statement { source_info, kind : StatementKind :: StorageLive ( l) } ) ;
1186
1189
}
@@ -1276,11 +1279,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
1276
1279
} ,
1277
1280
) ;
1278
1281
1282
+ let always_live_locals = storage:: AlwaysLiveLocals :: new ( & body) ;
1283
+
1279
1284
// Extract locals which are live across suspension point into `layout`
1280
1285
// `remap` gives a mapping from local indices onto generator struct indices
1281
1286
// `storage_liveness` tells us which locals have live storage at suspension points
1282
1287
let ( remap, layout, storage_liveness) =
1283
- compute_layout ( tcx, source, & upvars, interior, movable, body) ;
1288
+ compute_layout ( tcx, source, & upvars, interior, & always_live_locals , movable, body) ;
1284
1289
1285
1290
let can_return = can_return ( tcx, body) ;
1286
1291
@@ -1294,6 +1299,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
1294
1299
state_substs,
1295
1300
remap,
1296
1301
storage_liveness,
1302
+ always_live_locals,
1297
1303
suspension_points : Vec :: new ( ) ,
1298
1304
new_ret_local,
1299
1305
discr_ty,
0 commit comments