Auto merge of #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`
This commit is contained in:
commit
0e2c1281e9
23 changed files with 974 additions and 705 deletions
|
@ -1,4 +1,6 @@
|
|||
use rustc_ast as ast;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use rustc_ast::ast;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
@ -16,7 +18,7 @@ use crate::dataflow::impls::{
|
|||
use crate::dataflow::move_paths::{HasMoveData, MoveData};
|
||||
use crate::dataflow::move_paths::{LookupResult, MovePathIndex};
|
||||
use crate::dataflow::MoveDataParamEnv;
|
||||
use crate::dataflow::{Analysis, Results, ResultsCursor};
|
||||
use crate::dataflow::{Analysis, JoinSemiLattice, Results, ResultsCursor};
|
||||
|
||||
pub struct SanityCheck;
|
||||
|
||||
|
@ -248,25 +250,26 @@ pub trait RustcPeekAt<'tcx>: Analysis<'tcx> {
|
|||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
flow_state: &BitSet<Self::Idx>,
|
||||
flow_state: &Self::Domain,
|
||||
call: PeekCall,
|
||||
);
|
||||
}
|
||||
|
||||
impl<'tcx, A> RustcPeekAt<'tcx> for A
|
||||
impl<'tcx, A, D> RustcPeekAt<'tcx> for A
|
||||
where
|
||||
A: Analysis<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>,
|
||||
A: Analysis<'tcx, Domain = D> + HasMoveData<'tcx>,
|
||||
D: JoinSemiLattice + Clone + Borrow<BitSet<MovePathIndex>>,
|
||||
{
|
||||
fn peek_at(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
flow_state: &BitSet<Self::Idx>,
|
||||
flow_state: &Self::Domain,
|
||||
call: PeekCall,
|
||||
) {
|
||||
match self.move_data().rev_lookup.find(place.as_ref()) {
|
||||
LookupResult::Exact(peek_mpi) => {
|
||||
let bit_state = flow_state.contains(peek_mpi);
|
||||
let bit_state = flow_state.borrow().contains(peek_mpi);
|
||||
debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state);
|
||||
if !bit_state {
|
||||
tcx.sess.span_err(call.span, "rustc_peek: bit not set");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue