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