What Optimization Levels Actually Change
The same code.
Different machine instructions.
Different behavior under the debugger.
1. The Purpose of Optimization
Compilers translate high-level code into machine instructions. During this process, they apply
optimization passes to improve performance, reduce code size, or simplify execution.
Optimization levels control how aggressively the compiler transforms the program. These levels determine whether the compiler prioritizes easier debugging, smaller binaries, or faster execution.
Optimization levels control how aggressively the compiler transforms the program. These levels determine whether the compiler prioritizes easier debugging, smaller binaries, or faster execution.
2. No Optimization -O0
-O0 disables most optimization passes.Characteristics:
- Code closely follows the original source
- Variables remain visible in the debugger
- Execution order matches the written code
This level is ideal for debugging and early development. However, it produces slow and inefficient machine code, making it unsuitable for performance testing or final firmware builds.
3. Basic Optimization -O1
-O1 enables simple optimizations that improve efficiency without drastically altering
program structure.Typical transformations include:
- removing redundant instructions
- simple constant propagation
- basic dead code elimination
The resulting program runs faster than
-O0, while still remaining relatively easy to
debug.
4. Production Optimization -O2
-O2 enables a much broader set of optimization techniques, such as:
- function inlining
- loop optimization
- instruction scheduling
- better register allocation
For most firmware projects,
-O2 is considered the standard optimization level for
production builds because it balances performance and binary size.
5. Aggressive Optimization -O3
-O3 applies even more aggressive transformations focused on maximum execution speed,
including:
- deeper function inlining
- loop unrolling
- vectorization where supported
- advanced instruction scheduling
While this can improve performance, it may also increase binary size and sometimes introduce unexpected timing differences, which can be critical in embedded systems.
6. Why This Matters in Embedded Systems
In firmware development, optimization levels influence more than just speed. They can affect:
A bug that does not appear at
Next
→ Debug vs Release Builds
- interrupt timing
- memory layout
- instruction ordering
- debugging behavior
A bug that does not appear at
-O0 may appear at -O2 or -O3
because the compiler reorganizes the program. For this reason, firmware should always be tested
using the same optimization level used in production builds.