370 lines
22 KiB
HTML
370 lines
22 KiB
HTML
<!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 -->
|
||
|
||
|
||
<!-- Provide site root and default themes to javascript -->
|
||
<script>
|
||
const path_to_root = "../";
|
||
const default_light_theme = "light";
|
||
const default_dark_theme = "navy";
|
||
</script>
|
||
<!-- Start loading toc.js asap -->
|
||
<script src="../toc.js"></script>
|
||
</head>
|
||
<body>
|
||
<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 = sidebar === 'visible';
|
||
html.classList.remove('sidebar-visible');
|
||
html.classList.add("sidebar-" + sidebar);
|
||
</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. (Shortkey: s)" 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/master/src/mir/passes.md" title="Suggest an edit" aria-label="Suggest an 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">
|
||
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
||
</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>
|
||
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|