[Bug rtl-optimization/59099] New: Erroneous register allocation on 32-bit x86 using regparm
ian at airs dot com
gcc-bugzilla@gcc.gnu.org
Wed Nov 13 02:20:00 GMT 2013
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59099
Bug ID: 59099
Summary: Erroneous register allocation on 32-bit x86 using
regparm
Product: gcc
Version: 4.8.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: ian at airs dot com
CC: vmakarov at redhat dot com
The appended test case should run without error and return 0. When I compile
it with -O2 -fPIC -m32 for 32-bit x86, it crashes at runtime with a
segmentation violation.
The generated code is incorrect. The loop is entered like this:
movl 12(%esp), %eax
leal 4(%esi), %ecx
movl %edi, 64(%esp)
xorl %esi, %esi
subl $1, %eax
movl %eax, 20(%esp)
jmp .L7
Note that %eax holds a value stored in 20(%esp), which as we will see is used
to terminate the loop. At .L7 we see this:
.L7:
movl 4(%esp), %edi
testl %edi, %edi
jne .L5
cmpl %edx, 20(%esp)
jne .L5
Note that nothing changes %eax. Note the comparison with 20(%esp).
At .L5 we see this:
.L5:
movl 64(%esp), %edi
movl (%eax), %eax
Note that we are loading a value from %eax. But at this point it still holds
the value it was given before the loop, which is a counter, not a pointer.
I have not tried to track down the problem, but superficially it appears that
the register allocator has decided to rematerialize the pointer p from the
register parameter, without realizing that the register has changed since the
start of the function.
This is reduced from code in the libgo library. The libgo code does not use
regparm, but the function in question is a static function and the optimizers
assign it regparm ((1)).
void (*pfn)(void);
struct s
{
void** q;
int h;
int t;
int s;
};
void* f (struct s *, struct s *) __attribute__ ((noinline, regparm(1)));
void*
__attribute__ ((regparm(1)))
f (struct s *p, struct s *p2)
{
void *gp, *gp1;
int t, h, s, t2, h2, c, i;
if (p2->h == p2->t)
return 0;
(*pfn) ();
h = p->h;
t = p->t;
s = p->s;
h2 = p2->h;
t2 = p2->t;
gp = p2->q[h2++];
c = (t2 - h2) / 2;
for (i = 0; i != c; i++)
{
if (t == h || (h == 0 && t == s - 1))
break;
gp1 = p2->q[h2++];
p->q[t++] = gp1;
if (t == s)
t = 0;
}
p2->h = h2;
return gp;
}
static void fn () { }
int
main()
{
struct s s1, s2;
void *q[10];
pfn = fn;
s1.q = q;
s1.h = 0;
s1.t = 2;
s1.s = 4;
s2.q = q;
s2.h = 0;
s2.t = 4;
s2.s = 2;
f (&s1, &s2);
return 0;
}
More information about the Gcc-bugs
mailing list