Skip to content

rework the queries for the MIR pipeline #41625

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
May 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0e5e2f3
introduce `mir_keys()`
nikomatsakis Apr 25, 2017
11b6b06
rework `MirPass` API to be stateless and extract helper fns
nikomatsakis Apr 25, 2017
46b342f
simplify the MirPass traits and passes dramatically
nikomatsakis Apr 25, 2017
e9e6ccc
introduce `DefIdPass` and remove all impls of `Pass` but `Inline`
nikomatsakis Apr 27, 2017
668886a
rewrite `Passes` to have sets of passes
nikomatsakis Apr 27, 2017
f23a7bc
move to only def-id passes
nikomatsakis Apr 27, 2017
2b32cb9
retool MIR passes completely
nikomatsakis Apr 27, 2017
e89a321
rename `MirPassSet` to `MirSuite`
nikomatsakis Apr 28, 2017
29263fd
introduce idea of "stealable" MIR
nikomatsakis Apr 28, 2017
ecc8ff9
rework macro to prepare for more modifiers than just `[pub]`
nikomatsakis Apr 28, 2017
3d1095c
introduce `IntoKeyValues` trait to prepare for multi-queries
nikomatsakis Apr 28, 2017
1d675ce
adjust the macro to allow for `multi` modifier
nikomatsakis Apr 28, 2017
a26e966
convert the `inline` pass to use the new multi result
nikomatsakis Apr 28, 2017
0d045d7
add comments to `Steal` and use `bug!`
nikomatsakis Apr 29, 2017
d9c8a2b
use `force` to ensure const-qualif has been done, not read
nikomatsakis Apr 29, 2017
532439f
add a README describing the whole design
nikomatsakis Apr 29, 2017
c1ff104
rename `mir_map` to `queries` and remove `build_mir_for_crate`
nikomatsakis May 1, 2017
c2cfdbb
adjust privacy of various types in `build`
nikomatsakis May 1, 2017
69c8f9d
move `build_mir` into `build` directory
nikomatsakis May 2, 2017
c253df5
remove `Pass` and (temporarily) drop `Inline`
nikomatsakis May 1, 2017
9c154a6
rip out everything but `MirPass`, move the logic into suites
nikomatsakis May 1, 2017
669d316
simplify down to one query per pass suite
nikomatsakis May 1, 2017
1dd9c3e
support inlining by asking for optimizer mir for callees
nikomatsakis May 1, 2017
851a880
remove irrelevant comments
nikomatsakis May 1, 2017
2fa1ba3
pacify the mercilous tidy
nikomatsakis May 1, 2017
74b2783
delete dead code
nikomatsakis May 1, 2017
c7023d1
run MIR borrowck on the validated, not optimized, MIR
nikomatsakis May 2, 2017
393fa4f
rename from `item_mir` to `optimized_mir`
nikomatsakis May 2, 2017
b0092e8
move queries code into transform
nikomatsakis May 2, 2017
0afcfce
update comment about heuristics
nikomatsakis May 2, 2017
15bc2f4
remove temporary variable
nikomatsakis May 2, 2017
e6793ac
have borrowck fetch MIR, which will perform some errors
nikomatsakis May 2, 2017
afc5acd
fix librustc_driver
nikomatsakis May 2, 2017
25be798
remove `mir_passes` from `Session` and add a FIXME
nikomatsakis May 2, 2017
488b2a3
add FIXME to `Steal`
nikomatsakis May 2, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub enum DepNode<D: Clone + Debug> {
BorrowCheck(D),
RvalueCheck(D),
Reachability,
MirKeys,
LateLintCheck,
TransCrateItem(D),
TransInlinedItem(D),
Expand Down Expand Up @@ -202,6 +203,7 @@ impl<D: Clone + Debug> DepNode<D> {
Variance => Some(Variance),
PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)),
Reachability => Some(Reachability),
MirKeys => Some(MirKeys),
LateLintCheck => Some(LateLintCheck),
TransWriteMetadata => Some(TransWriteMetadata),

Expand Down
1 change: 0 additions & 1 deletion src/librustc/dep_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,5 @@ pub use self::graph::WorkProduct;
pub use self::query::DepGraphQuery;
pub use self::safe::AssertDepGraphSafe;
pub use self::safe::DepGraphSafe;
pub use self::visit::visit_all_bodies_in_krate;
pub use self::visit::visit_all_item_likes_in_krate;
pub use self::raii::DepTask;
6 changes: 6 additions & 0 deletions src/librustc/dep_graph/safe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ impl<A, B> DepGraphSafe for (A, B)
{
}

/// Shared ref to dep-graph-safe stuff should still be dep-graph-safe.
impl<'a, A> DepGraphSafe for &'a A
where A: DepGraphSafe,
{
}

/// No data here! :)
impl DepGraphSafe for () {
}
Expand Down
12 changes: 0 additions & 12 deletions src/librustc/dep_graph/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,3 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>
krate.visit_all_item_likes(&mut tracking_visitor)
}

pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C)
where C: Fn(/* body_owner */
DefId,
/* body id */
hir::BodyId)
{
let krate = tcx.hir.krate();
for &body_id in &krate.body_ids {
let body_owner_def_id = tcx.hir.body_owner_def_id(body_id);
callback(body_owner_def_id, body_id);
}
}
2 changes: 1 addition & 1 deletion src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ impl<'hir> Map<'hir> {
if let EntryExpr(_, expr) = entry {
BodyId { node_id: expr.id }
} else {
span_bug!(self.span(id), "id `{}` has no associated body", id);
span_bug!(self.span(id), "id `{}` has no associated body: {:?}", id, entry);
}
}
} else {
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
#![feature(unboxed_closures)]
#![feature(discriminant_value)]
#![feature(sort_unstable)]
#![feature(trace_macros)]

#![recursion_limit="128"]

extern crate arena;
extern crate core;
Expand Down
90 changes: 90 additions & 0 deletions src/librustc/mir/README.md
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`.

2 changes: 2 additions & 0 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! MIR datatypes and passes. See [the README](README.md) for details.

use graphviz::IntoCow;
use middle::const_val::ConstVal;
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
Expand Down
Loading