------- Comment #7 from jakub at gcc dot gnu dot org 2007-08-22 13:27 -------
Actually, to me this doesn't look like missed-optimization at all.
And you should be happy for 4.2.1 generated bigger code, 4.1.1 optimized out
something it shouldn't.
Below is an stripped down testcase, which works on 3.4/4.1/4.2/4.3 with -O0
or -O2 -fno-strict-aliasing, works even with -O2 with 3.4 and 4.2, segfaults
with 4.1 (x86_64 -m64, aborts with x86_64 -m32) and issues a bogus warning
about unitialized common_head and aborts on the trunk.
/* { dg-do run } */
/* { dg-options "-O2" } */
typedef __SIZE_TYPE__ size_t;
extern void exit (int);
extern void *malloc (size_t);
extern void *realloc (void *, size_t);
extern void abort (void);
void *
__attribute__ ((noinline))
xmalloc (size_t size)
{
void *p = malloc (size);
if (p == 0)
exit (0);
return p;
}
void *
__attribute__ ((noinline))
xrealloc (void *old, size_t size)
{
void *p = realloc (old, size);
if (p == 0)
exit (0);
return p;
}
struct obj_section
{
unsigned int sh_type;
unsigned int sh_flags;
unsigned int sh_size;
unsigned int sh_addralign;
const char *name;
char *contents;
struct obj_section *load_next;
int idx;
};
struct obj_symbol
{
struct obj_symbol *next;
unsigned long value;
unsigned long size;
int secidx;
};
struct obj_file
{
unsigned short e_shnum;
struct obj_section **sections;
struct obj_symbol *symtab[521];
};
static void
__attribute__((noinline))
obj_allocate_commons (struct obj_file *f)
{
struct common_entry
{
struct common_entry *next;
struct obj_symbol *sym;
} *common_head = (void *) 0;
unsigned long i;
for (i = 0; i < 521; ++i)
{
struct obj_symbol *sym;
for (sym = f->symtab[i]; sym; sym = sym->next)
if (sym->secidx == 0xfff2)
{
struct common_entry **p, *n;
for (p = &common_head; *p; p = &(*p)->next)
if (sym->size <= (*p)->sym->size)
break;
n = __builtin_alloca (sizeof (*n));
n->next = *p;
n->sym = sym;
*p = n;
}
}
if (common_head)
{
for (i = 0; i < f->e_shnum; ++i)
if (f->sections[i]->sh_type == 8)
break;
if (i == f->e_shnum)
{
struct obj_section *sec;
f->sections = xrealloc (f->sections, (i + 1) * sizeof (sec));
f->sections[i] = sec = xmalloc (sizeof (struct obj_section));
f->e_shnum = i + 1;
__builtin_memset (sec, 0, sizeof (*sec));
sec->sh_type = 1;
sec->sh_flags = (1 << 0) | (1 << 1);
sec->name = ".bss";
sec->idx = i;
}
}
}
int
main (void)
{
struct obj_file of;
struct obj_symbol s;
struct obj_section *sec;
__builtin_memset (&s, 0, sizeof (s));
s.value = 4;
s.size = 4;
s.secidx = 0xfff2;
__builtin_memset (&of, 0, sizeof (of));
of.e_shnum = 2;
of.sections = xmalloc (2 * sizeof (sec));
of.sections[0] = sec = xmalloc (sizeof (struct obj_section));
__builtin_memset (sec, 0, sizeof (*sec));
sec->sh_type = 4;
sec->sh_flags = (1 << 0) | (1 << 1);
sec->name = ".foo";
sec->idx = 0;
of.sections[1] = sec = xmalloc (sizeof (struct obj_section));
__builtin_memset (sec, 0, sizeof (*sec));
sec->sh_type = 4;
sec->sh_flags = (1 << 0) | (1 << 1);
sec->name = ".bar";
sec->idx = 1;
of.symtab[0] = &s;
obj_allocate_commons (&of);
if (of.e_shnum != 3)
abort ();
return 0;
}
Even on the original testcase, obj_allocate_commons is so short because
the whole if (common_head) { ... } huge block has been completely optimized
out (watch for xrealloc call e.g.).
To me the code looks valid, there is no type puning involved.
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33136