forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#41625 - nikomatsakis:incr-comp-dep-tracking…
…-cell-mir, r=eddyb rework the queries for the MIR pipeline This PR refashions the MIR pipeline. There are a number of changes: * We no longer have "MIR passes" and the pass manager is completely reworked. Unless we are doing the interprocedural optimization (meaning, right now, the inline pass), we will process a single MIR from beginning to finish in a completely on-demand fashion; i.e., when you request `optimized_mir(D)`, that will trigger the MIR for `D` to actually be built and optimized, but no other functions are built or touched. * We no longer use `&'tcx RefCell<Mir<'tcx>>` as the result of queries, since that spoils the view of queries as "pure functions". To avoid however copying the MIR, we use a `&'tcx Steal<Mir<'tcx>>` -- this is something like a ref-cell, in that you can use `borrow()` to read it, but it has no `borrow_mut()`. Instead, it has `steal()`, which will take the contents and then panic if any further read attempt occurs. * We now support `[multi]` queries, which can optionally yield not just one result but a sequence of (K, V) pairs. This is used for the inlining pass. If inlining is enabled, then when it is invoked on **any** def-id D, it will go and read the results for **all** def-ids and transform them, and then return the results for all of them at once. This isn't ideal, and we'll probably want to rework this further, but it seems ok for now (note that MIR inlining is not enabled by default). **Tips for the reviewer:** The commits here are meant to build individually, but the path is a *bit* meandering. In some cases, for example, I introduce a trait in one commit, and then tweak it in a later commit as I actually try to put it to use. You may want to read the README in the final commit to get a sense of where the overall design is headed. @eddyb I did not wind up adding support for queries that produce more than one *kind* of result. Instead, I decided to just insert judicious use of the `force()` command. In other words, we had talked about e.g. having a query that produced not only the MIR but also the `const_qualif` result for the MIR in one sweep. I realized you can also have the same effect by having a kind of meta-query that forces the const-qualif pass and then reads the result. See the README for a description. (We can still do these "multi-query results" later if we want, I'm not sure though if it is necessary.) r? @eddyb cc @michaelwoerister @matthewhammer @arielb1, who participated in the IRC discussion.
- Loading branch information
Showing
54 changed files
with
1,263 additions
and
1,278 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
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
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
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,90 @@ | ||
# MIR definition and pass system | ||
|
||
This file contains the definition of the MIR datatypes along with the | ||
various types for the "MIR Pass" system, which lets you easily | ||
register and define new MIR transformations and analyses. | ||
|
||
Most of the code that operates on MIR can be found in the | ||
`librustc_mir` crate or other crates. The code found here in | ||
`librustc` is just the datatype definitions, alonging the functions | ||
which operate on MIR to be placed everywhere else. | ||
|
||
## MIR Data Types and visitor | ||
|
||
The main MIR data type is `rustc::mir::Mir`, defined in `mod.rs`. | ||
There is also the MIR visitor (in `visit.rs`) which allows you to walk | ||
the MIR and override what actions will be taken at various points (you | ||
can visit in either shared or mutable mode; the latter allows changing | ||
the MIR in place). Finally `traverse.rs` contains various traversal | ||
routines for visiting the MIR CFG in [different standard orders][traversal] | ||
(e.g. pre-order, reverse post-order, and so forth). | ||
|
||
[traversal]: https://en.wikipedia.org/wiki/Tree_traversal | ||
|
||
## MIR pass suites and their integration into the query system | ||
|
||
As a MIR *consumer*, you are expected to use one of the queries that | ||
returns a "final MIR". As of the time of this writing, there is only | ||
one: `optimized_mir(def_id)`, but more are expected to come in the | ||
future. For foreign def-ids, we simply read the MIR from the other | ||
crate's metadata. But for local query, this query will construct the | ||
MIR and then iteratively optimize it by putting it through various | ||
pipeline stages. This section describes those pipeline stages and how | ||
you can extend them. | ||
|
||
To produce the `optimized_mir(D)` for a given def-id `D`, the MIR | ||
passes through several suites of optimizations, each represented by a | ||
query. Each suite consists of multiple optimizations and | ||
transformations. These suites represent useful intermediate points | ||
where we want to access the MIR for type checking or other purposes: | ||
|
||
- `mir_build(D)` -- not a query, but this constructs the initial MIR | ||
- `mir_const(D)` -- applies some simple transformations to make MIR ready for constant evaluation; | ||
- `mir_validated(D)` -- applies some more transformations, making MIR ready for borrow checking; | ||
- `optimized_mir(D)` -- the final state, after all optimizations have been performed. | ||
|
||
### Stealing | ||
|
||
The intermediate queries `mir_const()` and `mir_validated()` yield up | ||
a `&'tcx Steal<Mir<'tcx>>`, allocated using | ||
`tcx.alloc_steal_mir()`. This indicates that the result may be | ||
**stolen** by the next suite of optimizations -- this is an | ||
optimization to avoid cloning the MIR. Attempting to use a stolen | ||
result will cause a panic in the compiler. Therefore, it is important | ||
that you not read directly from these intermediate queries except as | ||
part of the MIR processing pipeline. | ||
|
||
Because of this stealing mechanism, some care must also be taken to | ||
ensure that, before the MIR at a particular phase in the processing | ||
pipeline is stolen, anyone who may want to read from it has already | ||
done so. Concretely, this means that if you have some query `foo(D)` | ||
that wants to access the result of `mir_const(D)` or | ||
`mir_validated(D)`, you need to have the successor pass either "force" | ||
`foo(D)` using `ty::queries::foo::force(...)`. This will force a query | ||
to execute even though you don't directly require its result. | ||
|
||
As an example, consider MIR const qualification. It wants to read the | ||
result produced by the `mir_const()` suite. However, that result will | ||
be **stolen** by the `mir_validated()` suite. If nothing was done, | ||
then `mir_const_qualif(D)` would succeed if it came before | ||
`mir_validated(D)`, but fail otherwise. Therefore, `mir_validated(D)` | ||
will **force** `mir_const_qualif` before it actually steals, thus | ||
ensuring that the reads have already happened: | ||
|
||
``` | ||
mir_const(D) --read-by--> mir_const_qualif(D) | ||
| ^ | ||
stolen-by | | ||
| (forces) | ||
v | | ||
mir_validated(D) ------------+ | ||
``` | ||
|
||
### Implementing and registering a pass | ||
|
||
To create a new MIR pass, you simply implement the `MirPass` trait for | ||
some fresh singleton type `Foo`. Once you have implemented a trait for | ||
your type `Foo`, you then have to insert `Foo` into one of the suites; | ||
this is done in `librustc_driver/driver.rs` by invoking `push_pass(S, | ||
Foo)` with the appropriate suite substituted for `S`. | ||
|
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.