# The MIR (Mid-level IR)
<!-- toc -->
MIR is Rust's _Mid-level Intermediate Representation_. It is
constructed from [HIR](../hir.html). MIR was introduced in
[RFC 1211]. It is a radically simplified form of Rust that is used for
certain flow-sensitive safety checks – notably the borrow checker! –
and also for optimization and code generation.
If you'd like a very high-level introduction to MIR, as well as some
of the compiler concepts that it relies on (such as control-flow
graphs and desugaring), you may enjoy the
[rust-lang blog post that introduced MIR][blog].
## Introduction to MIR
MIR is defined in the [`compiler/rustc_middle/src/mir/`][mir] module, but much of the code
that manipulates it is found in [`compiler/rustc_mir_build`][mirmanip_build],
[`compiler/rustc_mir_transform`][mirmanip_transform], and
[`compiler/rustc_mir_dataflow`][mirmanip_dataflow].
Some of the key characteristics of MIR are:
- It is based on a [control-flow graph][cfg].
- It does not have nested expressions.
- All types in MIR are fully explicit.
## Key MIR vocabulary
This section introduces the key concepts of MIR, summarized here:
- **Basic blocks**: units of the control-flow graph, consisting of:
- **statements:** actions with one successor
- **terminators:** actions with potentially multiple successors; always at
the end of a block
- (if you're not familiar with the term *basic block*, see the [background
chapter][cfg])
- **Locals:** Memory locations allocated on the stack (conceptually, at
least), such as function arguments, local variables, and
temporaries. These are identified by an index, written with a
leading underscore, like `_1`. There is also a special "local"
(`_0`) allocated to store the return value.
- **Places:** expressions that identify a location in memory, like `_1` or
`_1.f`.
- **Rvalues:** expressions that produce a value. The "R" stands for
the fact that these are the "right-hand side" of an assignment.
- **Operands:** the arguments to an rvalue, which can either be a
constant (like `22`) or a place (like `_1`).
You can get a feeling for how MIR is constructed by translating simple
programs into MIR and reading the pretty printed output. In fact, the
playground makes this easy, since it supplies a MIR button that will
show you the MIR for your program. Try putting this program into play
(or [clicking on this link][sample-play]), and then clicking the "MIR"
button on the top:
```rust
fn main() {
let mut vec = Vec::new();
vec.push(1);
vec.push(2);
}
```
You should see something like:
```mir
// WARNING: This output format is intended for human consumers only
// and is subject to change without notice. Knock yourself out.
fn main() -> () {
...
}
```
This is the MIR format for the `main` function.
MIR shown by above link is optimized.
Some statements like `StorageLive` are removed in optimization.
This happens because the compiler notices the value is never accessed in the code.
We can use `rustc [filename].rs -Z mir-opt-level=0 --emit mir` to view unoptimized MIR.
This requires the nightly toolchain.
**Variable declarations.** If we drill in a bit, we'll see it begins
with a bunch of variable declarations. They look like this:
```mir
let mut _0: (); // return place
let mut _1: std::vec::Vec<i32>; // in scope 0 at src/main.rs:2:9: 2:16
let mut _2: ();
let mut _3: &mut std::vec::Vec<i32>;
let mut _4: ();
let mut _5: &mut std::vec::Vec<i32>;
```
You can see that variables in MIR don't have names, they have indices,
like `_0` or `_1`. We also intermingle the user's variables (e.g.,
`_1`) with temporary values (e.g., `_2` or `_3`). You can tell apart
user-defined variables because they have debuginfo associated to them (see below).
**User variable debuginfo.** Below the variable declarations, we find the only
hint that `_1` represents a user variable:
```mir
scope 1 {
debug vec => _1; // in scope 1 at src/main.rs:2:9: 2:16