Course contentsShow
← Rust
Lesson 1748 of 1,91015. Performance and Architectural EngineeringFree lesson

Compiler Optimization Analysis

Analyze intermediate representation to verify if expensive code was successfully inlined.

In this lesson, you will learn how to verify if the Rust compiler has successfully inlined expensive functions by inspecting the generated Intermediate Representation (IR).

The Inlining Challenge

Inlining is a powerful optimization where the compiler replaces a function call with the actual body of the function, effectively eliminating the overhead of setting up a stack frame and performing a jump. However, the compiler’s inliner is conservative; it won't inline if a function is too large or if it lacks sufficient metadata. To confirm that your performance-critical code is being inlined, you must move beyond source code and analyze the compiler's output.

Verifying via LLVM IR

When you compile Rust code, it eventually reaches the LLVM IR stage. If a function is inlined, its call site in the IR will no longer contain a call instruction to that function's label. Instead, the logic will be seamlessly integrated into the caller's block.

To inspect this, you can use the cargo-show-asm tool or emit LLVM IR directly. Consider this scenario:

#[inline(always)]
fn heavy_calculation(x: u64) -> u64 {
    x * 42
}

pub fn execute(n: u64) -> u64 {
    heavy_calculation(n) + 10
}

If you compile this with cargo rustc -- --emit llvm-ir, you can search the generated .ll file for the definition of execute.

  • If inlined: You will see the multiplication logic mul i64 %0, 42 directly inside the body of execute. You will not find a call i64 @heavy_calculation instruction.
  • If not inlined: You will see a call opcode followed by the function name, indicating the compiler decided the cost of inlining outweighed the benefit.

Strategic Inspection

When analyzing high-performance loops (such as those you have previously optimized using loop unrolling or SIMD), check the IR to ensure your abstractions—like iterators or closures—are not causing hidden function calls. If your IR shows call instructions inside a hot loop, you have discovered a performance bottleneck that prevents the compiler from performing further inter-procedural optimizations like vectorization.

Key Takeaway: Use LLVM IR inspection to confirm that function calls have been replaced by their definitions, ensuring that your abstractions do not introduce hidden overhead in hot code paths.