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