Software developers are often faced with a difficult choice when developing product-level code, you always want your code to be superior, which means you need to compile it at a high level of optimization, and you may want to debug the binary in your product, rather than the source files that are not optimized at compile time. If you've tried debugging optimized code, you probably already know the difficulty:
Source code statements do not execute sequentially, or they do not when you want them to execute;
The variable is not updated as expected;
A variable has no defined value, not even a defined identifier;
Updates to variables within the debugger have no effect on program execution.
This is not because of a compiler error, it was designed to retain the results of your program and external behavior, rather than its transient and internal behavior in the debugger.
Next Generation compilers
In 2012, IBM released the latest version of C + + and Fortran compilers on the Ibmpower system: the xlc/c++ compiler V12.1 and the Xlfortran compiler V14.1, all corresponding to the AIX and PowerLinux platforms. These new compilers provide a range of numerical options for debugging optimized code, and you are free to choose between fully optimized code and fully debugged code. In most other compilers, developers have two options available:
Compile a debug version that is not optimized (for example, using-g), or
An optimized version, but can be poorly debugged (for example, using-O2).
In the new xlc++ V12.1 and XL FortranV14.1 compilers, you can use a series of-G values, from-g0 to-g9, the lower the debug level, the greater the likelihood of errors observed during debugging, which means that you are free to weigh debugging and performance. When the program is optimized, the compiler will ensure that all levels of debugging, and in the debugging process to ensure that the expected behavior effectively maximize the performance of the application.
Order of execution
In the optimization process, compilers often rearrange the logic without changing the results of the program, and the compiler does this either to improve the performance of the program directly or to allow the next optimization to improve the performance of the program. In addition, in order to improve processor throughput or other reasons, when the primary optimization phase is complete and the instruction is generated, the sequence of instructions associated with the source line may also be reordered.
The optimizations of these compilers have two main effects: first, if you step through the program by the number of lines in the source code, the program may not execute in the correct order. Second, if you set a breakpoint at the beginning of a process, no one can guarantee that the parameters of the process will contain the correct values at this time, and the program will not even enter the process at all. This is because the compiler will inline the invoked procedure code within the optimization process to the call. In earlier versions of Xlc/c++ and Xlfortran, the old-G behavior generates all debugging information, but it is not known whether it is useful for an optimized program, so in a program with-G and-O, when you try to debug and observe what the parameters of a particular procedure are called, You can't even determine if a breakpoint set at the process entrance will allow you to see the actual values of these parameters. However, the-G3 or higher debug level ensures that the parameters at the entrance to the process are valid and visible.
Some of the statements in the optimization code may not be executed, and others may be executed before the statements before them. If you set a breakpoint in a given line of source code, you cannot be sure whether the variable was assigned the correct value in the row before it logically. For example, consider the program segment:
Ten x=x+1;
11FL=FL1/FL2;
y=y+1;
If we set a breakpoint on line 11th and run the program, the debugger will stop at the first instruction associated with line 11th, but the 10th line may not have been executed since the 10th line is unrelated to the 11th line, and the compiler is free to swap them in order. If you want to step through this code, you may find that we have already performed 11 lines before stopping at line 10th, which is a strong signal (but not a certain) that the instructions associated with line 10th have not yet been executed. In this example, the compiler will do the division as early as possible, because the division instruction has a long delay, an advanced pipelined processor can continue to work while division is in place, so that there is no association behavior, such as reading the value of x into the register and adding it to 1, which may occur simultaneously. Suppose we are interested in the result of division at line 11th. In a program that has not been optimized, we only need to step to line 12th and then look at the value of FL. However, in the optimized program, step to step 12th does not guarantee that all operations related to line 11th have been completed, we may have completed division but have not yet saved the results back to memory, so determine The only way a variable can already display the correct result is to step into the machine instruction until you see that the result of the division operation is written back into the memory space. If you are only concerned with the value of the result (rather than verifying that the variable is updated), instead you can print its value while the division operation updates its target register.
When you compile a program with xlc/c++ V12.1 or XL FortranV14.1-g8 or higher options, the debugger can get the state of the program at the start of each executable statement. Using-g8 in the previous example ensures that when you reach the breakpoint on line 11th, the addition of line 10th is complete, and you can get the result from the debugger.