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; }