| Age | Commit message (Collapse) | Author | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Also add unit tests
|
|
|
|
|
|
|
|
|
|
Index impl, remove body fn
rustc_codegen_ssa: Fix BodyAndCache reborrow to Body and change instances of body() call to derefence
rustc_mir: Fix BodyAndCache reborrow to Body and change intances of body() call to derefence
|
|
rename all body_cache back to body
|
|
|
|
(lifetime errors still exist)
|
|
(ReadOnly)BodyCache type errors
|
|
invalidate cache when accessing unique terminator
|
|
|
|
This prepares the code base for when projection is interned. Place's
projection field is going to be `&List<PlaceElem<'tcx>>` so we won't be
able to pattern match against it.
|
|
|
|
Make `into` schedule drop for the destination
closes #47949
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This adds a dataflow analysis that determines if a reference to a given
`Local` or part of a `Local` that would allow mutation exists before a
point in the CFG. If no such reference exists, we know for sure that
that `Local` cannot have been mutated via an indirect assignment or
function call.
|
|
|
|
|
|
Add a `Place::is_indirect` method to determine whether a `Place` contains a `Deref` projection
Working on #63860 requires tracking some property about each local. This requires differentiating `Place`s like `x` and `x.field[index]` from ones like `*x` and `*x.field`, since the first two will always access the same region of memory as `x` while the latter two may access any region of memory. This functionality is duplicated in various places across the compiler. This PR adds a helper method to `Place` which determines whether that `Place` has a `Deref` projection at any point and changes some existing code to use the new method.
I've not converted `qualify_consts.rs` to use the new method, since it's not a trivial conversion and it will get replaced anyway by #63860. There may be other potential uses besides the two I change in this PR.
r? @oli-obk
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Don't store locals that have been moved from in generators
This avoids reserving storage in generators for locals that are moved
out of (and not re-initialized) prior to yield points. Fixes #59123.
This adds a new dataflow analysis, `RequiresStorage`, to determine whether the storage of a local can be destroyed without being observed by the program. The rules are:
1. StorageLive(x) => mark x live
2. StorageDead(x) => mark x dead
3. If a local is moved from, _and has never had its address taken_, mark it dead
4. If (any part of) a local is initialized, mark it live'
This is used to determine whether to save a local in the generator object at all, as well as which locals can be overlapped in the generator layout.
Here's the size in bytes of all testcases included in the change, before and after the change:
async fn test |Size before |Size after
-----------------|------------|----------
single | 1028 | 1028
single_with_noop | 2056 | 1032
joined | 5132 | 3084
joined_with_noop | 8208 | 3084
generator test |Size before |Size after
----------------------------|------------|----------
move_before_yield | 1028 | 1028
move_before_yield_with_noop | 2056 | 1032
overlap_move_points | 3080 | 2056
## Future work
Note that there is a possible extension to this optimization, which modifies rule 3 to read: "If a local is moved from, _**and either has never had its address taken, or is Freeze and has never been mutably borrowed**_, mark it dead." This was discussed at length in #59123 and then #61849. Because this would cause some behavior to be UB which was not UB before, it's a step that needs to be taken carefully.
A more immediate priority for me is inlining `std::mem::size_of_val(&x)` so it becomes apparent that the address of `x` is not taken. This way, using `size_of_val` to look at the size of your inner futures does not affect the size of your outer future.
cc @cramertj @eddyb @Matthias247 @nikomatsakis @RalfJung @Zoxc
|
|
|
|
|
|
|
|
This avoids reserving storage in generators for locals that are moved
out of (and not re-initialized) prior to yield points.
|
|
|
|
Since the value of `InitialFlow` defines the semantics of the `join`
operation, there's no reason to have seperate traits for each. We can
add a default impl of `join` which branches based on `BOTTOM_VALUE`.
This should get optimized away.
|
|
This commit makes `sets.on_entry` inaccessible in
`{before_,}{statement,terminator}_effect`. This field was meant to allow
implementors of `BitDenotation` to access the initial state for each
block (optionally with the effect of all previous statements applied via
`accumulates_intrablock_state`) while defining transfer functions.
However, the ability to set the initial value for the entry set of each
basic block (except for START_BLOCK) no longer exists. As a result, this
functionality is mostly useless, and when it *was* used it was used
erroneously (see #62007).
Since `on_entry` is now useless, we can also remove `BlockSets`, which
held the `gen`, `kill`, and `on_entry` bitvectors and replace it with a
`GenKill` struct. Variables of this type are called `trans` since they
represent a transfer function. `GenKill`s are stored contiguously in
`AllSets`, which reduces the number of bounds checks and may improve
cache performance: one is almost never accessed without the other.
Replacing `BlockSets` with `GenKill` allows us to define some new helper
functions which streamline dataflow iteration and the
dataflow-at-location APIs. Notably, `state_for_location` used a subtle
side-effect of the `kill`/`kill_all` setters to apply the transfer
function, and could be incorrect if a transfer function depended on
effects of previous statements in the block on `gen_set`.
|
|
Resolves #62007.
Due to a bug, the previous version of this check did not actually kill
any conflicting borrows unless the borrowed place had no projections.
Specifically, `entry_set` will always be empty when `statement_effect`
is called. It does not contain the set of borrows which are live at this
point in the program.
|