Skip to content

Commit 3ffe9f8

Browse files
committed
Auto merge of rust-lang#76044 - ecstatic-morse:dataflow-lattice, r=oli-obk
Support dataflow problems on arbitrary lattices This PR implements last of the proposed extensions I mentioned in the design meeting for the original dataflow refactor. It extends the current dataflow framework to work with arbitrary lattices, not just `BitSet`s. This is a prerequisite for dataflow-enabled MIR const-propagation. Personally, I am skeptical of the usefulness of doing const-propagation pre-monomorphization, since many useful constants only become known after monomorphization (e.g. `size_of::<T>()`) and users have a natural tendency to hand-optimize the rest. It's probably worth exprimenting with, however, and others have shown interest cc `@rust-lang/wg-mir-opt.` The `Idx` associated type is moved from `AnalysisDomain` to `GenKillAnalysis` and replaced with an associated `Domain` type that must implement `JoinSemiLattice`. Like before, each `Analysis` defines the "bottom value" for its domain, but can no longer override the dataflow join operator. Analyses that want to use set intersection must now use the `lattice::Dual` newtype. `GenKillAnalysis` impls have an additional requirement that `Self::Domain: BorrowMut<BitSet<Self::Idx>>`, which effectively means that they must use `BitSet<Self::Idx>` or `lattice::Dual<BitSet<Self::Idx>>` as their domain. Most of these changes were mechanical. However, because a `Domain` is no longer always a powerset of some index type, we can no longer use an `IndexVec<BasicBlock, GenKillSet<A::Idx>>>` to store cached block transfer functions. Instead, we use a boxed `dyn Fn` trait object. I discuss a few alternatives to the current approach in a commit message. The majority of new lines of code are to preserve existing Graphviz diagrams for those unlucky enough to have to debug dataflow analyses. I find these diagrams incredibly useful when things are going wrong and considered regressing them unacceptable, especially the pretty-printing of `MovePathIndex`s, which are used in many dataflow analyses. This required a parallel `fmt` trait used only for printing dataflow domains, as well as a refactoring of the `graphviz` module now that we cannot expect the domain to be a `BitSet`. Some features did have to be removed, such as the gen/kill display mode (which I didn't use but existed to mirror the output of the old dataflow framework) and line wrapping. Since I had to rewrite much of it anyway, I took the opportunity to switch to a `Visitor` for printing dataflow state diffs instead of using cursors, which are error prone for code that must be generic over both forward and backward analyses. As a side-effect of this change, we no longer have quadratic behavior when writing graphviz diagrams for backward dataflow analyses. r? `@pnkfelix`
2 parents 4286d9c + 1c5b0fb commit 3ffe9f8

File tree

1 file changed

+7
-10
lines changed

1 file changed

+7
-10
lines changed

clippy_lints/src/redundant_clone.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use rustc_middle::mir::{
1414
visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
1515
};
1616
use rustc_middle::ty::{self, fold::TypeVisitor, Ty};
17-
use rustc_mir::dataflow::BottomValue;
1817
use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
1918
use rustc_session::{declare_lint_pass, declare_tool_lint};
2019
use rustc_span::source_map::{BytePos, Span};
@@ -411,21 +410,24 @@ impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor {
411410
struct MaybeStorageLive;
412411

413412
impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
414-
type Idx = mir::Local;
413+
type Domain = BitSet<mir::Local>;
415414
const NAME: &'static str = "maybe_storage_live";
416415

417-
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
418-
body.local_decls.len()
416+
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
417+
// bottom = dead
418+
BitSet::new_empty(body.local_decls.len())
419419
}
420420

421-
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
421+
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
422422
for arg in body.args_iter() {
423423
state.insert(arg);
424424
}
425425
}
426426
}
427427

428428
impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
429+
type Idx = mir::Local;
430+
429431
fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
430432
match stmt.kind {
431433
mir::StatementKind::StorageLive(l) => trans.gen(l),
@@ -454,11 +456,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
454456
}
455457
}
456458

457-
impl BottomValue for MaybeStorageLive {
458-
/// bottom = dead
459-
const BOTTOM_VALUE: bool = false;
460-
}
461-
462459
/// Collects the possible borrowers of each local.
463460
/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
464461
/// possible borrowers of `a`.

0 commit comments

Comments
 (0)