rust-lang/rust
MIR pipeline
MIR (Mid-level Intermediate Representation) is rustc's main IR for everything after type checking. It's a control-flow-graph-based, three-address-code-style IR that's small enough to optimize quickly and structured enough to verify.
Why MIR exists
Before MIR (pre-Rust 1.12 era), rustc translated HIR straight to LLVM IR. That made many analyses awkward: the borrow checker had to reason about source-level constructs (for loops, ?, drop semantics), and codegen had to re-derive control flow. MIR fixed both: HIR is desugared into a small set of well-defined statements, and every later phase reads MIR.
Today MIR is the substrate for borrow checking, dataflow, optimization, const evaluation, and codegen.
Pipeline
graph TD
HIR[(HIR + TypeckResults)]
HIR --> ThirBuild[rustc_mir_build<br/>HIR → THIR]
ThirBuild --> THIR[(THIR)]
THIR --> Build[rustc_mir_build<br/>THIR → MIR]
Build --> MIR0[(MIR: built)]
MIR0 --> Borrowck[rustc_borrowck]
Borrowck --> MIR1[(MIR: validated)]
MIR1 --> Optimize[rustc_mir_transform]
Optimize --> MIR2[(MIR: optimized)]
MIR2 --> Eval[rustc_const_eval]
MIR2 --> Mono[rustc_monomorphize]
Eval -.const items.-> Mono
Mono --> Codegen[codegen backend]THIR
Before MIR comes THIR (Typed HIR) — a brief intermediate where every expression has a fully resolved type and every method call has a DefId. THIR is short-lived: rustc_mir_build builds it from HIR, then immediately lowers it to MIR. THIR exists because building MIR directly from HIR was complex; THIR is the "type-annotated tree" that simplifies the lowering. Defined in compiler/rustc_middle/src/thir.rs.
MIR shape
A MIR Body is:
- A list of
LocalDecls (_0is the return place,_1..are arguments, the rest are temporaries) - A list of
BasicBlocks — each a sequence ofStatements ending in aTerminator - Source info for diagnostics
- Promoted constants (an array of sub-bodies for promoted
&constants)
Statements are mostly assignments: _3 = _1 + _2, _4 = &_3, _5 = move _4. Terminators are Goto, SwitchInt, Return, Unreachable, Drop, Call, Assert, Yield, FalseEdge, FalseUnwind, InlineAsm. The full enum is in compiler/rustc_middle/src/mir/syntax.rs.
rustc_mir_build — building MIR
compiler/rustc_mir_build/ takes THIR and produces an unoptimized MIR Body. Its biggest sub-area is pattern lowering: match arms are lowered into a decision tree of SwitchInts and FalseEdges. The exhaustiveness check from rustc_pattern_analysis is invoked here.
rustc_borrowck — borrow checking
compiler/rustc_borrowck/ is the borrow checker. It runs on the freshly-built MIR and verifies:
- No two mutable borrows alias
- No mutable borrow aliases an immutable borrow
- Lifetimes (regions) outlive their referents
- Moves out of borrowed places aren't allowed
&mutcannot be reborrowed inappropriately
The implementation does region inference on the MIR, computing the smallest set of program points each lifetime variable must contain to satisfy the constraints. This is "Non-Lexical Lifetimes" (NLL) — although the term is now mostly historical because that's just how the borrow checker works.
The borrow checker is also the source of some of rustc's most-loved diagnostic improvements; the rustc_borrowck::diagnostics module is huge.
rustc_mir_dataflow — dataflow framework
compiler/rustc_mir_dataflow/ is a generic forward/backward dataflow analysis framework: define a state lattice and a transfer function, plug it into the engine, and get fixed-point analyses for free. Several analyses use it, the borrow checker among them.
rustc_mir_transform — optimization passes
compiler/rustc_mir_transform/ is a sequence of MIR-to-MIR passes:
SimplifyCfg— collapses goto chainsInline— inlines small#[inline]d calleesConstProp— constant propagationDeadStoreEliminationRemoveStorageMarkersDeaggregator—_x = (a, b)→ individual field storesJumpThreading- … and many more
The main loop runs each enabled pass in order; passes log dumps to mir_dump/ when -Zdump-mir=all is set. See Tests for MIR for the snapshot test infrastructure.
rustc_const_eval — the MIR interpreter
compiler/rustc_const_eval/ interprets MIR. It powers:
const fnevaluation during type checkingconstandstaticevaluation during codegen- Pattern matching on consts at compile time
- Miri (
src/tools/miri/), the standalone undefined-behavior detector — Miri is literally the same engine with extra alias tracking turned on (Stacked Borrows / Tree Borrows)
The interpreter operates on Allocations (byte buffers with provenance tracking) and provides a faithful runtime semantics for safe Rust plus the parts of unsafe Rust where the rules are agreed upon.
rustc_monomorphize — generic instantiation and partitioning
compiler/rustc_monomorphize/ does two things:
- Mono collection — find every concrete instantiation (
MonoItem) actually reached from the crate's roots. This is essentially a reachability analysis on the call graph. - CGU partitioning — group mono items into codegen units (CGUs) to balance parallel codegen. The resulting CGU plan is what each backend processes.
The tcx.collect_and_partition_mono_items(()) query is the entry point.
Key abstractions
| Type | Where | Purpose |
|---|---|---|
Body<'tcx> |
rustc_middle::mir |
A MIR body for one function/const/promoted |
BasicBlock / BasicBlockData |
rustc_middle::mir |
A CFG node |
Local / LocalDecl |
rustc_middle::mir |
A SSA-ish local variable |
Place<'tcx> |
rustc_middle::mir |
An lvalue: local + projection list |
Operand<'tcx> |
rustc_middle::mir |
An rvalue source (move, copy, constant) |
Statement / Terminator |
rustc_middle::mir::syntax |
One MIR instruction |
MoveData |
rustc_borrowck::move_data |
Move analysis output |
BorrowSet |
rustc_borrowck::borrow_set |
All borrows in a body, indexed |
Allocation |
rustc_const_eval::interpret |
Interpreter's heap / stack memory |
MonoItem |
rustc_middle::mir::mono |
A concrete generic instantiation |
Cgu |
rustc_middle::mir::mono |
A codegen unit |
Entry points for modification
- New MIR optimization →
rustc_mir_transform/src/passes/(note: opts must be sound for all targets, including const-eval) - Borrow checker fix →
rustc_borrowck. Probably also atests/ui/borrowck/test - Const-eval bug →
rustc_const_eval/src/interpret/. Probably also affects Miri - New MIR dump or visualization →
rustc_middle::mir::prettyormir_dump - Mono collection / CGU split — careful: changes affect compile time and binary layout
Where MIR-opt tests live
tests/mir-opt/ contains snapshot tests of MIR after specific passes. To run, edit, and regenerate:
./x test tests/mir-opt --blessSee also
- Type checking — what runs before MIR build
- Codegen — what runs after MIR is final
- rustc-dev-guide: MIR
- rustc-dev-guide: borrow checking
- Miri's README
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.