seen with 20091228 trunk and 4.4 branch on i486-linux-gnu, not seen with 4.3 branch (opening new report, because PR39431 is fixed for 4.4 and 4.5). Adding -fomit-frame-pointer avoids the ice. Matthias $ /usr/lib/gcc-snapshot/bin/gcc -g -O2 -fno-gcse -fno-inline-functions -fno-unit-at-a-time -fstack-protector -c cvm.i cvm.c: In function '_ILCVMInterpreter': cvm.c:889:1: error: unable to find a register to spill in class 'GENERAL_REGS' cvm.c:889:1: error: this is the insn: (insn 11992 11991 11993 863 cvm_ptr.c:66 (set (mem:DI (plus:SI (plus:SI (mult:SI (reg:SI 6750 [ D.20325 ]) (const_int 8 [0x8])) (reg/f:SI 6746 [ tempptr.3460 ])) (const_int 4 [0x4])) [16 S8 A64]) (reg:DI 12123)) 88 {*movdi_2} (expr_list:REG_DEAD (reg:DI 12123) (expr_list:REG_DEAD (reg:SI 6750 [ D.20325 ]) (expr_list:REG_DEAD (reg/f:SI 6746 [ tempptr.3460 ]) (nil))))) cvm.c:889:1: internal compiler error: in spill_failure, at reload1.c:2141 Please submit a full bug report, with preprocessed source if appropriate.
Created attachment 19411 [details] preprocessed source
With 3 register vars in the function (ebx, edi, esi) on the register starved ix86 the error is tollerable. From the 8 registers the programmer takes 3, %esp is fixed, without -fomit-frame-pointer %ebp is fixed too, which leaves just %eax, %edx and %ecx for register allocation. Even if this happens to compile, the result can't work fast, as almost all insns need to have temporaries spilled and reread back.
Reduced testcase: /* { dg-do compile { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */ /* { dg-options "-O2 -fno-gcse" } */ struct C; struct B { struct C *b; }; struct C { void (*baz) (struct B *, void *, int); }; typedef union { int f; void *e; } D; struct E { struct B *e; }; struct A { struct E *a1; D *a2; D *a3; }; void foo (long *x, long y) { *(long long *) x = y; } extern long fn1 (D); extern void fn2 (void); void _bar (struct A *x) { register int a asm ("esi"); register D *volatile b asm ("edi"); register int c asm ("ebx"); void *d; asm volatile ("" : "=r" (a), "=r" (b), "=r" (c) : : "memory"); if ((d = b[-2].e) != 0 && b [-2].e < d) { foo (&(((long *) d) + 1) [b[0].f], fn1 (b[-1])); x->a2 = (D *) c; x->a3 = b; fn2 (); } x->a1->e->b->baz (x->a1->e, (void *) (long) a, 1); } Wonder why RA doesn't try to force the memory address into register, that would free up one register from the 4 otherwise needed (2 for the address, 2 for DImode value being stored into the memory).
Jeff/Vlad, how hard would it be to try to split the insn into two insns instead of a spill failure (for insns using a MEM whose address uses more than one hard register) - one which forces the address into register (assuming it is supported) and the store (or load) which would use a simpler address form?
I guess it would be possible for reload to split an insn in some circumstances, particularly when there's complex addressing modes and multiple registers dying within the insn. As you know, I've been poking at range splitting and we might be able to model this case too. Right now I split based on unallocated pseudos and expect to split ranges based on pseudos getting the wrong kind of register in the future. However, there's a couple areas were we still want to split ranges and we may be able to come up with a generic way to express the other ranges we want to split:
(In reply to comment #4) > Jeff/Vlad, how hard would it be to try to split the insn into two insns instead > of a spill failure (for insns using a MEM whose address uses more than one hard > register) - one which forces the address into register (assuming it is > supported) and the store (or load) which would use a simpler address form? If it is done in reload (and imho this is the most right place to do), I think it would be hard. It needs some person with a good knowledge of the reload. It is also possible to do some splitting in other parts of compiler but it would an approximate solution (it means not all such cases will be avoided or/and it will hurt performance in general case).
I cannot reproduce this bug on the trunk or 4.6.
(In reply to comment #7) > I cannot reproduce this bug on the trunk or 4.6. I want to say this is really a dup of bug 44174.
4.4 branch is being closed, moving to 4.5.4 target.
The 4.5 branch is being closed, adjusting target milestone.
(In reply to comment #7) > I cannot reproduce this bug on the trunk or 4.6. Try with "-O2 -fno-gcse -fno-omit-frame-pointer -m32", it fails on 4.6+. Reconfirmed.
(In reply to comment #11) > Reconfirmed. BTW: Moving the complex address to the temporary (as proposed in Comment #4) would help "atomic_compare_and_swap<dwi>_doubleword" on 32bit x86 targets, too. This pattern uses cmpxchg8b_pic_memory_operand predicate to limit the number of address registers for 32bit x86 targets, in order to avoid spill failures. Please see i386/sync.md.
bug 55277 tracks the similar ICE in LRA instead of reload.
GCC 4.6.4 has been released and the branch has been closed.
Fixed in 4.8.0 by means of using LRA.