Some comments about quality of generanted code.
Ram'on Garc'ia Fern'andez
ramon@jl1.quim.ucm.es
Wed Aug 4 15:19:00 GMT 1999
Hello,
I have just tested the new GCC 2.95 on a Pentium II/Linux machine and I have
some comments to make.
1) Stack alignment code
GCC generates lots of redundant code to access the stack, for example:
main:
.LFB1:
pushl %ebp
.LCFI0:
movl %esp,%ebp
.LCFI1:
subl $116,%esp
.LCFI2:
pushl %ebx
.LCFI3:
addl $-12,%esp
pushl $8
.LCFI4:
call __builtin_new
movl %eax,%ebx
movb $1,-97(%ebp)
.LEHB529:
addl $16,%esp
addl $-8,%esp
See the last two instructions. They could be replaced by one. The problem
is related with the attempts to keep the stack aligned. Compiling with
-mpreferred-stack-boundary=2 removes the problem. The amount of code added
by stack alignment is very large. The size of the code that I tested changed
from 471 bytes to 414 when enabling this option. I believe that stack
alignment is beneficial for floating point. I am not sure if this high
alignment should be done by default. Anyway, if done, it would be much
better to do it in such way that these redundant calculations can be
simplified.
2) Exception handling
Other feature that stroke my attention is the amount of code added by
exception handling. The size of the main function above changed from 116 bytes
to 471 bytes when enabling exception handling (this does included the code
only; it does not include the tables). A bit large, isn't it? Look at the
generated code yourself.
I tested with -fnew-abi, but did not see any change. Just some change
in the manged name of std::terminate. All the code exactly the same.
3) PIC
Another comment is abut the code generated using -fPIC. This flag reserves a
register for accessing global variables through the GOT table, right? This
is not necessary for global functions, thanks to the relative call instruction.
However, at present GCC allocates this register always, even if there are
no global variables in a function, which is a very frecuent situation
in well structured code. I believe that the correct way of supporting PIC
code would be to add an expression that calculates the GOT position at the
top of the function, and then use that expression. So if it is not used,
because there are no global variables, it could be simply removed. Otherwise
it could be calculated in the most optimal way, for example, if there is
one global variable only, the register with the GOT address would be locked
only as long as it is needed for calculating that variable, rather that along
all the function. In my test code std::cout is the only global variable,
but the register %ebx is locked along all the function.
I am attaching here the code that I used for all the comments above as
well as the assembly output (compiled without PIC).
4) New IA32 backend
A final comment regarding the new IA32 backend recently donated by Cygnus
solutions. I have tested it and it is really an improvement. Testing
some Fortran codes that we use for benchmarking, the new G77 compiler
with this backend performs exactly like the Porland group compiler.
I had no problems running it with -O3 -ffast-math -march=pentiumpro
-fomit-frame-pointer. The code gived correct results.
By contrast, the standard G77 from GCC-2.95 performs about 15 - 20 % slower.
Since testing the new backend should not be very complicated (it is just
for one architecture) it would be very good if there is a release of GCC
with that new backend. 15 % of performance makes a lot of diffence, it
is like changing from a Pentium 400 MHz to a Pentium 460 MHz.
It would be very good to release a version of GCC with the new backend
before GCC 3.0. The Porland compiler is becoming very popular in the
scientific comunity. Therefore an early relase of GCC with the new backend
would encourage more use of free software.
Ramon
More information about the Gcc
mailing list