]>
Commit | Line | Data |
---|---|---|
a1dfa0c6 | 1 | # MIR optimizations |
60c5eb7d XL |
2 | |
3 | MIR optimizations are optimizations run on the [MIR][mir] to produce better MIR | |
4 | before codegen. This is important for two reasons: first, it makes the final | |
5 | generated executable code better, and second, it means that LLVM has less work | |
6 | to do, so compilation is faster. Note that since MIR is generic (not | |
7 | [monomorphized][monomorph] yet), these optimizations are particularly | |
8 | effective; we can optimize the generic version, so all of the monomorphizations | |
9 | are cheaper! | |
10 | ||
74b04a01 | 11 | [mir]: https://rustc-dev-guide.rust-lang.org/mir/index.html |
ba9703b0 | 12 | [monomorph]: https://rustc-dev-guide.rust-lang.org/appendix/glossary.html#mono |
60c5eb7d XL |
13 | |
14 | MIR optimizations run after borrow checking. We run a series of optimization | |
15 | passes over the MIR to improve it. Some passes are required to run on all code, | |
16 | some passes don't actually do optimizations but only check stuff, and some | |
17 | passes are only turned on in `release` mode. | |
18 | ||
19 | The [`optimized_mir`][optmir] [query] is called to produce the optimized MIR | |
20 | for a given [`DefId`][defid]. This query makes sure that the borrow checker has | |
ba9703b0 | 21 | run and that some validation has occurred. Then, it [steals][steal] the MIR, |
60c5eb7d XL |
22 | optimizes it, and returns the improved MIR. |
23 | ||
24 | [optmir]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/transform/fn.optimized_mir.html | |
74b04a01 | 25 | [query]: https://rustc-dev-guide.rust-lang.org/query.html |
ba9703b0 | 26 | [defid]: https://rustc-dev-guide.rust-lang.org/appendix/glossary.html#def-id |
74b04a01 | 27 | [steal]: https://rustc-dev-guide.rust-lang.org/mir/passes.html?highlight=steal#stealing |
60c5eb7d XL |
28 | |
29 | ## Defining optimization passes | |
30 | ||
31 | The list of passes run and the order in which they are run is defined by the | |
32 | [`run_optimization_passes`][rop] function. It contains an array of passes to | |
33 | run. Each pass in the array is a struct that implements the [`MirPass`] trait. | |
34 | The array is an array of `&dyn MirPass` trait objects. Typically, a pass is | |
35 | implemented in its own submodule of the [`rustc_mir::transform`][trans] module. | |
36 | ||
37 | [rop]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/transform/fn.run_optimization_passes.html | |
38 | [`MirPass`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/transform/trait.MirPass.html | |
6a06907d | 39 | [trans]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/transform/index.html |
60c5eb7d XL |
40 | |
41 | Some examples of passes are: | |
42 | - `CleanupNonCodegenStatements`: remove some of the info that is only needed for | |
43 | analyses, rather than codegen. | |
44 | - `ConstProp`: Does [constant propagation][constprop] | |
45 | ||
46 | You can see the ["Implementors" section of the `MirPass` rustdocs][impl] for more examples. | |
47 | ||
48 | [impl]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/transform/trait.MirPass.html#implementors | |
49 | [constprop]: https://en.wikipedia.org/wiki/Constant_folding#Constant_propagation | |
6a06907d XL |
50 | |
51 | ## MIR optimization levels | |
52 | ||
53 | MIR optimizations can come in various levels of readiness. Experimental | |
54 | optimizations may cause miscompilations, or slow down compile times. | |
55 | These passes are still included in nightly builds to gather feedback and make it easier to modify | |
56 | the pass. To enable working with slow or otherwise experimental optimization passes, | |
57 | you can specify the `-Z mir-opt-level` debug flag. You can find the | |
58 | definitions of the levels in the [compiler MCP]. If you are developing a MIR pass and | |
59 | want to query whether your optimization pass should run, you can check the | |
60 | current level using `tcx.sess.opts.debugging_opts.mir_opt_level`. | |
61 | ||
62 | [compiler MCP]: https://github.com/rust-lang/compiler-team/issues/319 | |
63 | ||
64 | ## Optimization fuel | |
65 | ||
66 | Optimization fuel is a compiler option (`-Z fuel=<crate>=<value>`) that allows for fine grained | |
67 | control over which optimizations can be applied during compilation: each optimization reduces | |
68 | fuel by 1, and when fuel reaches 0 no more optimizations are applied. The primary use of fuel | |
69 | is debugging optimizations that may be incorrect or misapplied. By changing the fuel | |
70 | value, you can bisect a compilation session down to the exact incorrect optimization | |
71 | (this behaves like a kind of binary search through the optimizations). | |
72 | ||
73 | MIR optimizations respect fuel, and in general each pass should check fuel by calling | |
74 | [`tcx.consider_optimizing`][consideroptimizing] and skipping the optimization if fuel | |
75 | is empty. There are a few considerations: | |
76 | ||
77 | 1. If the pass is considered "guaranteed" (for example, it should always be run because it is | |
78 | needed for correctness), then fuel should not be used. An example of this is `PromoteTemps`. | |
79 | 2. In some cases, an initial pass is performed to gather candidates, which are then iterated to | |
80 | perform optimizations. In these situations, we should allow for the initial gathering pass | |
81 | and then check fuel as close to the mutation as possible. This allows for the best | |
82 | debugging experience, because we can determine where in the list of candidates an optimization | |
83 | may have been misapplied. Examples of this are `InstCombine` and `ConstantPropagation`. | |
84 | ||
85 | [consideroptimizing]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.consider_optimizing |