Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Rust’s LLVM backend receives LLVM IR—not generic Rust source. Rustc first identifies the concrete generic instances a program needs, then translates MIR into LLVM IR while substituting those concrete types. It groups the generated code into codegen units (CGUs), which LLVM processes as modules, before object files are linked into the requested output.

How Rust code reaches LLVM

  1. Rustc collects items for code generation. Before lowering MIR for code generation, rustc determines which concrete instances of generic functions and other monomorphized items are needed, then partitions those items into CGUs. The compiler guide describes this work under collect_and_partition_mono_items.
  2. Rustc translates MIR into concrete code. Generic MIR supports earlier compiler analysis, but code generation needs concrete types. As rustc translates MIR, it substitutes those types and emits each needed instance. The Rust Compiler Development Guide explains: “The actual monomorphization is performed as we go, while we do the translation.” Rust Compiler Development Guide: Lowering MIR to a Codegen IR.
  3. The LLVM backend receives LLVM IR. That IR represents the concrete code rustc has produced from MIR; LLVM does not receive the original generic Rust source.
  4. Rustc organizes the IR into CGUs. Each codegen unit corresponds to an LLVM module. Modules can be processed independently, including in parallel, and CGUs also matter for incremental compilation.
  5. LLVM and the linker finish the build. LLVM optimizes modules and emits object files; the linker combines the relevant outputs into an executable or another requested artifact. With some forms of link-time optimization (LTO), optimization can also take place during linking.

This describes rustc’s LLVM backend. Rust supports other codegen backends, so the LLVM-specific stages do not describe every possible Rust build.

What monomorphization means for generics

Rust generates code for the concrete generic types a program uses. For example, use of Vec<u64> and Vec<String> entails generated Vec code for those concrete types. This static specialization can produce efficient code, but creating concrete instances has compile-time and binary-size costs.

It helps to separate two stages: rustc collects the required instances, then makes them concrete as it translates MIR into LLVM IR. Saying that LLVM receives generic Rust code skips both the MIR-to-IR translation and the concrete specialization.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What codegen units contain

CGUs package code-generation items into LLVM modules. In the compiler guide’s described default partitioning, rustc creates two CGUs for each source-level module: a stable unit for non-generic code and a more volatile unit for monomorphized or specialized instances. This is a description of that partitioning approach, not a guarantee that every configuration or compiler version has identical boundaries.

Generic instances from a dependency may be generated in the consuming crate’s CGU. Ordinary non-generic functions from a dependency are not simply copied into every downstream CGU. The guide distinguishes ordinary functions, inline functions, generic functions, and generic inline functions when describing where code is generated.

CGU boundaries support independent module processing and are relevant to incremental reuse. They are not immutable boundaries across all compiler versions, build configurations, or LTO modes; optimization may move into the link stage.

How to inspect the LLVM input

The Rust Compiler Development Guide documents these options for examining generated output. Compiler flags and output details can vary by rustc version and settings.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • --emit=llvm-ir asks rustc to emit LLVM IR. With Cargo, the guide shows RUSTFLAGS='--emit=llvm-ir'.
  • -C save-temps preserves intermediate bitcode. The llvm-dis utility can convert bitcode into readable .ll text.
  • -C codegen-units=1 is used in the guide’s example for clearer pass output, because output from multiple CGUs may interleave.

Different optimization settings produce different IR, so an emitted file is a snapshot of a particular build configuration—not a universal representation of every Rust program or compiler run. For the documented commands and context, see Rust Compiler Development Guide: LLVM.

Rust’s compiler tests also distinguish emitted-IR checks from tests of mono-item collection and CGU partitioning. The former inspect codegen output; the latter examine what rustc collects and how it divides that work.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What can change between builds

The exact output and processing boundaries depend on several build choices. When investigating a build, identify:

  • Backend: whether the compiler is using LLVM or another supported codegen backend.
  • Optimization and LTO: these affect generated IR and can change where optimization occurs.
  • CGU count and partitioning: these affect module boundaries and can affect how output is organized.
  • Which stage you are inspecting: rustc-emitted LLVM IR differs from IR after LLVM passes.

The compiler guide pages do not specify one rustc release as the universal reference. Treat implementation details and flags as version-sensitive, and check the documentation for the compiler version you are using.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.