| <!DOCTYPE HTML> |
| <html lang="en" class="light sidebar-visible" dir="ltr"> |
| <head> |
| <!-- Book generated using mdBook --> |
| <meta charset="UTF-8"> |
| <title>MIR queries and passes: getting the MIR - 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/passes.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-queries-and-passes"><a class="header" href="#mir-queries-and-passes">MIR queries and passes</a></h1> |
| <p>If you would like to get the MIR:</p> |
| <ul> |
| <li>for a function - you can use the <code>optimized_mir</code> query (typically used by codegen) or the <code>mir_for_ctfe</code> query (typically used by compile time function evaluation, i.e., <em>CTFE</em>);</li> |
| <li>for a promoted - you can use the <code>promoted_mir</code> query.</li> |
| </ul> |
| <p>These will give you back the final, optimized MIR. For foreign def-ids, we simply read the MIR |
| from the other crate's metadata. But for local def-ids, the query will |
| construct the optimized MIR by requesting a pipeline of upstream queries<sup class="footnote-reference" id="fr-query-1"><a href="#footnote-query">1</a></sup>. |
| Each query will contain a series of passes. |
| This section describes how those queries and passes work and how you can extend them.</p> |
| <p>To produce the optimized MIR for a given def-id <code>D</code>, <code>optimized_mir(D)</code> |
| goes through several suites of passes, each grouped by a |
| query. Each suite consists of passes which perform linting, analysis, transformation or |
| optimization. Each query represent a useful intermediate point |
| where we can access the MIR dialect for type checking or other purposes:</p> |
| <ul> |
| <li><code>mir_built(D)</code> – it gives the initial MIR just after it's built;</li> |
| <li><code>mir_const(D)</code> – it applies some simple transformation passes to make MIR ready for |
| const qualification;</li> |
| <li><code>mir_promoted(D)</code> - it extracts promotable temps into separate MIR bodies, and also makes MIR |
| ready for borrow checking;</li> |
| <li><code>mir_drops_elaborated_and_const_checked(D)</code> - it performs borrow checking, runs major |
| transformation passes (such as drop elaboration) and makes MIR ready for optimization;</li> |
| <li><code>optimized_mir(D)</code> – it performs all enabled optimizations and reaches the final state.</li> |
| </ul> |
| <h2 id="implementing-and-registering-a-pass"><a class="header" href="#implementing-and-registering-a-pass">Implementing and registering a pass</a></h2> |
| <p>A <code>MirPass</code> is some bit of code that processes the MIR, typically transforming it along the way |
| somehow. But it may also do other things like linting (e.g., <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/check_packed_ref/struct.CheckPackedRef.html"><code>CheckPackedRef</code></a>, |
| <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/check_const_item_mutation/struct.CheckConstItemMutation.html"><code>CheckConstItemMutation</code></a>, <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/function_item_references/struct.FunctionItemReferences.html"><code>FunctionItemReferences</code></a>, which implement <code>MirLint</code>) or |
| optimization (e.g., <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/simplify/enum.SimplifyCfg.html"><code>SimplifyCfg</code></a>, <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/remove_unneeded_drops/struct.RemoveUnneededDrops.html"><code>RemoveUnneededDrops</code></a>). While most MIR passes |
| are defined in the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/"><code>rustc_mir_transform</code></a> crate, the <code>MirPass</code> trait itself is |
| <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/pass_manager/trait.MirPass.html">found</a> in the <code>rustc_middle</code> crate, and it basically consists of one primary method, |
| <code>run_pass</code>, that simply gets an <code>&mut Body</code> (along with the <code>tcx</code>). |
| The MIR is therefore modified in place (which helps to keep things efficient).</p> |
| <p>A basic example of a MIR pass is <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/remove_storage_markers/struct.RemoveStorageMarkers.html"><code>RemoveStorageMarkers</code></a>, which walks |
| the MIR and removes all storage marks if they won't be emitted during codegen. As you |
| can see from its source, a MIR pass is defined by first defining a |
| dummy type, a struct with no fields:</p> |
| <pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)] |
| </span><span class="boring">fn main() { |
| </span>pub struct RemoveStorageMarkers; |
| <span class="boring">}</span></code></pre></pre> |
| <p>for which we implement the <code>MirPass</code> trait. We can then insert |
| this pass into the appropriate list of passes found in a query like |
| <code>mir_built</code>, <code>optimized_mir</code>, etc. (If this is an optimization, it |
| should go into the <code>optimized_mir</code> list.)</p> |
| <p>Another example of a simple MIR pass is <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/cleanup_post_borrowck/struct.CleanupPostBorrowck.html"><code>CleanupPostBorrowck</code></a>, which walks |
| the MIR and removes all statements that are not relevant to code generation. As you can see from |
| its <a href="https://github.com/rust-lang/rust/blob/e2b52ff73edc8b0b7c74bc28760d618187731fe8/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs#L27">source</a>, it is defined by first defining a dummy type, a struct with no |
| fields:</p> |
| <pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)] |
| </span><span class="boring">fn main() { |
| </span>pub struct CleanupPostBorrowck; |
| <span class="boring">}</span></code></pre></pre> |
| <p>for which we implement the <code>MirPass</code> trait:</p> |
| <pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)] |
| </span><span class="boring">fn main() { |
| </span>impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck { |
| fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { |
| ... |
| } |
| } |
| <span class="boring">}</span></code></pre></pre> |
| <p>We <a href="https://github.com/rust-lang/rust/blob/e2b52ff73edc8b0b7c74bc28760d618187731fe8/compiler/rustc_mir_transform/src/lib.rs#L413">register</a> this pass inside the <code>mir_drops_elaborated_and_const_checked</code> query. |
| (If this is an optimization, it should go into the <code>optimized_mir</code> list.)</p> |
| <p>If you are writing a pass, there's a good chance that you are going to |
| want to use a <a href="./visitor.html">MIR visitor</a>. MIR visitors are a handy way to walk all |
| the parts of the MIR, either to search for something or to make small |
| edits.</p> |
| <h2 id="stealing"><a class="header" href="#stealing">Stealing</a></h2> |
| <p>The intermediate queries <code>mir_const()</code> and <code>mir_promoted()</code> yield up |
| a <code>&'tcx Steal<Body<'tcx>></code>, allocated using <code>tcx.alloc_steal_mir()</code>. |
| This indicates that the result may be <strong>stolen</strong> by a subsequent query – this is an |
| optimization to avoid cloning the MIR. Attempting to use a stolen |
| result will cause a panic in the compiler. Therefore, it is important |
| that you do not accidentally read from these intermediate queries without |
| the consideration of the dependency in the MIR processing pipeline.</p> |
| <p>Because of this stealing mechanism, some care must be taken to |
| ensure that, before the MIR at a particular phase in the processing |
| pipeline is stolen, anyone who may want to read from it has already |
| done so.</p> |
| <p>Concretely, this means that if you have a query <code>foo(D)</code> |
| that wants to access the result of <code>mir_promoted(D)</code>, you need to have <code>foo(D)</code> |
| calling the <code>mir_const(D)</code> query first. This will force it |
| to execute even though you don't directly require its result.</p> |
| <blockquote> |
| <p>This mechanism is a bit dodgy. There is a discussion of more elegant |
| alternatives in <a href="https://github.com/rust-lang/rust/issues/41710">rust-lang/rust#41710</a>.</p> |
| </blockquote> |
| <h3 id="overview"><a class="header" href="#overview">Overview</a></h3> |
| <p>Below is an overview of the stealing dependency in the MIR processing pipeline<sup class="footnote-reference" id="fr-part-1"><a href="#footnote-part">2</a></sup>:</p> |
| <pre class="mermaid">flowchart BT |
| mir_for_ctfe* --borrow--> id40 |
| id5 --steal--> id40 |
| |
| mir_borrowck* --borrow--> id3 |
| id41 --steal part 1--> id3 |
| id40 --steal part 0--> id3 |
| |
| mir_const_qualif* -- borrow --> id2 |
| id3 -- steal --> id2 |
| |
| id2 -- steal --> id1 |
| |
| id1([mir_built]) |
| id2([mir_const]) |
| id3([mir_promoted]) |
| id40([mir_drops_elaborated_and_const_checked]) |
| id41([promoted_mir]) |
| id5([optimized_mir]) |
| |
| style id1 fill:#bbf |
| style id2 fill:#bbf |
| style id3 fill:#bbf |
| style id40 fill:#bbf |
| style id41 fill:#bbf |
| style id5 fill:#bbf |
| </pre> |
| <p>The stadium-shape queries (e.g., <code>mir_built</code>) with a deep color are the primary queries in the |
| pipeline, while the rectangle-shape queries (e.g., <code>mir_const_qualif*</code><sup class="footnote-reference" id="fr-star-1"><a href="#footnote-star">3</a></sup>) with a shallow color |
| are those subsequent queries that need to read the results from <code>&'tcx Steal<Body<'tcx>></code>. With the |
| stealing mechanism, the rectangle-shape queries must be performed before any stadium-shape queries, |
| that have an equal or larger height in the dependency tree, ever do.</p> |
| <h3 id="example"><a class="header" href="#example">Example</a></h3> |
| <p>As an example, consider MIR const qualification. It wants to read the result produced by the |
| <code>mir_const</code> query. However, that result will be <strong>stolen</strong> by the <code>mir_promoted</code> query at some |
| time in the pipeline. Before <code>mir_promoted</code> is ever queried, calling the <code>mir_const_qualif</code> query |
| will succeed since <code>mir_const</code> will produce (if queried the first time) or cache (if queried |
| multiple times) the <code>Steal</code> result and the result is <strong>not</strong> stolen yet. After <code>mir_promoted</code> is |
| queried, the result would be stolen and calling the <code>mir_const_qualif</code> query to read the result |
| would cause a panic.</p> |
| <p>Therefore, with this stealing mechanism, <code>mir_promoted</code> should guarantee any <code>mir_const_qualif*</code> |
| queries are called before it actually steals, thus ensuring that the reads have already happened |
| (remember that <a href="../query.html">queries are memoized</a>, so executing a query twice |
| simply loads from a cache the second time).</p> |
| <hr> |
| <ol class="footnote-definition"><li id="footnote-query"> |
| <p>See the <a href="../query.html">Queries</a> chapter for the general concept of query. <a href="#fr-query-1">↩</a></p> |
| </li> |
| <li id="footnote-part"> |
| <p>The <code>mir_promoted</code> query will yield up a tuple |
| <code>(&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>)</code>, <code>promoted_mir</code> will steal |
| part 1 (<code>&'tcx Steal<IndexVec<Promoted, Body<'tcx>>></code>) and <code>mir_drops_elaborated_and_const_checked</code> |
| will steal part 0 (<code>&'tcx Steal<Body<'tcx>></code>). And their stealing is irrelevant to each other, |
| i.e., can be performed separately. <a href="#fr-part-1">↩</a></p> |
| </li> |
| <li id="footnote-star"> |
| <p>Note that the <code>*</code> suffix in the queries represent a set of queries with the same prefix. |
| For example, <code>mir_borrowck*</code> represents <code>mir_borrowck</code>, <code>mir_borrowck_const_arg</code> and |
| <code>mir_borrowck_opt_const_arg</code>. <a href="#fr-star-1">↩</a></p> |
| </li> |
| </ol> |
| </main> |
| |
| <nav class="nav-wrapper" aria-label="Page navigation"> |
| <!-- Mobile navigation buttons --> |
| <a rel="prev" href="../mir/visitor.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="../asm.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="../mir/visitor.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="../asm.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> |