| Age | Commit message (Collapse) | Author | Lines |
|
Those effects are untested and unused. Remove them along with
the implementation of `BasicBlocks::switch_sources`.
|
|
Fix a mix-up of a block with its predecessors in handling of SwitchInt
edge effects for backward analysis. Note that this functionality is
currently unused, so change has no practical impact.
|
|
|
|
`Results` contains and `Analysis` and an `EntryStates`. The unfortunate
thing about this is that the analysis needs to be mutable everywhere
(`&mut Analysis`) which forces the `Results` to be mutable everywhere,
even though `EntryStates` is immutable everywhere.
To fix this, this commit renames `Results` as `AnalysisAndResults`,
renames `EntryStates` as `Results`, and separates the analysis and
results as much as possible. (`AnalysisAndResults` doesn't get much use,
it's mostly there to facilitate method chaining of
`iterate_to_fixpoint`.)
`Results` is immutable everywhere, which:
- is a bit clearer on how the data is used,
- avoids an unnecessary clone of entry states in
`locals_live_across_suspend_points`, and
- moves the results outside the `RefCell` in Formatter.
The commit also reformulates `ResultsHandle` as the generic `CowMut`,
which is simpler than `ResultsHandle` because it doesn't need the
`'tcx` lifetime and the trait bounds. It also which sits nicely
alongside the new use of `Cow` in `ResultsCursor`.
|
|
Every `Results` contains an `Analysis`, but these methods only need the
`Analysis`. No point passing them more data than they need.
|
|
|
|
It's only passed to `Analysis::apply_switch_int_edge_effect`, and the
existing impls of that method only use the `value` field. So pass that
instead.
|
|
This is much clearer than `Option<u128>`.
|
|
Very minor changes that will make the next few commits easier to follow.
|
|
|
|
It is possible to avoid the clone as suggested in the comment. It would
require introducing an enum with two variants
`CloneBeforeModifying(&Domain)` and `Modifiable(&mut Domain)`. But it's
not worth the effort, because this code path just isn't very hot. E.g.
when compiling a large benchmark like `cargo-0.60.0` it's only hit a few
thousand times.
|
|
Switches to the idiom used elsewhere of calling `Analysis::bottom_value`
to initialize a `state` value outside a loop, and then using
`clone_from` to update it within the loop. This is simpler and has no
impact on performance.
|
|
Current `SwitchInt` handling has complicated control flow.
- The dataflow engine calls `Analysis::apply_switch_int_edge_effects`,
passing in an "applier" that impls `SwitchIntEdgeEffects`.
- `apply_switch_int_edge_effects` possibly calls `apply` on the applier,
passing it a closure.
- The `apply` method calls the closure on each `SwitchInt` edge.
- The closure operates on the edge.
I.e. control flow goes from the engine, to the analysis, to the applier
(which came from the engine), to the closure (which came from the
analysis). It took me a while to work this out.
This commit changes to a simpler structure that maintains the important
characteristics.
- The dataflow engine calls `Analysis::get_switch_int_data`.
- `get_switch_int_data` returns an `Option<Self::SwitchIntData>` value.
- If that returned value was `Some`, the dataflow engine calls
`Analysis::apply_switch_int_edge_effect` on each edge, passing the
`Self::SwitchIntData` value.
- `Analysis::apply_switch_int_edge_effect` operates on the edge.
I.e. control flow goes from the engine, to the analysis, to the
engine, to the analysis.
Added:
- The `Analysis::SwitchIntData` assoc type and the
`Analysis::get_switch_int_data` method. Both only need to be
defined by analyses that look at `SwitchInt` terminators.
- The `MaybePlacesSwitchIntData` struct, which has three fields.
Changes:
- `Analysis::apply_switch_int_edge_effects` becomes
`Analysis::apply_switch_int_edge_effect`, which is a little simpler
because it's dealing with a single edge instead of all edges.
Removed:
- The `SwitchIntEdgeEffects` trait, and its two impls:
`BackwardSwitchIntEdgeEffectsApplier` (which has six fields) and
`ForwardSwitchIntEdgeEffectsApplier` structs (which has four fields).
- The closure.
The new structure is more concise and simpler.
|
|
The words "before" and "after" have an obvious temporal meaning, e.g.
`seek_before_primary_effect`,
`visit_statement_{before,after}_primary_effect`. But "before" is also
used to name the effect that occurs before the primary effect of a
statement/terminator; this is `Effect::Before`. This leads to the
confusing possibility of talking about things happening "before/after
the before event".
This commit removes this awkward overloading of "before" by renaming
`Effect::Before` as `Effect::Early`. It also renames some of the
`Analysis` and `ResultsVisitor` methods to be more consistent.
Here are the before and after names:
- `Effect::{Before,Primary}` -> `Effect::{Early,Primary}`
- `apply_before_statement_effect` -> `apply_early_statement_effect`
- `apply_statement_effect` -> `apply_primary_statement_effect`
- `visit_statement_before_primary_effect` -> `visit_after_early_statement_effect`
- `visit_statement_after_primary_effect` -> `visit_after_primary_statement_effect`
(And s/statement/terminator/ for all the terminator events.)
|
|
Describing some things that took me a long time to understand.
|
|
They are always called in succession, so it's simpler if they are merged
into a single function.
|
|
Now that `Results` is the only impl of `ResultsVisitable`, the trait can
be removed. This simplifies things by removining unnecessary layers of
indirection and abstraction.
- `ResultsVisitor` is simpler.
- Its type parameter changes from `R` (an analysis result) to the
simpler `A` (an analysis).
- It no longer needs the `Domain` associated type, because it can use
`A::Domain`.
- Occurrences of `R` become `Results<'tcx, A>`, because there is now
only one kind of analysis results.
- `save_as_intervals` also changes type parameter from `R` to `A`.
- The `results.reconstruct_*` method calls are replaced with
`results.analysis.apply_*` method calls, which are equivalent.
- `Direction::visit_results_in_block` is simpler, with a single generic
param (`A`) instead of two (`D` and `R`/`F`, with a bound connecting
them). Likewise for `visit_results`.
- The `ResultsVisitor` impls for `MirBorrowCtxt` and
`StorageConflictVisitor` are now specific about the type of the
analysis results they work with. They both used to have a type param
`R` but they weren't genuinely generic. In both cases there was only a
single results type that made sense to instantiate them with.
|
|
This is an alternative to `Engine::new_generic` for gen/kill analyses.
It's supposed to be an optimization, but it has negligible effect.
The commit merges `Engine::new_generic` into `Engine::new`.
This allows the removal of various other things: `GenKillSet`,
`gen_kill_statement_effects_in_block`, `is_cfg_cyclic`.
|
|
Because that's what it is; no point having a different name for it.
|
|
The previous commit updated `rustfmt.toml` appropriately. This commit is
the outcome of running `x fmt --all` with the new formatting options.
|
|
|
|
|
|
Some types have a `body: &'mir Body<'tcx>` and some have `body: &'a
Body<'tcx>`. The former is more readable, so this commit converts some
fo the latter to the former.
|
|
`x clippy compiler -Aclippy::all -Wclippy::needless_borrow --fix`.
Then I had to remove a few unnecessary parens and muts that were exposed
now.
|
|
|
|
|
|
|
|
|
|
|
|
Take MIR dataflow analyses by mutable reference
The main motivation here is any analysis requiring dynamically sized scratch memory to work. One concrete example would be pointer target tracking, where tracking the results of a dereference can result in multiple possible targets. This leads to processing multi-level dereferences requiring the ability to handle a changing number of potential targets per step. A (simplified) function for this would be `fn apply_deref(potential_targets: &mut Vec<Target>)` which would use the scratch space contained in the analysis to send arguments and receive the results.
The alternative to this would be to wrap everything in a `RefCell`, which is what `MaybeRequiresStorage` currently does. This comes with a small perf cost and loses the compiler's guarantee that we don't try to take multiple borrows at the same time.
For the implementation:
* `AnalysisResults` is an unfortunate requirement to avoid an unconstrained type parameter error.
* `CloneAnalysis` could just be `Clone` instead, but that would result in more work than is required to have multiple cursors over the same result set.
* `ResultsVisitor` now takes the results type on in each function as there's no other way to have access to the analysis without cloning it. This could use an associated type rather than a type parameter, but the current approach makes it easier to not care about the type when it's not necessary.
* `MaybeRequiresStorage` now no longer uses a `RefCell`, but the graphviz formatter now does. It could be removed, but that would require even more changes and doesn't really seem necessary.
|
|
|
|
|
|
Unify terminology used in unwind action and terminator, and reflect
the fact that a nounwind panic is triggered instead of an immediate
abort is triggered for this terminator.
|
|
|
|
PR 107844 made DropAndReplace unused, let's remove it completely
from the codebase.
|
|
As a part of drop elaboration, we identify dead unwinds, i.e., unwind
edges on a drop terminators which are known to be unreachable, because
there is no need to drop anything.
Previously, the data flow framework was informed about the dead unwinds,
and it assumed those edges are absent from MIR. Unfortunately, the data
flow framework wasn't consistent in maintaining this assumption.
In particular, if a block was reachable only through a dead unwind edge,
its state was propagated to other blocks still. This became an issue in
the context of change removes DropAndReplace terminator, since it
introduces initialization into cleanup blocks.
To avoid this issue, remove unreachable unwind edges before the drop
elaboration, and elaborate only blocks that remain reachable.
|
|
Dead unwinds set contains a head of an unreachable unwind edge.
|
|
|
|
|
|
|
|
Make it explicit that the analysis direction is constant.
This also makes the value immediately available for optimizations.
Previously those functions were neither inline nor generic and so their
definition was unavailable when using data flow framework from other
crates.
|
|
|
|
|
|
to avoid quadratic space overhead
|
|
Switch sources are used by backward analysis with a custom switch int
edge effects, but are otherwise unnecessarily computed.
Delay the computation until we know that switch sources are indeed
required and avoid the computation otherwise.
|
|
|
|
* Add lazily computed `switch_sources` data structure
* Don't assume a target has only one associated value
|
|
|
|
See #91867 for more information.
|
|
|