Refactor MIR phases
This commit is contained in:
parent
9f4d5d2a28
commit
aad14c701e
17 changed files with 289 additions and 186 deletions
|
@ -23,75 +23,110 @@ use rustc_span::symbol::Symbol;
|
|||
use rustc_span::Span;
|
||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||
|
||||
/// The various "big phases" that MIR goes through.
|
||||
/// Represents the "flavors" of MIR.
|
||||
///
|
||||
/// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the
|
||||
/// dialects forbid certain variants or values in certain phases. The sections below summarize the
|
||||
/// changes, but do not document them thoroughly. The full documentation is found in the appropriate
|
||||
/// documentation for the thing the change is affecting.
|
||||
/// All flavors of MIR use the same data structure, but there are some important differences. These
|
||||
/// differences come in two forms: Dialects and phases.
|
||||
///
|
||||
/// Warning: ordering of variants is significant.
|
||||
/// Dialects represent a stronger distinction than phases. This is because the transitions between
|
||||
/// dialects are semantic changes, and therefore technically *lowerings* between distinct IRs. In
|
||||
/// other words, the same [`Body`](crate::mir::Body) might be well-formed for multiple dialects, but
|
||||
/// have different semantic meaning and different behavior at runtime.
|
||||
///
|
||||
/// Each dialect additionally has a number of phases. However, phase changes never involve semantic
|
||||
/// changes. If some MIR is well-formed both before and after a phase change, it is also guaranteed
|
||||
/// that it has the same semantic meaning. In this sense, phase changes can only add additional
|
||||
/// restrictions on what MIR is well-formed.
|
||||
///
|
||||
/// When adding phases, remember to update [`MirPhase::phase_index`].
|
||||
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(HashStable)]
|
||||
pub enum MirPhase {
|
||||
/// The dialect of MIR used during all phases before `DropsLowered` is the same. This is also
|
||||
/// the MIR that analysis such as borrowck uses.
|
||||
/// The MIR that is generated by MIR building.
|
||||
///
|
||||
/// One important thing to remember about the behavior of this section of MIR is that drop terminators
|
||||
/// (including drop and replace) are *conditional*. The elaborate drops pass will then replace each
|
||||
/// instance of a drop terminator with a nop, an unconditional drop, or a drop conditioned on a drop
|
||||
/// flag. Of course, this means that it is important that the drop elaboration can accurately recognize
|
||||
/// when things are initialized and when things are de-initialized. That means any code running on this
|
||||
/// version of MIR must be sure to produce output that drop elaboration can reason about. See the
|
||||
/// section on the drop terminatorss for more details.
|
||||
Built = 0,
|
||||
// FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
|
||||
// We used to have this for pre-miri MIR based const eval.
|
||||
Const = 1,
|
||||
/// This phase checks the MIR for promotable elements and takes them out of the main MIR body
|
||||
/// by creating a new MIR body per promoted element. After this phase (and thus the termination
|
||||
/// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir`
|
||||
/// query.
|
||||
ConstsPromoted = 2,
|
||||
/// After this projections may only contain deref projections as the first element.
|
||||
Derefered = 3,
|
||||
/// Beginning with this phase, the following variants are disallowed:
|
||||
/// * [`TerminatorKind::DropAndReplace`]
|
||||
/// The only things that operate on this dialect are unsafeck, the various MIR lints, and const
|
||||
/// qualifs.
|
||||
///
|
||||
/// This has no distinct phases.
|
||||
Built,
|
||||
/// The MIR used for most analysis.
|
||||
///
|
||||
/// The only semantic change between analysis and built MIR is constant promotion. In built MIR,
|
||||
/// sequences of statements that would generally be subject to constant promotion are
|
||||
/// semantically constants, while in analysis MIR all constants are explicit.
|
||||
///
|
||||
/// The result of const promotion is available from the `mir_promoted` and `promoted_mir` queries.
|
||||
///
|
||||
/// This is the version of MIR used by borrowck and friends.
|
||||
Analysis(AnalysisPhase),
|
||||
/// The MIR used for CTFE, optimizations, and codegen.
|
||||
///
|
||||
/// The semantic changes that occur in the lowering from analysis to runtime MIR are as follows:
|
||||
///
|
||||
/// - Drops: In analysis MIR, `Drop` terminators represent *conditional* drops; roughly speaking,
|
||||
/// if dataflow analysis determines that the place being dropped is uninitialized, the drop will
|
||||
/// not be executed. The exact semantics of this aren't written down anywhere, which means they
|
||||
/// are essentially "what drop elaboration does." In runtime MIR, the drops are unconditional;
|
||||
/// when a `Drop` terminator is reached, if the type has drop glue that drop glue is always
|
||||
/// executed. This may be UB if the underlying place is not initialized.
|
||||
/// - Packed drops: Places might in general be misaligned - in most cases this is UB, the exception
|
||||
/// is fields of packed structs. In analysis MIR, `Drop(P)` for a `P` that might be misaligned
|
||||
/// for this reason implicitly moves `P` to a temporary before dropping. Runtime MIR has no such
|
||||
/// rules, and dropping a misaligned place is simply UB.
|
||||
/// - Unwinding: in analysis MIR, unwinding from a function which may not unwind aborts. In runtime
|
||||
/// MIR, this is UB.
|
||||
/// - Retags: If `-Zmir-emit-retag` is enabled, analysis MIR has "implicit" retags in the same way
|
||||
/// that Rust itself has them. Where exactly these are is generally subject to change, and so we
|
||||
/// don't document this here. Runtime MIR has all retags explicit.
|
||||
/// - Generator bodies: In analysis MIR, locals may actually be behind a pointer that user code has
|
||||
/// access to. This occurs in generator bodies. Such locals do not behave like other locals,
|
||||
/// because they eg may be aliased in surprising ways. Runtime MIR has no such special locals -
|
||||
/// all generator bodies are lowered and so all places that look like locals really are locals.
|
||||
/// - Const prop lints: The lint pass which reports eg `200_u8 + 200_u8` as an error is run as a
|
||||
/// part of analysis to runtime MIR lowering. This means that transformations which may supress
|
||||
/// such errors may not run on analysis MIR.
|
||||
Runtime(RuntimePhase),
|
||||
}
|
||||
|
||||
/// See [`MirPhase::Analysis`].
|
||||
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(HashStable)]
|
||||
pub enum AnalysisPhase {
|
||||
Initial = 0,
|
||||
/// Beginning in this phase, the following variants are disallowed:
|
||||
/// * [`TerminatorKind::FalseUnwind`]
|
||||
/// * [`TerminatorKind::FalseEdge`]
|
||||
/// * [`StatementKind::FakeRead`]
|
||||
/// * [`StatementKind::AscribeUserType`]
|
||||
/// * [`Rvalue::Ref`] with `BorrowKind::Shallow`
|
||||
///
|
||||
/// And the following variant is allowed:
|
||||
/// * [`StatementKind::Retag`]
|
||||
///
|
||||
/// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop`
|
||||
/// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands
|
||||
/// are allowed for non-`Copy` types.
|
||||
DropsLowered = 4,
|
||||
/// Beginning with this phase, the following variant is disallowed:
|
||||
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
|
||||
///
|
||||
/// And the following variant is allowed:
|
||||
/// * [`StatementKind::SetDiscriminant`]
|
||||
Deaggregated = 5,
|
||||
/// Before this phase, generators are in the "source code" form, featuring `yield` statements
|
||||
/// and such. With this phase change, they are transformed into a proper state machine. Running
|
||||
/// optimizations before this change can be potentially dangerous because the source code is to
|
||||
/// some extent a "lie." In particular, `yield` terminators effectively make the value of all
|
||||
/// locals visible to the caller. This means that dead store elimination before them, or code
|
||||
/// motion across them, is not correct in general. This is also exasperated by type checking
|
||||
/// having pre-computed a list of the types that it thinks are ok to be live across a yield
|
||||
/// point - this is necessary to decide eg whether autotraits are implemented. Introducing new
|
||||
/// types across a yield point will lead to ICEs becaues of this.
|
||||
///
|
||||
/// Beginning with this phase, the following variants are disallowed:
|
||||
/// Furthermore, `Deref` projections must be the first projection within any place (if they
|
||||
/// appear at all)
|
||||
PostCleanup = 1,
|
||||
}
|
||||
|
||||
/// See [`MirPhase::Runtime`].
|
||||
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(HashStable)]
|
||||
pub enum RuntimePhase {
|
||||
/// In addition to the semantic changes, beginning with this phase, the following variants are
|
||||
/// disallowed:
|
||||
/// * [`TerminatorKind::DropAndReplace`]
|
||||
/// * [`TerminatorKind::Yield`]
|
||||
/// * [`TerminatorKind::GeneratorDrop`]
|
||||
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
|
||||
///
|
||||
/// And the following variants are allowed:
|
||||
/// * [`StatementKind::Retag`]
|
||||
/// * [`StatementKind::SetDiscriminant`]
|
||||
/// * [`StatementKind::Deinit`]
|
||||
///
|
||||
/// Furthermore, `Copy` operands are allowed for non-`Copy` types.
|
||||
Initial = 0,
|
||||
/// Beginning with this phase, the following variant is disallowed:
|
||||
/// * [`ProjectionElem::Deref`] of `Box`
|
||||
GeneratorsLowered = 6,
|
||||
Optimized = 7,
|
||||
PostCleanup = 1,
|
||||
Optimized = 2,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue