📎 Webclip
Loop Optimizations in C# (and various other compilers)
This post uses infographics to show loop optimizations in C# and briefly compares them with Go and Rust. It focuses on how the compiler and JIT react to specific loop shapes, compiler versions, and code constructs.
Reading notes#
- C# loop cloning can remove array bounds checks in a fast path by cloning the loop into slow and fast paths.
- Loop hoisting moves expressions that can be computed once into a temporary variable or register.
- Compound assignment in C# emits a dup instruction in IL and can prevent loop cloning and hoisting in the JIT.
- Try-catch blocks block loop cloning and hoisting, even when part of the block is removed as empty.
- Loop optimizations are sensitive to the exact range expression; a slightly more complex loop condition can keep bounds checks on every iteration.
- With Span
, the compiler can remove bounds checks in the fast case, and working on a slice helps the compiler decide correctly. - Prolog creates the stack frame and epilog cleans it up; too many returns from a function in a loop can turn optimizations off.
- Go shows few advanced optimizations in the author’s simple tests.
- Rust applies many optimizations, including bounds checks, loop unrolling, and hoisting, depending on the range construction and count.
