blob: 148233ed8a6805e0ab9d0069919552e53a899af0 [file] [log] [blame] [edit]
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>MIR optimizations - Rust Compiler Development Guide</title>
<!-- Custom HTML head -->
<meta name="description" content="A guide to developing the Rust compiler (rustc)">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../pagetoc.css">
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
sidebar_toggle.checked = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust Compiler Development Guide</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide/edit/main/src/mir/optimizations.md" title="Suggest an edit" aria-label="Suggest an edit" rel="edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<i class="fa fa-spinner fa-spin"></i>
</div>
</div>
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="mir-optimizations"><a class="header" href="#mir-optimizations">MIR optimizations</a></h1>
<p>MIR optimizations are optimizations run on the <a href="../mir/index.html">MIR</a> 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
<a href="../appendix/glossary.html#mono">monomorphized</a> yet), these optimizations are particularly
effective; we can optimize the generic version, so all of the monomorphizations
are cheaper!</p>
<p>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 <code>release</code> mode.</p>
<p>The <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/fn.optimized_mir.html"><code>optimized_mir</code></a> <a href="../query.html">query</a> is called to produce the optimized MIR
for a given <a href="../appendix/glossary.html#def-id"><code>DefId</code></a>. This query makes sure that the borrow checker has
run and that some validation has occurred. Then, it <a href="../mir/passes.html#stealing">steals</a> the MIR,
optimizes it, and returns the improved MIR.</p>
<h2 id="quickstart-for-adding-a-new-optimization"><a class="header" href="#quickstart-for-adding-a-new-optimization">Quickstart for adding a new optimization</a></h2>
<ol>
<li>
<p>Make a Rust source file in <code>tests/mir-opt</code> that shows the code you want to
optimize. This should be kept simple, so avoid <code>println!</code> or other formatting
code if it's not necessary for the optimization. The reason for this is that
<code>println!</code>, <code>format!</code>, etc. generate a lot of MIR that can make it harder to
understand what the optimization does to the test.</p>
</li>
<li>
<p>Run <code>./x test --bless tests/mir-opt/&lt;your-test&gt;.rs</code> to generate a MIR
dump. Read <a href="https://github.com/rust-lang/rust/blob/HEAD/tests/mir-opt/README.md">this README</a> for instructions on how to dump
things.</p>
</li>
<li>
<p>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.</p>
</li>
<li>
<p>Implement a new optimization in <a href="https://github.com/rust-lang/rust/tree/HEAD/compiler/rustc_mir_transform/src"><code>compiler/rustc_mir_transform/src</code></a>.
The fastest and easiest way to do this is to</p>
<ol>
<li>pick a small optimization (such as <a href="https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_mir_transform/src/remove_storage_markers.rs"><code>remove_storage_markers</code></a>) and copy it
to a new file,</li>
<li>add your optimization to one of the lists in the
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/fn.run_optimization_passes.html"><code>run_optimization_passes()</code></a> function,</li>
<li>and then start modifying the copied optimization.</li>
</ol>
</li>
<li>
<p>Rerun <code>./x test --bless tests/mir-opt/&lt;your-test&gt;.rs</code> to regenerate the
MIR dumps. Look at the diffs to see if they are what you expect.</p>
</li>
<li>
<p>Run <code>./x test tests/ui</code> to see if your optimization broke anything.</p>
</li>
<li>
<p>If there are issues with your optimization, experiment with it a bit and
repeat steps 5 and 6.</p>
</li>
<li>
<p>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 <code>[WIP]</code> or otherwise note that it is a
work in progress) in that case.</p>
<p>Make sure to commit the blessed test output as well! It's necessary for CI to
pass and it's very helpful to reviewers.</p>
</li>
</ol>
<p>If you have any questions along the way, feel free to ask in
<code>#t-compiler/wg-mir-opt</code> on Zulip.</p>
<h2 id="defining-optimization-passes"><a class="header" href="#defining-optimization-passes">Defining optimization passes</a></h2>
<p>The list of passes run and the order in which they are run is defined by the
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/fn.run_optimization_passes.html"><code>run_optimization_passes</code></a> function. It contains an array of passes to
run. Each pass in the array is a struct that implements the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/pass_manager/trait.MirPass.html"><code>MirPass</code></a> trait.
The array is an array of <code>&amp;dyn MirPass</code> trait objects. Typically, a pass is
implemented in its own module of the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/index.html"><code>rustc_mir_transform</code></a> crate.</p>
<p>Some examples of passes are:</p>
<ul>
<li><code>CleanupPostBorrowck</code>: Remove some of the info that is only needed for
analyses, rather than codegen.</li>
<li><code>ConstProp</code>: Does <a href="https://en.wikipedia.org/wiki/Constant_folding#Constant_propagation">constant propagation</a>.</li>
</ul>
<p>You can see the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/pass_manager/trait.MirPass.html#implementors">"Implementors" section of the <code>MirPass</code> rustdocs</a> for more examples.</p>
<h2 id="mir-optimization-levels"><a class="header" href="#mir-optimization-levels">MIR optimization levels</a></h2>
<p>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 <code>-Z mir-opt-level</code> debug flag. You can find the
definitions of the levels in the <a href="https://github.com/rust-lang/compiler-team/issues/319">compiler MCP</a>. If you are developing a MIR pass and
want to query whether your optimization pass should run, you can check the
current level using <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_session/config/struct.UnstableOptions.html#structfield.mir_opt_level"><code>tcx.sess.opts.unstable_opts.mir_opt_level</code></a>.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../part-5-intro.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../mir/debugging.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../part-5-intro.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../mir/debugging.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
<script src="../mermaid.min.js"></script>
<script src="../mermaid-init.js"></script>
<script src="../pagetoc.js"></script>
</div>
</body>
</html>