Get build code after every GCC optimization?

From compiler optimization to Wikipedia,

Compiler optimization is usually implemented using a sequence of optimizing transformations , algorithms that take a program and transform it to create a semantically equivalent output program that uses less resources.

and GCC has many optimization options.

I would like to examine the generated assembly (one -S gives) after each GCC optimization when compiling with various flags like -O1 , -O2 , -O3 , etc.

How can i do this?

Edit: My input will be C code.

+10
optimization c assembly gcc compiler-construction
Mar 05 '13 at 14:44
source share
7 answers

An intermediate view can be saved in files using the -fdump-tree-all switch.

The finer -fdump switches are -fdump .

See the gcc manual for more details.

To read these views, check out the GCC backend guide .

+7
Mar 05 '13 at 15:25
source share

Compile with the -S switch to get the build code. This should work for any level of optimization. For example, to get the assembly code generated in O2 mode, try:

  g++/gcc -S -O2 input.cpp 

the corresponding input.s will be created, which contains the generated assembly code. Repeat this for any level of optimization you want.

+1
Mar 05 '13 at 14:49
source share

gcc -S ( Capital S )

gives asm output, but assembler can make a difference, so I prefer just creating an object

gcc -c -o myfile.o myfile.c

then disassemble

objdump -D myfile.o

Understand that this is not connected, therefore the destination of the external branch and other external addresses will have a placeholder instead of a real number. If you want the optimization to be compiled without optimization (-O0), then compile with -O1, then -O2 and -O3, and see if something changes. There are other optimization flags that you can play with. To see the difference needed to compile with and without flags, compare them yourself.

diff will not work, you will see why (change register allocation).

+1
Mar 05 '13 at 15:05
source share

While you can take a small piece of code, compile it with -S and with many options, it's hard to understand what really changed. A slight change is required to make the code completely different - one variable entering the register means that the register is no longer available for something, which leads to detonation effects to the rest of the function code.

I compared the same code with two almost identical functions earlier today (with a question in C ++), and there was ONE difference in the source code. One change in which a variable was used to complete a condition within a single for loop led to a change in the lines of assembler code. Since the compiler decided to arrange the registers differently, using a different register for one of the main variables, and then everything else changed as a result.

I have seen cases where adding a small change to a function transfers it from built-in to non-integrated, which, in turn, makes big changes to ALL code in the program that calls this code.

So yes, of course, compile very simple code with various optimizations and use -S to check the code generated by the compiler. Then compare the different options to see what effect it has. But if you are not used to reading assembler code and do not understand what you are actually looking for, it is often difficult to see a forest for trees.

It is also worth considering that optimization steps often work together - one step allows you to take another step to do your job (inline leads to merging branches, using registers, etc.).

+1
Mar 05 '13 at 16:24
source share

gcc / clang performs optimization on intermediate representations (IR), which can be printed after each optimization step.

for gcc this is (-fdump-tree-all) ' http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html ' with clang this is (-llvm -print-after-all).

Clang / gcc offers much more options for analyzing optimizations. Easy to turn on / off optimization from the command line ( http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Optimize-Options.html , http://llvm.org/docs/Passes.html )

using clang-llvm, you can also specify optimization lists that were executed using the command line parameter (-mllvm -debug-pass = Structure)

+1
Mar 07 '13 at 8:34
source share

If you want to learn compiler optimization and agnostics for the compiler, then take a look at the Clang / LLVM projects. Clang is a C compiler that can output LLVM IR and LLVM commands that can use separate optimization sessions separately.

LLVM IR Output:

 clang test.c -S -emit-llvm -o test.ll 

Performing an optimization transition:

 opt test.ll -<optimization_pass> -S -o test_opt.ll 

Compile assembly:

 llc test.ll -o test.s 
0
Mar 05 '13 at 15:22
source share

Solution1:

gcc -O1 -S test.c (capital O and capital S)

Solution2:

This site can also help you. You can use -O0 , -O1 , .. any suitable compiler options to get what you want.

An example from this site: (verified by both solutions)

  void maxArray(double* x, double* y) { for (int i = 0; i < 65536; i++) { if (y[i] > x[i]) x[i] = y[i]; } } 
  • Compiler -O0 :

result:

 maxArray(double*, double*): pushq %rbp movq %rsp, %rbp movq %rdi, -24(%rbp) movq %rsi, -32(%rbp) movl $0, -4(%rbp) jmp .L2 .L5: movl -4(%rbp), %eax cltq leaq 0(,%rax,8), %rdx movq -32(%rbp), %rax addq %rdx, %rax movsd (%rax), %xmm0 movl -4(%rbp), %eax cltq leaq 0(,%rax,8), %rdx movq -24(%rbp), %rax addq %rdx, %rax movsd (%rax), %xmm1 ucomisd %xmm1, %xmm0 jbe .L3 movl -4(%rbp), %eax cltq leaq 0(,%rax,8), %rdx movq -24(%rbp), %rax addq %rax, %rdx movl -4(%rbp), %eax cltq leaq 0(,%rax,8), %rcx movq -32(%rbp), %rax addq %rcx, %rax movq (%rax), %rax movq %rax, (%rdx) .L3: addl $1, -4(%rbp) .L2: cmpl $65535, -4(%rbp) jle .L5 popq %rbp ret 
  • Compiler -O1 :

result:

 maxArray(double*, double*): movl $0, %eax .L5: movsd (%rsi,%rax), %xmm0 ucomisd (%rdi,%rax), %xmm0 jbe .L2 movsd %xmm0, (%rdi,%rax) .L2: addq $8, %rax cmpq $524288, %rax jne .L5 rep; ret 
0
Aug 03 '14 at 1:50
source share



All Articles