blob: bd726805ab504bce64da51b34304670f3b98284e [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 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>&amp;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&lt;'tcx&gt; MirPass&lt;'tcx&gt; for CleanupPostBorrowck {
fn run_pass(&amp;self, tcx: TyCtxt&lt;'tcx&gt;, body: &amp;mut Body&lt;'tcx&gt;) {
...
}
}
<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>&amp;'tcx Steal&lt;Body&lt;'tcx&gt;&gt;</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--&gt; id40
id5 --steal--&gt; id40
mir_borrowck* --borrow--&gt; id3
id41 --steal part 1--&gt; id3
id40 --steal part 0--&gt; id3
mir_const_qualif* -- borrow --&gt; id2
id3 -- steal --&gt; id2
id2 -- steal --&gt; 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>&amp;'tcx Steal&lt;Body&lt;'tcx&gt;&gt;</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>(&amp;'tcx Steal&lt;Body&lt;'tcx&gt;&gt;, &amp;'tcx Steal&lt;IndexVec&lt;Promoted, Body&lt;'tcx&gt;&gt;&gt;)</code>, <code>promoted_mir</code> will steal
part 1 (<code>&amp;'tcx Steal&lt;IndexVec&lt;Promoted, Body&lt;'tcx&gt;&gt;&gt;</code>) and <code>mir_drops_elaborated_and_const_checked</code>
will steal part 0 (<code>&amp;'tcx Steal&lt;Body&lt;'tcx&gt;&gt;</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>