4.12 Optimizations
The MPLAB XC8 compiler can perform a variety of
optimizations. Optimizations can be controlled using the -O
option
(described in 3.6.6 Options for Controlling Optimization). In
Free mode, some of these optimizations are disabled. Even if they are enabled,
optimizations might only be applied if very specific conditions are met. As a result, you
might see that some lines of code are optimized, but other similar lines are not. When
debugging code, you may wish to reduce the optimization level to ensure expected program
flow.
Level | Optimization sets available |
---|---|
O0 |
Rudimentary optimization |
O1 |
Minimal optimizations |
O2 |
All generic optimizations |
O3
(Licensed
only) |
All generic optimizations plus those targeting speed |
Os
(Licensed
only) |
All generic optimizations plus those targeting space |
- Simplification and folding of constant expressions to simplify expressions.
- Expression tree optimizations to ensure efficient assembly generation.
- Propagation of constants is performed where the numerical contents
of a variable or expression can be determined at compile time. Variables which are
not
volatile
and whose value can be exactly determined are replaced with the numerical value. Uninitialized global variables are assumed to contain zero prior to any assignment to them. - Unreachable code is removed. C Statements that cannot be reached are removed before they generate assembly code. This allows subsequent optimizations to be applied at the C level.
- Strength reductions and expression transformations are applied to all expression trees before code is generated. This involves replacing expressions with equivalent, but less costly operations.
- Unused variables in a program are removed. This applies to all variables. Variables removed will not have memory reserved for them, will not appear in any list or map file, and will not be present in debug information (will not be observable in the debugger). A warning is produced if an unused variable is encountered. Taking the address of a variable or referencing its assembly-domain symbol in hand-written assembly code also constitutes use of the variable.
- Redundant assignments to variables not subsequently used are
removed, unless the variable is
volatile
. The assignment statement is completely removed, as if it was never present in the original source code. No code will be produced for it and you will not be able to set a breakpoint on that line in the debugger. - Unused functions in a program are removed. A function is considered
unused if it is not called, directly or indirectly, nor has had its address taken.
The entire function is removed, as if it was never present in the original source
code. No code will be produced for it and you will not be able to set a breakpoint on
any line in the function in the debugger. Referencing a function’s assembly-domain
symbol in a separate hand-written assembly module will prevent it being removed. The
assembly code need only use the symbol in the
.global
directive. - Dereferencing pointers with only target can be replaced with direct access of the target object. This applies to data and function pointers.
- Inlining of small routines is done so that a call to the routine is not required. Only very small routines (typically a few instructions) that are called only once will be changed so that code size is not adversely impacted. This speeds code execution without a significant increase in code size.
- Explicit inlining of functions that use the inline specifier (see 4.7.1.1 Inline Specifier).
- Procedural abstraction is performed on assembly code sequences that appear more than once. This is essentially a reverse inlining process. The code sequences are abstracted into callable routines. A call to this routine will replace every instance of the original code sequence. This optimization reduces code size considerably, with a small impact on code speed. It can, however, adversely impact debugging.
- Replacement of long-form call and jump instructions with their shorter relative forms, either directly or via trampoline constructs.
- Peephole optimizations are performed on every instruction. These optimizations consider the state of execution at and immediately around each instruction – hence the name. They either alter or delete one or more instructions at each step.