Skip to content

Commit cfff369

Browse files
authored
Rollup merge of #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.
2 parents 1a5284c + 488b2a3 commit cfff369

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1263
-1278
lines changed

src/librustc/dep_graph/dep_node.rs

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub enum DepNode<D: Clone + Debug> {
7676
BorrowCheck(D),
7777
RvalueCheck(D),
7878
Reachability,
79+
MirKeys,
7980
LateLintCheck,
8081
TransCrateItem(D),
8182
TransInlinedItem(D),
@@ -202,6 +203,7 @@ impl<D: Clone + Debug> DepNode<D> {
202203
Variance => Some(Variance),
203204
PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)),
204205
Reachability => Some(Reachability),
206+
MirKeys => Some(MirKeys),
205207
LateLintCheck => Some(LateLintCheck),
206208
TransWriteMetadata => Some(TransWriteMetadata),
207209

src/librustc/dep_graph/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,5 @@ pub use self::graph::WorkProduct;
2828
pub use self::query::DepGraphQuery;
2929
pub use self::safe::AssertDepGraphSafe;
3030
pub use self::safe::DepGraphSafe;
31-
pub use self::visit::visit_all_bodies_in_krate;
3231
pub use self::visit::visit_all_item_likes_in_krate;
3332
pub use self::raii::DepTask;

src/librustc/dep_graph/safe.rs

+6
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ impl<A, B> DepGraphSafe for (A, B)
5050
{
5151
}
5252

53+
/// Shared ref to dep-graph-safe stuff should still be dep-graph-safe.
54+
impl<'a, A> DepGraphSafe for &'a A
55+
where A: DepGraphSafe,
56+
{
57+
}
58+
5359
/// No data here! :)
5460
impl DepGraphSafe for () {
5561
}

src/librustc/dep_graph/visit.rs

-12
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,3 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>
7575
krate.visit_all_item_likes(&mut tracking_visitor)
7676
}
7777

78-
pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C)
79-
where C: Fn(/* body_owner */
80-
DefId,
81-
/* body id */
82-
hir::BodyId)
83-
{
84-
let krate = tcx.hir.krate();
85-
for &body_id in &krate.body_ids {
86-
let body_owner_def_id = tcx.hir.body_owner_def_id(body_id);
87-
callback(body_owner_def_id, body_id);
88-
}
89-
}

