Skip to content

Commit a38991f

Browse files
committed
Small review fixes
1 parent 63d73fd commit a38991f

File tree

3 files changed

+92
-67
lines changed

3 files changed

+92
-67
lines changed

src/librustc/ty/layout.rs

+43-36
Original file line numberDiff line numberDiff line change
@@ -649,13 +649,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
649649
use SavedLocalEligibility::*;
650650

651651
let mut assignments: IndexVec<GeneratorSavedLocal, SavedLocalEligibility> =
652-
iter::repeat(Unassigned)
653-
.take(info.field_tys.len())
654-
.collect();
652+
IndexVec::from_elem_n(Unassigned, info.field_tys.len());
655653

656654
// The saved locals not eligible for overlap. These will get
657655
// "promoted" to the prefix of our generator.
658-
let mut eligible_locals = BitSet::new_filled(info.field_tys.len());
656+
let mut ineligible_locals = BitSet::new_empty(info.field_tys.len());
659657

660658
// Figure out which of our saved locals are fields in only
661659
// one variant. The rest are deemed ineligible for overlap.
@@ -670,7 +668,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
670668
// point, so it is no longer a candidate.
671669
trace!("removing local {:?} in >1 variant ({:?}, {:?})",
672670
local, variant_index, idx);
673-
eligible_locals.remove(*local);
671+
ineligible_locals.insert(*local);
674672
assignments[*local] = Ineligible(None);
675673
}
676674
Ineligible(_) => {},
@@ -681,46 +679,50 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
681679
// Next, check every pair of eligible locals to see if they
682680
// conflict.
683681
for (local_a, conflicts_a) in info.storage_conflicts.iter_enumerated() {
684-
if !eligible_locals.contains(local_a) {
682+
if ineligible_locals.contains(local_a) {
685683
continue;
686684
}
687685

688686
for local_b in conflicts_a.iter() {
689-
// local_a and local_b have overlapping storage, therefore they
687+
// local_a and local_b are storage live at the same time, therefore they
690688
// cannot overlap in the generator layout. The only way to guarantee
691689
// this is if they are in the same variant, or one is ineligible
692690
// (which means it is stored in every variant).
693-
if !eligible_locals.contains(local_b) ||
691+
if ineligible_locals.contains(local_b) ||
694692
assignments[local_a] == assignments[local_b]
695693
{
696694
continue;
697695
}
698696

699697
// If they conflict, we will choose one to make ineligible.
698+
// This is not always optimal; it's just a greedy heuristic
699+
// that seems to produce good results most of the time.
700700
let conflicts_b = &info.storage_conflicts[local_b];
701701
let (remove, other) = if conflicts_a.count() > conflicts_b.count() {
702702
(local_a, local_b)
703703
} else {
704704
(local_b, local_a)
705705
};
706-
eligible_locals.remove(remove);
706+
ineligible_locals.insert(remove);
707707
assignments[remove] = Ineligible(None);
708708
trace!("removing local {:?} due to conflict with {:?}", remove, other);
709709
}
710710
}
711711

712-
let mut ineligible_locals = BitSet::new_filled(info.field_tys.len());
713-
ineligible_locals.subtract(&eligible_locals);
714-
715712
// Write down the order of our locals that will be promoted to
716713
// the prefix.
717-
for (idx, local) in ineligible_locals.iter().enumerate() {
718-
assignments[local] = Ineligible(Some(idx as u32));
714+
{
715+
let mut idx = 0u32;
716+
for local in ineligible_locals.iter() {
717+
assignments[local] = Ineligible(Some(idx));
718+
idx += 1;
719+
}
719720
}
720721
debug!("generator saved local assignments: {:?}", assignments);
721722

722723
// Build a prefix layout, including "promoting" all ineligible
723-
// locals as part of the prefix.
724+
// locals as part of the prefix. We compute the layout of all of
725+
// these fields at once to get optimal packing.
724726
let discr_index = substs.prefix_tys(def_id, tcx).count();
725727
let promoted_tys =
726728
ineligible_locals.iter().map(|local| subst_field(info.field_tys[local]));
@@ -733,20 +735,23 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
733735
StructKind::AlwaysSized)?;
734736
let (prefix_size, prefix_align) = (prefix.size, prefix.align);
735737

736-
// Split the prefix layout into the "outer" fields (upvars and
737-
// discriminant) and the "promoted" fields. Promoted fields will
738-
// get included in each variant that requested them in
739-
// GeneratorLayout.
740-
let renumber_indices = |mut index: Vec<u32>| -> Vec<u32> {
741-
debug!("renumber_indices({:?})", index);
742-
let mut inverse_index = (0..index.len() as u32).collect::<Vec<_>>();
743-
inverse_index.sort_unstable_by_key(|i| index[*i as usize]);
738+
let recompute_memory_index = |offsets: &Vec<u32>| -> Vec<u32> {
739+
debug!("recompute_memory_index({:?})", offsets);
740+
let mut inverse_index = (0..offsets.len() as u32).collect::<Vec<_>>();
741+
inverse_index.sort_unstable_by_key(|i| offsets[*i as usize]);
742+
743+
let mut index = vec![0; offsets.len()];
744744
for i in 0..index.len() {
745745
index[inverse_index[i] as usize] = i as u32;
746746
}
747-
debug!("renumber_indices() => {:?}", index);
747+
debug!("recompute_memory_index() => {:?}", index);
748748
index
749749
};
750+
751+
// Split the prefix layout into the "outer" fields (upvars and
752+
// discriminant) and the "promoted" fields. Promoted fields will
753+
// get included in each variant that requested them in
754+
// GeneratorLayout.
750755
debug!("prefix = {:#?}", prefix);
751756
let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields {
752757
FieldPlacement::Arbitrary { offsets, memory_index } => {
@@ -756,11 +761,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
756761
memory_index.split_at(discr_index + 1);
757762
let outer_fields = FieldPlacement::Arbitrary {
758763
offsets: offsets_a.to_vec(),
759-
memory_index: renumber_indices(memory_index_a.to_vec())
764+
memory_index: recompute_memory_index(&memory_index_a.to_vec())
760765
};
761766
(outer_fields,
762767
offsets_b.to_vec(),
763-
renumber_indices(memory_index_b.to_vec()))
768+
recompute_memory_index(&memory_index_b.to_vec()))
764769
}
765770
_ => bug!(),
766771
};
@@ -769,15 +774,17 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
769774
let mut align = prefix.align;
770775
let variants = info.variant_fields.iter_enumerated().map(|(index, variant_fields)| {
771776
// Only include overlap-eligible fields when we compute our variant layout.
772-
let variant_only_tys = variant_fields.iter().flat_map(|local| {
773-
let ty = info.field_tys[*local];
774-
match assignments[*local] {
775-
Unassigned => bug!(),
776-
Assigned(v) if v == index => Some(subst_field(ty)),
777-
Assigned(_) => bug!("assignment does not match variant"),
778-
Ineligible(_) => None,
779-
}
780-
});
777+
let variant_only_tys = variant_fields
778+
.iter()
779+
.filter(|local| {
780+
match assignments[**local] {
781+
Unassigned => bug!(),
782+
Assigned(v) if v == index => true,
783+
Assigned(_) => bug!("assignment does not match variant"),
784+
Ineligible(_) => false,
785+
}
786+
})
787+
.map(|local| subst_field(info.field_tys[*local]));
781788

782789
let mut variant = univariant_uninterned(
783790
&variant_only_tys
@@ -823,7 +830,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
823830
}
824831
variant.fields = FieldPlacement::Arbitrary {
825832
offsets: combined_offsets,
826-
memory_index: renumber_indices(combined_memory_index),
833+
memory_index: recompute_memory_index(&combined_memory_index),
827834
};
828835

829836
size = size.max(variant.size);

src/librustc_mir/dataflow/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ fn for_each_block_location<'tcx, T: BitDenotation<'tcx>>(
431431
let term_loc = Location { block, statement_index: mir[block].statements.len() };
432432
analysis.before_terminator_effect(&mut sets, term_loc);
433433
f(sets.gen_set, term_loc);
434-
analysis.before_statement_effect(&mut sets, term_loc);
434+
analysis.terminator_effect(&mut sets, term_loc);
435435
f(sets.gen_set, term_loc);
436436
}
437437
}

src/librustc_mir/transform/generator.rs

+48-30
Original file line numberDiff line numberDiff line change
@@ -394,17 +394,33 @@ impl<'tcx> Visitor<'tcx> for StorageIgnored {
394394
}
395395
}
396396

397+
struct LivenessInfo {
398+
/// Which locals are live across any suspension point.
399+
///
400+
/// GeneratorSavedLocal is indexed in terms of the elements in this set;
401+
/// i.e. GeneratorSavedLocal::new(1) corresponds to the second local
402+
/// included in this set.
403+
live_locals: liveness::LiveVarSet,
404+
405+
/// The set of saved locals live at each suspension point.
406+
live_locals_at_suspension_points: Vec<BitSet<GeneratorSavedLocal>>,
407+
408+
/// For every saved local, the set of other saved locals that are
409+
/// storage-live at the same time as this local. We cannot overlap locals in
410+
/// the layout which have conflicting storage.
411+
storage_conflicts: IndexVec<GeneratorSavedLocal, BitSet<GeneratorSavedLocal>>,
412+
413+
/// For every suspending block, the locals which are storage-live across
414+
/// that suspension point.
415+
storage_liveness: FxHashMap<BasicBlock, liveness::LiveVarSet>,
416+
}
417+
397418
fn locals_live_across_suspend_points(
398419
tcx: TyCtxt<'a, 'tcx, 'tcx>,
399420
body: &Body<'tcx>,
400421
source: MirSource<'tcx>,
401422
movable: bool,
402-
) -> (
403-
liveness::LiveVarSet,
404-
Vec<BitSet<GeneratorSavedLocal>>,
405-
IndexVec<GeneratorSavedLocal, BitSet<GeneratorSavedLocal>>,
406-
FxHashMap<BasicBlock, liveness::LiveVarSet>,
407-
) {
423+
) -> LivenessInfo {
408424
let dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
409425
let def_id = source.def_id();
410426

@@ -434,7 +450,7 @@ fn locals_live_across_suspend_points(
434450
};
435451

436452
// Calculate the liveness of MIR locals ignoring borrows.
437-
let mut set = liveness::LiveVarSet::new_empty(body.local_decls.len());
453+
let mut live_locals = liveness::LiveVarSet::new_empty(body.local_decls.len());
438454
let mut liveness = liveness::liveness_of_locals(
439455
body,
440456
);
@@ -489,36 +505,40 @@ fn locals_live_across_suspend_points(
489505
// Locals live are live at this point only if they are used across
490506
// suspension points (the `liveness` variable)
491507
// and their storage is live (the `storage_liveness` variable)
492-
storage_liveness.intersect(&liveness.outs[block]);
508+
let mut live_locals_here = storage_liveness;
509+
live_locals_here.intersect(&liveness.outs[block]);
493510

494511
// The generator argument is ignored
495-
storage_liveness.remove(self_arg());
496-
497-
let live_locals = storage_liveness;
512+
live_locals_here.remove(self_arg());
498513

499514
// Add the locals live at this suspension point to the set of locals which live across
500515
// any suspension points
501-
set.union(&live_locals);
516+
live_locals.union(&live_locals_here);
502517

503-
live_locals_at_suspension_points.push(live_locals);
518+
live_locals_at_suspension_points.push(live_locals_here);
504519
}
505520
}
506521

507522
// Renumber our liveness_map bitsets to include only the locals we are
508523
// saving.
509524
let live_locals_at_suspension_points = live_locals_at_suspension_points
510525
.iter()
511-
.map(|live_locals| renumber_bitset(&live_locals, &set))
526+
.map(|live_here| renumber_bitset(&live_here, &live_locals))
512527
.collect();
513528

514529
let storage_conflicts = compute_storage_conflicts(
515530
body,
516-
&set,
531+
&live_locals,
517532
&ignored,
518533
storage_live,
519534
storage_live_analysis);
520535

521-
(set, live_locals_at_suspension_points, storage_conflicts, storage_liveness_map)
536+
LivenessInfo {
537+
live_locals,
538+
live_locals_at_suspension_points,
539+
storage_conflicts,
540+
storage_liveness: storage_liveness_map,
541+
}
522542
}
523543

