c++/2806: g++ 2.96 inadequate optimization in static and global initializers

eric-gcc@omnifarious.org eric-gcc@omnifarious.org
Fri May 11 15:06:00 GMT 2001


>Number:         2806
>Category:       c++
>Synopsis:       g++ 2.96 inadequate optimization in static and global initializers
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          pessimizes-code
>Submitter-Id:   net
>Arrival-Date:   Fri May 11 15:06:01 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Eric Hopper
>Release:        gcc 2.96  (Yeah, yeah, I know, RedHat's, but I bet gcc 2.95.3 does it too)
>Organization:
>Environment:
RH Linux 7.0
>Description:
This code:
----  (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);
----

when compiled liked this: g++ -pipe -march=athlon -O2 -S example.cpp

results in this assembly:
---- (pessimized example.s)
        .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)"
----

when it should've resulted in something like this:
---- .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)"
----

The results of all these initializers can be statically determined at compile time.  There is no reason I can think of they shouldn't 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.

Actually, the repeated compare jump sequence can be created with non-initializer code too.  Here's an example program that I've been told produced sub-optimal assembly:

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;
    }
}
>How-To-Repeat:

>Fix:

>Release-Note:
>Audit-Trail:
>Unformatted:



More information about the Gcc-bugs mailing list