src/librustc/hir/map/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ impl<'hir> Map<'hir> {
455455
if let EntryExpr(_, expr) = entry {
456456
BodyId { node_id: expr.id }
457457
} else {
458-
span_bug!(self.span(id), "id `{}` has no associated body", id);
458+
span_bug!(self.span(id), "id `{}` has no associated body: {:?}", id, entry);
459459
}
460460
}
461461
} else {

src/librustc/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
#![feature(unboxed_closures)]
4444
#![feature(discriminant_value)]
4545
#![feature(sort_unstable)]
46+
#![feature(trace_macros)]
47+
48+
#![recursion_limit="128"]
4649

4750
extern crate arena;
4851
extern crate core;

src/librustc/mir/README.md

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# MIR definition and pass system
2+
3+
This file contains the definition of the MIR datatypes along with the
4+
various types for the "MIR Pass" system, which lets you easily
5+
register and define new MIR transformations and analyses.
6+
7+
Most of the code that operates on MIR can be found in the
8+
`librustc_mir` crate or other crates. The code found here in
9+
`librustc` is just the datatype definitions, alonging the functions
10+
which operate on MIR to be placed everywhere else.
11+
12+
## MIR Data Types and visitor
13+
14+
The main MIR data type is `rustc::mir::Mir`, defined in `mod.rs`.
15+
There is also the MIR visitor (in `visit.rs`) which allows you to walk
16+
the MIR and override what actions will be taken at various points (you
17+
can visit in either shared or mutable mode; the latter allows changing
18+
the MIR in place). Finally `traverse.rs` contains various traversal
19+
routines for visiting the MIR CFG in [different standard orders][traversal]
20+
(e.g. pre-order, reverse post-order, and so forth).
21+
22+
[traversal]: https://en.wikipedia.org/wiki/Tree_traversal
23+
24+
## MIR pass suites and their integration into the query system
25+
26+
As a MIR *consumer*, you are expected to use one of the queries that
27+
returns a "final MIR". As of the time of this writing, there is only
28+
one: `optimized_mir(def_id)`, but more are expected to come in the
29+
future. For foreign def-ids, we simply read the MIR from the other
30+
crate's metadata. But for local query, this query will construct the
31+
MIR and then iteratively optimize it by putting it through various
32+
pipeline stages. This section describes those pipeline stages and how
33+
you can extend them.
34+
35+
To produce the `optimized_mir(D)` for a given def-id `D`, the MIR
36+
passes through several suites of optimizations, each represented by a
37+
query. Each suite consists of multiple optimizations and
38+
transformations. These suites represent useful intermediate points
39+
where we want to access the MIR for type checking or other purposes:
40+
41+
- `mir_build(D)` -- not a query, but this constructs the initial MIR
42+
- `mir_const(D)` -- applies some simple transformations to make MIR ready for constant evaluation;
43+
- `mir_validated(D)` -- applies some more transformations, making MIR ready for borrow checking;
44+
- `optimized_mir(D)` -- the final state, after all optimizations have been performed.
45+
46+
### Stealing
47+
48+
The intermediate queries `mir_const()` and `mir_validated()` yield up
49+
a `&'tcx Steal<Mir<'tcx>>`, allocated using
50+
`tcx.alloc_steal_mir()`. This indicates that the result may be
51+
**stolen** by the next suite of optimizations -- this is an
52+
optimization to avoid cloning the MIR. Attempting to use a stolen
53+
result will cause a panic in the compiler. Therefore, it is important
54+
that you not read directly from these intermediate queries except as
55+
part of the MIR processing pipeline.
56+
57+
Because of this stealing mechanism, some care must also be taken to
58+
ensure that, before the MIR at a particular phase in the processing
59+
pipeline is stolen, anyone who may want to read from it has already
60+
done so. Concretely, this means that if you have some query `foo(D)`
61+
that wants to access the result of `mir_const(D)` or
62+
`mir_validated(D)`, you need to have the successor pass either "force"
63+
`foo(D)` using `ty::queries::foo::force(...)`. This will force a query
64+
to execute even though you don't directly require its result.
65+
66+
As an example, consider MIR const qualification. It wants to read the
67+
result produced by the `mir_const()` suite. However, that result will
68+
be **stolen** by the `mir_validated()` suite. If nothing was done,
69+
then `mir_const_qualif(D)` would succeed if it came before
70+
`mir_validated(D)`, but fail otherwise. Therefore, `mir_validated(D)`
71+
will **force** `mir_const_qualif` before it actually steals, thus
72+
ensuring that the reads have already happened:
73+
74+
```
75+
mir_const(D) --read-by--> mir_const_qualif(D)
76+
| ^
77+
stolen-by |
78+
| (forces)
79+
v |
80+
mir_validated(D) ------------+
81+
```
82+
83+
### Implementing and registering a pass
84+
85+
To create a new MIR pass, you simply implement the `MirPass` trait for
86+
some fresh singleton type `Foo`. Once you have implemented a trait for
87+
your type `Foo`, you then have to insert `Foo` into one of the suites;
88+
this is done in `librustc_driver/driver.rs` by invoking `push_pass(S,
89+
Foo)` with the appropriate suite substituted for `S`.
90+

src/librustc/mir/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
//! MIR datatypes and passes. See [the README](README.md) for details.
12+
1113
use graphviz::IntoCow;
1214
use middle::const_val::ConstVal;
1315
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};

0 commit comments

Comments
 (0)