524544
/// For every saved local, looks for which locals are StorageLive at the same
@@ -555,14 +575,11 @@ fn compute_storage_conflicts(
555575
eligible_storage_live.intersect(&stored_locals);
556576

557577
for local in eligible_storage_live.iter() {
558-
let mut overlaps = eligible_storage_live.clone();
559-
overlaps.remove(local);
560-
local_conflicts[local].union(&overlaps);
578+
local_conflicts[local].union(&eligible_storage_live);
579+
}
561580

562-
if !overlaps.is_empty() {
563-
trace!("at {:?}, local {:?} conflicts with {:?}",
564-
loc, local, overlaps);
565-
}
581+
if eligible_storage_live.count() > 1 {
582+
trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live);
566583
}
567584
});
568585

@@ -617,8 +634,9 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
617634
FxHashMap<BasicBlock, liveness::LiveVarSet>)
618635
{
619636
// Use a liveness analysis to compute locals which are live across a suspension point
620-
let (live_locals, live_locals_at_suspension_points, storage_conflicts, storage_liveness) =
621-
locals_live_across_suspend_points(tcx, body, source, movable);
637+
let LivenessInfo {
638+
live_locals, live_locals_at_suspension_points, storage_conflicts, storage_liveness
639+
} = locals_live_across_suspend_points(tcx, body, source, movable);
622640

623641
// Erase regions from the types passed in from typeck so we can compare them with
624642
// MIR types
@@ -673,11 +691,11 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
673691
let mut fields = IndexVec::new();
674692
for (idx, saved_local) in live_locals.iter().enumerate() {
675693
fields.push(saved_local);
676-
// Note that if a field is included in multiple variants, it will be
677-
// added overwritten here. That's fine; fields do not move around
678-
// inside generators, so it doesn't matter which variant index we
679-
// access them by.
680-
remap.insert(locals[saved_local], (tys[saved_local], variant_index, idx));
694+
// Note that if a field is included in multiple variants, we will
695+
// just use the first one here. That's fine; fields do not move
696+
// around inside generators, so it doesn't matter which variant
697+
// index we access them by.
698+
remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx));
681699
}
682700
variant_fields.push(fields);
683701
}

0 commit comments

Comments
 (0)