perf: only calculate conflicts for candidates

This commit is contained in:
Jonas Schievink 2020-05-26 22:21:10 +02:00
parent 665a98d21f
commit ab26fb140c

View File

@ -124,9 +124,22 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
return; return;
} }
let mut conflicts = Conflicts::build(tcx, body, source); let candidates = find_candidates(tcx, body);
if candidates.is_empty() {
debug!("{:?}: no dest prop candidates, done", source.def_id());
return;
}
// Collect all locals we care about. We only compute conflicts for these to save time.
let mut relevant_locals = BitSet::new_empty(body.local_decls.len());
for CandidateAssignment { dest, src, loc: _ } in &candidates {
relevant_locals.insert(dest.local);
relevant_locals.insert(*src);
}
let mut conflicts = Conflicts::build(tcx, body, source, &relevant_locals);
let mut replacements = Replacements::new(body.local_decls.len()); let mut replacements = Replacements::new(body.local_decls.len());
for candidate @ CandidateAssignment { dest, src, loc } in find_candidates(tcx, body) { for candidate @ CandidateAssignment { dest, src, loc } in candidates {
// Merge locals that don't conflict. // Merge locals that don't conflict.
if conflicts.contains(dest.local, src) { if conflicts.contains(dest.local, src) {
debug!("at assignment {:?}, conflict {:?} vs. {:?}", loc, dest.local, src); debug!("at assignment {:?}, conflict {:?} vs. {:?}", loc, dest.local, src);
@ -370,16 +383,30 @@ struct Conflicts {
} }
impl Conflicts { impl Conflicts {
fn build<'tcx>(tcx: TyCtxt<'tcx>, body: &'_ Body<'tcx>, source: MirSource<'tcx>) -> Self { fn build<'tcx>(
// We don't have to look out for locals that have their address taken, since `find_candidates` tcx: TyCtxt<'tcx>,
// already takes care of that. body: &'_ Body<'tcx>,
source: MirSource<'tcx>,
relevant_locals: &BitSet<Local>,
) -> Self {
// We don't have to look out for locals that have their address taken, since
// `find_candidates` already takes care of that.
debug!(
"Conflicts::build: {}/{} locals relevant",
relevant_locals.count(),
body.local_decls.len()
);
let mut conflicts = BitMatrix::from_row_n( let mut conflicts = BitMatrix::from_row_n(
&BitSet::new_empty(body.local_decls.len()), &BitSet::new_empty(body.local_decls.len()),
body.local_decls.len(), body.local_decls.len(),
); );
let mut record_conflicts = |new_conflicts: &BitSet<_>| { let mut record_conflicts = |new_conflicts: &mut BitSet<_>| {
// Remove all locals that are not candidates.
new_conflicts.intersect(relevant_locals);
for local in new_conflicts.iter() { for local in new_conflicts.iter() {
conflicts.union_row_with(&new_conflicts, local); conflicts.union_row_with(&new_conflicts, local);
} }
@ -449,7 +476,7 @@ impl Conflicts {
}, },
); );
let mut relevant_locals = Vec::new(); let mut live_and_init_locals = Vec::new();
// Visit only reachable basic blocks. The exact order is not important. // Visit only reachable basic blocks. The exact order is not important.
for (block, data) in traversal::preorder(body) { for (block, data) in traversal::preorder(body) {
@ -462,7 +489,7 @@ impl Conflicts {
// that, we first collect in the `MaybeInitializedLocals` results in a forwards // that, we first collect in the `MaybeInitializedLocals` results in a forwards
// traversal. // traversal.
relevant_locals.resize_with(data.statements.len() + 1, || { live_and_init_locals.resize_with(data.statements.len() + 1, || {
BitSet::new_empty(body.local_decls.len()) BitSet::new_empty(body.local_decls.len())
}); });
@ -471,7 +498,7 @@ impl Conflicts {
let loc = Location { block, statement_index }; let loc = Location { block, statement_index };
init.seek_before_primary_effect(loc); init.seek_before_primary_effect(loc);
relevant_locals[statement_index].clone_from(init.get()); live_and_init_locals[statement_index].clone_from(init.get());
} }
// Now, go backwards and union with the liveness results. // Now, go backwards and union with the liveness results.
@ -479,11 +506,11 @@ impl Conflicts {
let loc = Location { block, statement_index }; let loc = Location { block, statement_index };
live.seek_after_primary_effect(loc); live.seek_after_primary_effect(loc);
relevant_locals[statement_index].intersect(live.get()); live_and_init_locals[statement_index].intersect(live.get());
trace!("record conflicts at {:?}", loc); trace!("record conflicts at {:?}", loc);
record_conflicts(&relevant_locals[statement_index]); record_conflicts(&mut live_and_init_locals[statement_index]);
} }
init.seek_to_block_end(block); init.seek_to_block_end(block);
@ -492,7 +519,7 @@ impl Conflicts {
conflicts.intersect(live.get()); conflicts.intersect(live.get());
trace!("record conflicts at end of {:?}", block); trace!("record conflicts at end of {:?}", block);
record_conflicts(&conflicts); record_conflicts(&mut conflicts);
} }
Self { matrix: conflicts, unify_cache: BitSet::new_empty(body.local_decls.len()) } Self { matrix: conflicts, unify_cache: BitSet::new_empty(body.local_decls.len()) }