| # MIR optimizations |
| |
| MIR optimizations are optimizations run on the [MIR] to produce better MIR before codegen. |
| This is important for two reasons: first, it makes the final |
| generated executable code better, and second, it means that LLVM has less work |
| to do, so compilation is faster. |
| Note that since MIR is generic (not |
| [monomorphized] yet), these optimizations are particularly |
| effective; we can optimize the generic version, so all of the monomorphizations are cheaper! |
| |
| [mir]: ../mir/index.md |
| [monomorphized]: ../appendix/glossary.md#mono |
| |
| MIR optimizations run after borrow checking. |
| We run a series of optimization passes over the MIR to improve it. |
| Some passes are required to run on all code, |
| some passes don't actually do optimizations but only check stuff, and some |
| passes are only turned on in `release` mode. |
| |
| The [`optimized_mir`] [query] is called to produce the optimized MIR |
| for a given [`DefId`]. |
| This query makes sure that the borrow checker has run and that some validation has occurred. |
| Then, it [steals] the MIR, |
| optimizes it, and returns the improved MIR. |
| |
| [`optimized_mir`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/fn.optimized_mir.html |
| [query]: ../query.md |
| [`defid`]: ../appendix/glossary.md#def-id |
| [steals]: ../mir/passes.md#stealing |
| |
| ## Quickstart for adding a new optimization |
| |
| 1. Make a Rust source file in `tests/mir-opt` that shows the code you want to optimize. |
| This should be kept simple, so avoid `println!` or other formatting |
| code if it's not necessary for the optimization. |
| The reason for this is that |
| `println!`, `format!`, etc. generate a lot of MIR that can make it harder to |
| understand what the optimization does to the test. |
| |
| 2. Run `./x test --bless tests/mir-opt/<your-test>.rs` to generate a MIR dump. |
| Read [this README][mir-opt-test-readme] for instructions on how to dump things. |
| |
| 3. Commit the current working directory state. |
| The reason you should commit the |
| test output before you implement the optimization is so that you (and your |
| reviewers) can see a before/after diff of what the optimization changed. |
| |
| 4. Implement a new optimization in [`compiler/rustc_mir_transform/src`]. |
| The fastest and easiest way to do this is to |
| |
| 1. pick a small optimization (such as [`remove_storage_markers`]) and copy it |
| to a new file, |
| 2. add your optimization to one of the lists in the [`run_optimization_passes()`] function, |
| 3. and then start modifying the copied optimization. |
| |
| 5. Rerun `./x test --bless tests/mir-opt/<your-test>.rs` to regenerate the MIR dumps. |
| Look at the diffs to see if they are what you expect. |
| |
| 6. Run `./x test tests/ui` to see if your optimization broke anything. |
| |
| 7. If there are issues with your optimization, experiment with it a bit and repeat steps 5 and 6. |
| |
| 8. Commit and open a PR. |
| You can do this at any point, even if things aren't |
| working yet, so that you can ask for feedback on the PR. |
| Open a "WIP" PR (just prefix your PR title with `[WIP]` or otherwise note that it is a |
| work in progress) in that case. |
| |
| Make sure to commit the blessed test output as well! |
| It's necessary for CI to pass and it's very helpful to reviewers. |
| |
| If you have any questions along the way, feel free to ask in `#t-compiler/wg-mir-opt` on Zulip. |
| |
| [mir-opt-test-readme]: https://github.com/rust-lang/rust/blob/HEAD/tests/mir-opt/README.md |
| [`compiler/rustc_mir_transform/src`]: https://github.com/rust-lang/rust/tree/HEAD/compiler/rustc_mir_transform/src |
| [`remove_storage_markers`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_mir_transform/src/remove_storage_markers.rs |
| [`run_optimization_passes()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/fn.run_optimization_passes.html |
| |
| ## Defining optimization passes |
| |
| The list of passes run and the order in which they are run is defined by the |
| [`run_optimization_passes`][rop] function. |
| It contains an array of passes to run. |
| Each pass in the array is a struct that implements the [`MirPass`] trait. |
| The array is an array of `&dyn MirPass` trait objects. |
| Typically, a pass is implemented in its own module of the [`rustc_mir_transform`][trans] crate. |
| |
| [rop]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/fn.run_optimization_passes.html |
| [`MirPass`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/pass_manager/trait.MirPass.html |
| [trans]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/index.html |
| |
| Some examples of passes are: |
| - `CleanupPostBorrowck`: Remove some of the info that is only needed for |
| analyses, rather than codegen. |
| - `ConstProp`: Does [constant propagation][constprop]. |
| |
| You can see the ["Implementors" section of the `MirPass` rustdocs][impl] for more examples. |
| |
| [impl]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/pass_manager/trait.MirPass.html#implementors |
| [constprop]: https://en.wikipedia.org/wiki/Constant_folding#Constant_propagation |
| |
| ## MIR optimization levels |
| |
| MIR optimizations can come in various levels of readiness. |
| Experimental optimizations may cause miscompilations, or slow down compile times. |
| These passes are still included in nightly builds to gather feedback and make it easier to modify |
| the pass. |
| To enable working with slow or otherwise experimental optimization passes, |
| you can specify the `-Z mir-opt-level` debug flag. |
| You can find the definitions of the levels in the [compiler MCP]. |
| If you are developing a MIR pass and |
| want to query whether your optimization pass should run, you can check the |
| current level using [`tcx.sess.opts.unstable_opts.mir_opt_level`][mir_opt_level]. |
| |
| [compiler MCP]: https://github.com/rust-lang/compiler-team/issues/319 |
| [mir_opt_level]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/config/struct.UnstableOptions.html#structfield.mir_opt_level |