Debugging optimized code

Debugging optimized programs presents special usability problems. Optimization can change the sequence of operations, add or remove code, change variable data locations, and perform other transformations that make it difficult to associate the generated code with the original source statements.

For example:
Data location issues
With an optimized program, it is not always certain where the most current value for a variable is located. For example, a value in memory may not be current if the most current value is being stored in a register. Most debuggers are incapable of following the removal of stores to a variable, and to the debugger it appears as though that variable is never updated, or possibly even never set. This contrasts with no optimization where all values are flushed back to memory and debugging can be more effective and usable.
Instruction scheduling issues
With an optimized program, the compiler might reorder instructions. That is, instructions might not be executed in the order you would expect based on the sequence of lines in the original source code. Also, the sequence of instructions for a statement might not be contiguous. As you step through the program with a debugger, the program may appear as if it is returning to a previously executed line in the code (interleaving of instructions).
Consolidating variable values
Optimizations can result in the removal and consolidation of variables. For example, if a program has two expressions that assign the same value to two different variables, the compiler may substitute a single variable. This can inhibit debug usability because a variable that a programmer is expecting to see is no longer available in the optimized program.
There are a couple of different approaches you can take to improve debug capabilities while also optimizing your program:
Debug non-optimized code first
Debug a non-optimized version of your program first, then recompile it with your desired optimization options. See Debugging in the presence of optimization for some compiler options that are useful in this approach.
Use -g level
Use the -g level suboption to control the amount of debugging information made available. Increasing it improves debug capability, but prevents some optimizations.
Use -qoptdebug
When compiling with -O3 optimization level or higher, use the compiler option -qoptdebug to generate a pseudocode file that more accurately maps to how instructions and variable values will operate in an optimized program. With this option, when you load your program into a debugger, you will be debugging the pseudocode for the optimized program. See Using -qoptdebug to help debug optimized programs for more information.