Update for recent dataflow simplifications. (#2121)

This commit is contained in:
Nicholas Nethercote 2024-11-04 15:57:00 +08:00 committed by GitHub
parent a54fe7590c
commit 2d1a0479a6
2 changed files with 16 additions and 60 deletions

View File

@ -54,13 +54,13 @@ move_data.move_paths[mpi].place
One of the first things we do in the MIR borrow check is to construct One of the first things we do in the MIR borrow check is to construct
the set of move paths. This is done as part of the the set of move paths. This is done as part of the
[`MoveData::gather_moves`] function. This function uses a MIR visitor [`MoveData::gather_moves`] function. This function uses a MIR visitor
called [`Gatherer`] to walk the MIR and look at how each [`Place`] called [`MoveDataBuilder`] to walk the MIR and look at how each [`Place`]
within is accessed. For each such [`Place`], it constructs a within is accessed. For each such [`Place`], it constructs a
corresponding [`MovePathIndex`]. It also records when/where that corresponding [`MovePathIndex`]. It also records when/where that
particular move path is moved/initialized, but we'll get to that in a particular move path is moved/initialized, but we'll get to that in a
later section. later section.
[`Gatherer`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/move_paths/builder/struct.Gatherer.html [`MoveDataBuilder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/move_paths/builder/struct.MoveDataBuilder.html
[`MoveData::gather_moves`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/move_paths/struct.MoveData.html#method.gather_moves [`MoveData::gather_moves`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/move_paths/struct.MoveData.html#method.gather_moves
### Illegal move paths ### Illegal move paths
@ -82,7 +82,7 @@ those just discussed, the function returns an `Err`. This in turn
means we don't have to bother tracking whether those places are means we don't have to bother tracking whether those places are
initialized (which lowers overhead). initialized (which lowers overhead).
[`move_path_for`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/move_paths/builder/struct.Gatherer.html#method.move_path_for [`move_path_for`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/move_paths/builder/struct.MoveDataBuilder.html#method.move_path_for
## Looking up a move-path ## Looking up a move-path

View File

@ -24,40 +24,14 @@ for the alternative lectures.
## Defining a Dataflow Analysis ## Defining a Dataflow Analysis
The interface for dataflow analyses is split into three traits. The first is A dataflow analysis is defined by the [`Analysis`] trait. In addition to the
[`AnalysisDomain`], which must be implemented by *all* analyses. In addition to type of the dataflow state, this trait defines the initial value of that state
the type of the dataflow state, this trait defines the initial value of that at entry to each block, as well as the direction of the analysis, either
state at entry to each block, as well as the direction of the analysis, either
forward or backward. The domain of your dataflow analysis must be a [lattice][] forward or backward. The domain of your dataflow analysis must be a [lattice][]
(strictly speaking a join-semilattice) with a well-behaved `join` operator. See (strictly speaking a join-semilattice) with a well-behaved `join` operator. See
documentation for the [`lattice`] module, as well as the [`JoinSemiLattice`] documentation for the [`lattice`] module, as well as the [`JoinSemiLattice`]
trait, for more information. trait, for more information.
You must then provide *either* a direct implementation of the [`Analysis`] trait
*or* an implementation of the proxy trait [`GenKillAnalysis`]. The latter is for
so-called ["gen-kill" problems], which have a simple class of transfer function
that can be applied very efficiently. Analyses whose domain is not a `BitSet`
of some index type, or whose transfer functions cannot be expressed through
"gen" and "kill" operations, must implement `Analysis` directly, and will run
slower as a result. All implementers of `GenKillAnalysis` also implement
`Analysis` automatically via a default `impl`.
```text
AnalysisDomain
^
| | = has as a supertrait
| . = provides a default impl for
|
Analysis
^ ^
| .
| .
| .
GenKillAnalysis
```
### Transfer Functions and Effects ### Transfer Functions and Effects
The dataflow framework in `rustc` allows each statement (and terminator) inside The dataflow framework in `rustc` allows each statement (and terminator) inside
@ -69,12 +43,6 @@ particular outgoing edges of some terminators (e.g.
[`apply_call_return_effect`] for the `success` edge of a `Call` [`apply_call_return_effect`] for the `success` edge of a `Call`
terminator). Collectively, these are referred to as "per-edge effects". terminator). Collectively, these are referred to as "per-edge effects".
The only meaningful difference (besides the "apply" prefix) between the methods
of the `GenKillAnalysis` trait and the `Analysis` trait is that an `Analysis`
has direct, mutable access to the dataflow state, whereas a `GenKillAnalysis`
only sees an implementer of the `GenKill` trait, which only allows the `gen`
and `kill` operations for mutation.
### "Before" Effects ### "Before" Effects
Observant readers of the documentation may notice that there are actually *two* Observant readers of the documentation may notice that there are actually *two*
@ -143,25 +111,16 @@ println!("x: {}", x);
## Inspecting the Results of a Dataflow Analysis ## Inspecting the Results of a Dataflow Analysis
Once you have constructed an analysis, you must pass it to an [`Engine`], which Once you have constructed an analysis, you must call `iterate_to_fixpoint`
is responsible for finding the steady-state solution to your dataflow problem. which will return a `Results`, which contains the dataflow state at fixpoint
You should use the [`into_engine`] method defined on the `Analysis` trait for upon entry of each block. Once you have a `Results`, you can inspect the
this, since it will use the more efficient `Engine::new_gen_kill` constructor dataflow state at fixpoint at any point in the CFG. If you only need the state
when possible. at a few locations (e.g., each `Drop` terminator) use a [`ResultsCursor`]. If
you need the state at *every* location, a [`ResultsVisitor`] will be more
Calling `iterate_to_fixpoint` on your `Engine` will return a `Results`, which efficient.
contains the dataflow state at fixpoint upon entry of each block. Once you have
a `Results`, you can inspect the dataflow state at fixpoint at any point in
the CFG. If you only need the state at a few locations (e.g., each `Drop`
terminator) use a [`ResultsCursor`]. If you need the state at *every* location,
a [`ResultsVisitor`] will be more efficient.
```text ```text
Analysis Analysis
|
| into_engine(…)
|
Engine
| |
| iterate_to_fixpoint() | iterate_to_fixpoint()
| |
@ -181,9 +140,8 @@ let mut my_visitor = MyVisitor::new();
// inspect the fixpoint state for every location within every block in RPO. // inspect the fixpoint state for every location within every block in RPO.
let results = MyAnalysis::new() let results = MyAnalysis::new()
.into_engine(tcx, body, def_id) .iterate_to_fixpoint(tcx, body, None);
.iterate_to_fixpoint() results.visit_with(body, &mut my_visitor);`
.visit_in_rpo_with(body, &mut my_visitor);
``` ```
whereas this code uses [`ResultsCursor`]: whereas this code uses [`ResultsCursor`]:
@ -222,12 +180,10 @@ the example below:
["gen-kill" problems]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems ["gen-kill" problems]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems
[*Static Program Analysis*]: https://cs.au.dk/~amoeller/spa/ [*Static Program Analysis*]: https://cs.au.dk/~amoeller/spa/
[Debugging MIR]: ./debugging.md [Debugging MIR]: ./debugging.md
[`AnalysisDomain`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.AnalysisDomain.html
[`Analysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.Analysis.html [`Analysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.Analysis.html
[`Engine`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/struct.Engine.html
[`GenKillAnalysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.GenKillAnalysis.html [`GenKillAnalysis`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.GenKillAnalysis.html
[`JoinSemiLattice`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/lattice/trait.JoinSemiLattice.html [`JoinSemiLattice`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/lattice/trait.JoinSemiLattice.html
[`NAME`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.AnalysisDomain.html#associatedconstant.NAME [`NAME`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.Analysis.html#associatedconstant.NAME
[`ResultsCursor`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/struct.ResultsCursor.html [`ResultsCursor`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/struct.ResultsCursor.html
[`ResultsVisitor`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.ResultsVisitor.html [`ResultsVisitor`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.ResultsVisitor.html
[`apply_call_return_effect`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.Analysis.html#tymethod.apply_call_return_effect [`apply_call_return_effect`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/trait.Analysis.html#tymethod.apply_call_return_effect