Update for recent dataflow simplifications. (#2121)
This commit is contained in:
parent
a54fe7590c
commit
2d1a0479a6
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue