From Bugzilla Helper: User-Agent: Mozilla/5.0 (X11; U; Linux 2.4.3 i686; en-US; 0.8.1) Gecko/20010421 Description of problem: Static initializers are optimized very poorly. Jump optimization seems not to be performed, and when the initializers have a result that can be verified as static at compile time, they are not removed and simply set up as constant values in the .rodata or .data section. How reproducible: Always Steps to Reproduce: 1.g++ -pipe -march=athlon -O2 -S example.cpp 2.Examine example.s. Actual Results: .file "example.cpp" .version "01.01" gcc2_compiled.: .globl abarney .bss .align 4 .type abarney,@object .size abarney,8 abarney: .zero 8 .globl afred .align 4 .type afred,@object .size afred,4 afred: .zero 4 .text .align 16 .type __static_initialization_and_destruction_0,@function __static_initialization_and_destruction_0: .LFB1: pushl %ebp .LCFI0: movl %esp, %ebp .LCFI1: movl 12(%ebp), %eax movl 8(%ebp), %edx cmpl $65535, %eax jne .L3 cmpl $1, %edx jne .L3 movl $5, abarney movl $6, abarney+4 .L3: cmpl $65535, %eax jne .L11 decl %edx jne .L11 movl $2, afred .L11: popl %ebp ret .LFE1: .Lfe1: .size __static_initialization_and_destruction_0,.Lfe1-__static_initialization_and_destruction_0 .align 16 .type _GLOBAL_.I.abarney,@function _GLOBAL_.I.abarney: .LFB2: pushl %ebp .LCFI2: movl %esp, %ebp .LCFI3: subl $16, %esp .LCFI4: pushl $65535 pushl $1 .LCFI5: call __static_initialization_and_destruction_0 addl $16, %esp leave ret .LFE2: .Lfe2: .size _GLOBAL_.I.abarney,.Lfe2-_GLOBAL_.I.abarney .section .ctors,"aw" .long _GLOBAL_.I.abarney .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-81)" Expected Results: .file "example2.cpp" .version "01.01" gcc2_compiled.: .globl abarney .section .rodata .align 4 .type abarney,@object .size abarney,8 abarney: .long 5 .long 6 .globl afred .align 4 .type afred,@object .size afred,4 afred: .long 2 .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-81)" Additional info: example.cpp: class Fred { public: Fred(int x) : x_(x) { } private: int x_; }; class Barney : public Fred { public: Barney(int x, int y) : Fred(x), y_(y) { } private: int y_; }; extern const Barney abarney(5, 6); extern const Fred afred(2); ------------ The results of all these initializers can be statically determined at compile time. There is no reason I can think of they should be stuck in the .rodata section. If they were not const, they could be stuck in the .data section. Even if the initializer is run, the initializer itself will make repeated comparisons of %eax against $65535 instead of simply jumping to the end if the first such comparison registers as being equal. This situation is also easily determined by simple analysis, and jump optimization in ordinary code would catch it.
Created attachment 17827 [details] This is an example C++ source file that compiles with bloated initializers
As for eliminating the static initializers, ATM none of g++ 2.95.x, 2.96-RH, 3.0-branch or 3.1-head do this. It would be probably better if you requested this enhancement on @gnu.org lists (it is too late for 3.0, but for 3.1 it could be doable). As for the jump to test+jump not being optimized out, I'll look at what's going on. It seems that gcc 3.0 and 3.1 behave the same way, have reproduced it on C code as well: int abarney[2]; int afred[1]; void foo(int edx, int eax) { if (eax == 65535) { if (edx == 1) { abarney[0] = 5; abarney[1] = 6; } } if (eax == 65535) { if (--edx == 0) afred[0] = 2; } }
Jump threading should be fixed in gcc-2.96-86, likewise it will generate better code for __static_initialization_and_destruction_0 (which even jump threading is not able to cope with).
Thanks, in gcc-c++-2.96-88, this is now lots better than it was. :-) I still say the constructors can be done away with completely and the constant initial values moved into the .bss segment, but I imagine that's kind of hard to do. It would solve a major class of problems dealing with order of static intialization though. I wouldn't have to worry about initialization order for many types of global constants.