This article is about constant merge, which is one of the simplest optimizations of the VC ++ compiler. This optimization means that the compiler directly calculates the expression results during compilation (during compilation) and replaces the expressions with the calculated results in the generated code. This avoids the cost of running these computations.
In the APP. cpp fileMainFunction:
- int main() { return 7 + 8; }
First, some notes about this article:
If you want to continue, please refer to the instructions below. In fact, you only need to select a correct variant from the Visual Studio list.
Note: If you are using a free compiler on Visual Studio Express, it can only run on x86, but it will also generate x64 code smoothly. This experiment is also useful .)
We can use the command CL/FA App. cpp to build the sample program. Use the/FA switch to create an output file to save the compilation code generated by the compiler. You can enter type App. asm to display it:
- PUBLIC main
- _TEXT SEGMENT
- main PROC
- mov eax, 15
- ret 0
- main ENDP
- _TEXT ENDS
- END
Interestingly, this commandMove ax, 15-- Assign only 15 values to the Register EAX (according to the definition of x64 call standard, x64 function will setIntValue, used as the result of the function and returned to the caller ). The compiler does not issue 7-plus 8 commands during runtime. As shown below:
- PUBLIC main
- _TEXT SEGMENT
- main PROC
- mov eax, 7
- add eax, 8
- ret 0
- main ENDP
- _TEXT ENDS
- END
Note: The last instruction of the two codes,Ret 0The control is returned to the caller and 0 bytes are displayed from the stack. Do not mislead the caller into believing that the return value is 0 !)
I guess you may be thinking: This is good, but which idiot would want to write 7 + 8 operations in the code? Indeed, you are right, but the compiler will regard this structure as a macro with side effects. After reading the example below, you will understand that constant merge is a useful optimization method:
- #define SECS_PER_MINUTE 60
- #define MINUTES_PER_HOUR 60
- #define HOURS_PER_DAY 24
-
- enum Event { Started, Stopped, LostData, ParityError };
-
- struct {
- int clock_time;
- enum Event ev;
- char* reason;
- } Record;
-
- int main() {
- const int table_size = SECS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY * sizeof Record;
- // rest of program
- }
We need to create a table that is large enough to store records every second. Therefore, table_size is the table size, expressed in bytes. It is easy to view the Assembly command of the variable table_size:
- mov DWORD PTR table_size$[rsp], 1382400 ; 00151800H
There is no multiplication command here. 60*60*24*16 = 1382400 is calculated during compilation.
In fact, when we look into the compiler, we will find that the constant merge operation is very simple, and it is executed by the front end. The backend optimizer does not require heavy lifting capabilities. So it always exists. Whether you enable optimization or O2) or disable optimization or Od, the optimization is always automatically executed.
Can we merge constants during compilation regardless of the complexity of expressions? -In fact, the front-end can handle Arbitrary Constant arithmetic expressions and even include the sizeof mentioned above, as long as they are computed during compilation) and operators+-*/% <> ++ And-). You can even use boolean values, logical operators, AND conditional operators if AND? :.
Does constant merge require a backend optimizer? Of course, see the following example:
- int bump(int n) { return n + 1; }
-
- int main() { return 3 + bump(6); }
Enter the command cl/FA/Od App. cpp and you will get the message: cannot optimize. Thank you !, Enter App. asm and we will get:
- mov ecx, 6
- call ?bump@@YAHH@Z ; bump
- add eax, 3
As we expected, ECX will save the first parameter 6, according to The x64 call convention, then call the bump function, and return the result to EAX, and then add 3 to EAX.
Let's see if we useCl/FA/O2 App. cppFor optimization, what will happen.
- mov eax,10
The backend optimizer has recognized that the bump function is very small and can be included in the caller. We will discuss this optimization method in the following sections, called inline function ). It can estimate the value of the entire expression at compilation, with only one command left. Amazing, right?
Http://blog.jobbole.com/47191/.