-
Notifications
You must be signed in to change notification settings - Fork 12.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #71956 - ecstatic-morse:remove-requires-storage-analysi…
…s, r=tmandry Clean up logic around live locals in generator analysis Resolves #69902. Requires #71893. I've found it difficult to make changes in the logic around live locals in `generator/transform.rs`. It uses a custom dataflow analysis, `MaybeRequiresStorage`, that AFAICT computes whether a local is either initialized or borrowed. That analysis is using `before` effects, which we should try to avoid if possible because they are harder to reason about than ones only using the unprefixed effects. @pnkfelix has suggested removing "before" effects entirely to simplify the dataflow framework, which I might pursue someday. This PR replaces `MaybeRequiresStorage` with a combination of the existing `MaybeBorrowedLocals` and a new `MaybeInitializedLocals`. `MaybeInitializedLocals` is just `MaybeInitializedPlaces` with a coarser resolution: it works on whole locals instead of move paths. As a result, I was able to simplify the logic in `compute_storage_conflicts` and `locals_live_across_suspend_points`. This is not exactly equivalent to the old logic; some generators are now smaller than before. I believe this was because the old logic was too conservative, but I'm not as familiar with the constraints as the original implementers were, so I could be wrong. For example, I don't see a reason the size of the `mixed_sizes` future couldn't be 5K. It went from 7K to 6K in this PR. r? @jonas-schievink @tmandry
- Loading branch information
Showing
7 changed files
with
254 additions
and
372 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
//! A less precise version of `MaybeInitializedPlaces` whose domain is entire locals. | ||
//! | ||
//! A local will be maybe initialized if *any* projections of that local might be initialized. | ||
|
||
use crate::dataflow::{self, BottomValue, GenKill}; | ||
|
||
use rustc_index::bit_set::BitSet; | ||
use rustc_middle::mir::visit::{PlaceContext, Visitor}; | ||
use rustc_middle::mir::{self, BasicBlock, Local, Location}; | ||
|
||
pub struct MaybeInitializedLocals; | ||
|
||
impl BottomValue for MaybeInitializedLocals { | ||
/// bottom = uninit | ||
const BOTTOM_VALUE: bool = false; | ||
} | ||
|
||
impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals { | ||
type Idx = Local; | ||
|
||
const NAME: &'static str = "maybe_init_locals"; | ||
|
||
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { | ||
body.local_decls.len() | ||
} | ||
|
||
fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut BitSet<Self::Idx>) { | ||
// Function arguments are initialized to begin with. | ||
for arg in body.args_iter() { | ||
entry_set.insert(arg); | ||
} | ||
} | ||
} | ||
|
||
impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals { | ||
// The generator transform relies on the fact that this analysis does **not** use "before" | ||
// effects. | ||
|
||
fn statement_effect( | ||
&self, | ||
trans: &mut impl GenKill<Self::Idx>, | ||
statement: &mir::Statement<'tcx>, | ||
loc: Location, | ||
) { | ||
TransferFunction { trans }.visit_statement(statement, loc) | ||
} | ||
|
||
fn terminator_effect( | ||
&self, | ||
trans: &mut impl GenKill<Self::Idx>, | ||
terminator: &mir::Terminator<'tcx>, | ||
loc: Location, | ||
) { | ||
TransferFunction { trans }.visit_terminator(terminator, loc) | ||
} | ||
|
||
fn call_return_effect( | ||
&self, | ||
trans: &mut impl GenKill<Self::Idx>, | ||
_block: BasicBlock, | ||
_func: &mir::Operand<'tcx>, | ||
_args: &[mir::Operand<'tcx>], | ||
return_place: mir::Place<'tcx>, | ||
) { | ||
trans.gen(return_place.local) | ||
} | ||
|
||
/// See `Analysis::apply_yield_resume_effect`. | ||
fn yield_resume_effect( | ||
&self, | ||
trans: &mut impl GenKill<Self::Idx>, | ||
_resume_block: BasicBlock, | ||
resume_place: mir::Place<'tcx>, | ||
) { | ||
trans.gen(resume_place.local) | ||
} | ||
} | ||
|
||
struct TransferFunction<'a, T> { | ||
trans: &'a mut T, | ||
} | ||
|
||
impl<T> Visitor<'tcx> for TransferFunction<'a, T> | ||
where | ||
T: GenKill<Local>, | ||
{ | ||
fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { | ||
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext}; | ||
match context { | ||
// These are handled specially in `call_return_effect` and `yield_resume_effect`. | ||
PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {} | ||
|
||
// Otherwise, when a place is mutated, we must consider it possibly initialized. | ||
PlaceContext::MutatingUse(_) => self.trans.gen(local), | ||
|
||
// If the local is moved out of, or if it gets marked `StorageDead`, consider it no | ||
// longer initialized. | ||
PlaceContext::NonUse(NonUseContext::StorageDead) | ||
| PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => self.trans.kill(local), | ||
|
||
// All other uses do not affect this analysis. | ||
PlaceContext::NonUse( | ||
NonUseContext::StorageLive | ||
| NonUseContext::AscribeUserTy | ||
| NonUseContext::VarDebugInfo, | ||
) | ||
| PlaceContext::NonMutatingUse( | ||
NonMutatingUseContext::Inspect | ||
| NonMutatingUseContext::Copy | ||
| NonMutatingUseContext::SharedBorrow | ||
| NonMutatingUseContext::ShallowBorrow | ||
| NonMutatingUseContext::UniqueBorrow | ||
| NonMutatingUseContext::AddressOf | ||
| NonMutatingUseContext::Projection, | ||
) => {} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.