Chatper 4. Preliminary: Compiler Internals
IR
Our analysis platform is primarily based on two forms of Rust intermediate representations: HIR and MIR.
- HIR: An AST-like, type-checked, high-level intermediate representation that closely follows Rust’s surface syntax while eliminating syntactic sugar.
- MIR: A LLVM-IR-like, mid-level intermediate representation designed to simplify borrow checking, optimization, and program analysis. Note that MIR is not SSA.
You can obtain the HIR or MIR of a Rust source file by executing the following commands:
cargo rustc -- -Z unpretty=hir-tree
cargo rustc -- -Zunpretty=mir
Key Terms and Usages
- TyCtxt: It is the central data structure of Rust compilers. We can obtain the hir or mir of a function based on the object.
- DefId: It is a globally unique identifier that identifies an item (such as a function, type, trait, or impl) across all crates by pairing a crate identifier with a definition index.
- LocalDefId: A crate-local identifier that is equivalent to a DefId with
krate == LOCAL_CRATE. UnlikeDefId, it does not carry a crate identifier and therefore cannot refer to definitions from external crates. - Place: An abstract memory location in MIR. A Place describes where a value is stored or accessed, consisting of a base (such as a local variable or static) and a projection path (e.g., field access, dereference, indexing).
- Local: An index identifying a local variable in a MIR body, such as function parameters, temporaries, or user-declared variables.
To obtain the mir of a function.
#![allow(unused)] fn main() { let mir = optimized_mir(def_id); }
To obtain the body of a function.
#![allow(unused)] fn main() { let body = self.tcx.optimized_mir(def_id); }
#![allow(unused)] fn main() { let mut ty = body.local_decls[local].ty; }