]>
Commit | Line | Data |
---|---|---|
a1dfa0c6 XL |
1 | # MIR passes |
2 | ||
3 | If you would like to get the MIR for a function (or constant, etc), | |
4 | you can use the `optimized_mir(def_id)` query. This will give you back | |
5 | the final, optimized MIR. For foreign def-ids, we simply read the MIR | |
6 | from the other crate's metadata. But for local def-ids, the query will | |
7 | construct the MIR and then iteratively optimize it by applying a | |
8 | series of passes. This section describes how those passes work and how | |
9 | you can extend them. | |
10 | ||
11 | To produce the `optimized_mir(D)` for a given def-id `D`, the MIR | |
12 | passes through several suites of optimizations, each represented by a | |
13 | query. Each suite consists of multiple optimizations and | |
14 | transformations. These suites represent useful intermediate points | |
15 | where we want to access the MIR for type checking or other purposes: | |
16 | ||
17 | - `mir_build(D)` – not a query, but this constructs the initial MIR | |
18 | - `mir_const(D)` – applies some simple transformations to make MIR ready for | |
19 | constant evaluation; | |
20 | - `mir_validated(D)` – applies some more transformations, making MIR ready for | |
21 | borrow checking; | |
22 | - `optimized_mir(D)` – the final state, after all optimizations have been | |
23 | performed. | |
24 | ||
a1dfa0c6 XL |
25 | ### Implementing and registering a pass |
26 | ||
27 | A `MirPass` is some bit of code that processes the MIR, typically – | |
28 | but not always – transforming it along the way somehow. For example, | |
29 | it might perform an optimization. The `MirPass` trait itself is found | |
3c0e092e | 30 | in [the `rustc_mir_transform` crate][mirtransform], and it |
a1dfa0c6 XL |
31 | basically consists of one method, `run_pass`, that simply gets an |
32 | `&mut Mir` (along with the tcx and some information about where it | |
33 | came from). The MIR is therefore modified in place (which helps to | |
34 | keep things efficient). | |
35 | ||
f25598a0 FG |
36 | A basic example of a MIR pass is [`RemoveStorageMarkers`], which walks |
37 | the MIR and removes all storage marks if they won't be emitted during codegen. As you | |
a1dfa0c6 XL |
38 | can see from its source, a MIR pass is defined by first defining a |
39 | dummy type, a struct with no fields, something like: | |
40 | ||
41 | ```rust | |
42 | struct MyPass; | |
43 | ``` | |
44 | ||
45 | for which you then implement the `MirPass` trait. You can then insert | |
46 | this pass into the appropriate list of passes found in a query like | |
47 | `optimized_mir`, `mir_validated`, etc. (If this is an optimization, it | |
48 | should go into the `optimized_mir` list.) | |
49 | ||
50 | If you are writing a pass, there's a good chance that you are going to | |
51 | want to use a [MIR visitor]. MIR visitors are a handy way to walk all | |
52 | the parts of the MIR, either to search for something or to make small | |
53 | edits. | |
54 | ||
55 | ### Stealing | |
56 | ||
57 | The intermediate queries `mir_const()` and `mir_validated()` yield up | |
58 | a `&'tcx Steal<Mir<'tcx>>`, allocated using | |
59 | `tcx.alloc_steal_mir()`. This indicates that the result may be | |
60 | **stolen** by the next suite of optimizations – this is an | |
61 | optimization to avoid cloning the MIR. Attempting to use a stolen | |
62 | result will cause a panic in the compiler. Therefore, it is important | |
63 | that you do not read directly from these intermediate queries except as | |
64 | part of the MIR processing pipeline. | |
65 | ||
66 | Because of this stealing mechanism, some care must also be taken to | |
67 | ensure that, before the MIR at a particular phase in the processing | |
68 | pipeline is stolen, anyone who may want to read from it has already | |
69 | done so. Concretely, this means that if you have some query `foo(D)` | |
70 | that wants to access the result of `mir_const(D)` or | |
71 | `mir_validated(D)`, you need to have the successor pass "force" | |
72 | `foo(D)` using `ty::queries::foo::force(...)`. This will force a query | |
73 | to execute even though you don't directly require its result. | |
74 | ||
75 | As an example, consider MIR const qualification. It wants to read the | |
76 | result produced by the `mir_const()` suite. However, that result will | |
77 | be **stolen** by the `mir_validated()` suite. If nothing was done, | |
78 | then `mir_const_qualif(D)` would succeed if it came before | |
79 | `mir_validated(D)`, but fail otherwise. Therefore, `mir_validated(D)` | |
80 | will **force** `mir_const_qualif` before it actually steals, thus | |
81 | ensuring that the reads have already happened (remember that | |
82 | [queries are memoized](../query.html), so executing a query twice | |
83 | simply loads from a cache the second time): | |
84 | ||
85 | ```text | |
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 | This mechanism is a bit dodgy. There is a discussion of more elegant | |
95 | alternatives in [rust-lang/rust#41710]. | |
96 | ||
97 | [rust-lang/rust#41710]: https://github.com/rust-lang/rust/issues/41710 | |
3c0e092e | 98 | [mirtransform]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/ |
f25598a0 | 99 | [`RemoveStorageMarkers`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/remove_storage_markers/struct.RemoveStorageMarkers.html |
a1dfa0c6 | 100 | [MIR visitor]: ./visitor.html |