Skip to content

Commit 6680d03

Browse files
committed
Use BitMatrix for storage conflicts
1 parent 66e7493 commit 6680d03

File tree

3 files changed

+32
-29
lines changed

3 files changed

+32
-29
lines changed

src/librustc/mir/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::hir::def_id::DefId;
99
use crate::hir::{self, InlineAsm as HirInlineAsm};
1010
use crate::mir::interpret::{ConstValue, InterpError, Scalar};
1111
use crate::mir::visit::MirVisitable;
12-
use rustc_data_structures::bit_set::BitSet;
12+
use rustc_data_structures::bit_set::BitMatrix;
1313
use rustc_data_structures::fx::FxHashSet;
1414
use rustc_data_structures::graph::dominators::{dominators, Dominators};
1515
use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
@@ -3008,7 +3008,7 @@ pub struct GeneratorLayout<'tcx> {
30083008
/// Which saved locals are storage-live at the same time. Locals that do not
30093009
/// have conflicts with each other are allowed to overlap in the computed
30103010
/// layout.
3011-
pub storage_conflicts: IndexVec<GeneratorSavedLocal, BitSet<GeneratorSavedLocal>>,
3011+
pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
30123012

30133013
/// Names and scopes of all the stored generator locals.
30143014
/// NOTE(tmandry) This is *strictly* a temporary hack for codegen
@@ -3586,7 +3586,7 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
35863586
}
35873587
}
35883588

3589-
impl<'tcx, T: Idx> TypeFoldable<'tcx> for BitSet<T> {
3589+
impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
35903590
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self {
35913591
self.clone()
35923592
}

src/librustc/ty/layout.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -678,12 +678,13 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
678678

679679
// Next, check every pair of eligible locals to see if they
680680
// conflict.
681-
for (local_a, conflicts_a) in info.storage_conflicts.iter_enumerated() {
681+
for local_a in info.storage_conflicts.rows() {
682+
let conflicts_a = info.storage_conflicts.count(local_a);
682683
if ineligible_locals.contains(local_a) {
683684
continue;
684685
}
685686

686-
for local_b in conflicts_a.iter() {
687+
for local_b in info.storage_conflicts.iter(local_a) {
687688
// local_a and local_b are storage live at the same time, therefore they
688689
// cannot overlap in the generator layout. The only way to guarantee
689690
// this is if they are in the same variant, or one is ineligible
@@ -697,8 +698,8 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
697698
// If they conflict, we will choose one to make ineligible.
698699
// This is not always optimal; it's just a greedy heuristic
699700
// that seems to produce good results most of the time.
700-
let conflicts_b = &info.storage_conflicts[local_b];
701-
let (remove, other) = if conflicts_a.count() > conflicts_b.count() {
701+
let conflicts_b = info.storage_conflicts.count(local_b);
702+
let (remove, other) = if conflicts_a > conflicts_b {
702703
(local_a, local_b)
703704
} else {
704705
(local_b, local_a)

src/librustc_mir/transform/generator.rs

+24-22
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ use rustc::ty::layout::VariantIdx;
5959
use rustc::ty::subst::SubstsRef;
6060
use rustc_data_structures::fx::FxHashMap;
6161
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
62-
use rustc_data_structures::bit_set::BitSet;
62+
use rustc_data_structures::bit_set::{BitSet, BitMatrix};
6363
use std::borrow::Cow;
6464
use std::iter;
6565
use std::mem;
@@ -408,7 +408,7 @@ struct LivenessInfo {
408408
/// For every saved local, the set of other saved locals that are
409409
/// storage-live at the same time as this local. We cannot overlap locals in
410410
/// the layout which have conflicting storage.
411-
storage_conflicts: IndexVec<GeneratorSavedLocal, BitSet<GeneratorSavedLocal>>,
411+
storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
412412

413413
/// For every suspending block, the locals which are storage-live across
414414
/// that suspension point.
@@ -551,7 +551,9 @@ fn compute_storage_conflicts(
551551
ignored: &StorageIgnored,
552552
storage_live: DataflowResults<'tcx, MaybeStorageLive<'mir, 'tcx>>,
553553
storage_live_analysis: MaybeStorageLive<'mir, 'tcx>,
554-
) -> IndexVec<GeneratorSavedLocal, BitSet<GeneratorSavedLocal>> {
554+
) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
555+
assert_eq!(body.local_decls.len(), ignored.0.domain_size());
556+
assert_eq!(body.local_decls.len(), stored_locals.domain_size());
555557
debug!("compute_storage_conflicts({:?})", body.span);
556558
debug!("ignored = {:?}", ignored.0);
557559

@@ -564,18 +566,15 @@ fn compute_storage_conflicts(
564566
// liveness. Those that do must be in the same variant to remain candidates.
565567
// FIXME(tmandry): Consider using sparse bitsets here once we have good
566568
// benchmarks for generators.
567-
let mut local_conflicts: IndexVec<Local, _> =
568-
// Add conflicts for every ineligible local.
569-
iter::repeat(ineligible_locals.clone())
570-
.take(body.local_decls.len())
571-
.collect();
569+
let mut local_conflicts: BitMatrix<Local, Local> =
570+
BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len());
572571

573572
for_each_location(body, &storage_live_analysis, &storage_live, |state, loc| {
574573
let mut eligible_storage_live = state.clone().to_dense();
575574
eligible_storage_live.intersect(&stored_locals);
576575

577576
for local in eligible_storage_live.iter() {
578-
local_conflicts[local].union(&eligible_storage_live);
577+
local_conflicts.union_row_with(&eligible_storage_live, local);
579578
}
580579

581580
if eligible_storage_live.count() > 1 {
@@ -588,19 +587,22 @@ fn compute_storage_conflicts(
588587
// However, in practice these bitsets are not usually large. The layout code
589588
// also needs to keep track of how many conflicts each local has, so it's
590589
// simpler to keep it this way for now.
591-
let storage_conflicts: IndexVec<GeneratorSavedLocal, _> = stored_locals
592-
.iter()
593-
.map(|local_a| {
594-
if ineligible_locals.contains(local_a) {
595-
// Conflicts with everything.
596-
BitSet::new_filled(stored_locals.count())
597-
} else {
598-
// Keep overlap information only for stored locals.
599-
renumber_bitset(&local_conflicts[local_a], stored_locals)
590+
let mut storage_conflicts = BitMatrix::new(stored_locals.count(), stored_locals.count());
591+
for (idx_a, local_a) in stored_locals.iter().enumerate() {
592+
let saved_local_a = GeneratorSavedLocal::new(idx_a);
593+
if ineligible_locals.contains(local_a) {
594+
// Conflicts with everything.
595+
storage_conflicts.insert_all_into_row(saved_local_a);
596+
} else {
597+
// Keep overlap information only for stored locals.
598+
for (idx_b, local_b) in stored_locals.iter().enumerate() {
599+
let saved_local_b = GeneratorSavedLocal::new(idx_b);
600+
if local_conflicts.contains(local_a, local_b) {
601+
storage_conflicts.insert(saved_local_a, saved_local_b);
602+
}
600603
}
601-
})
602-
.collect();
603-
604+
}
605+
}
604606
storage_conflicts
605607
}
606608

@@ -700,7 +702,7 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
700702
variant_fields.push(fields);
701703
}
702704
debug!("generator variant_fields = {:?}", variant_fields);
703-
debug!("generator storage_conflicts = {:?}", storage_conflicts);
705+
debug!("generator storage_conflicts = {:#?}", storage_conflicts);
704706

705707
let layout = GeneratorLayout {
706708
field_tys: tys,

0 commit comments

Comments
 (0)