| Summary: | unable to find a register to spill in class ‘GENERAL_REGS’ with global registers | ||
|---|---|---|---|
| Product: | gcc | Reporter: | Dirk Mueller <mueller> |
| Component: | target | Assignee: | Not yet assigned to anyone <unassigned> |
| Status: | RESOLVED DUPLICATE | ||
| Severity: | normal | CC: | bero, gcc-bugs, greenrd, happyarch, mueller, nigelenki, pawel_sikora, pbrook, pjb, pterjan, rmathew |
| Priority: | P3 | ||
| Version: | 4.3.0 | ||
| Target Milestone: | --- | ||
| Host: | Target: | i686-suse-linux | |
| Build: | Known to work: | ||
| Known to fail: | 2.95.4 3.3.3 4.1.2 4.2.2 4.3.0 | Last reconfirmed: | 2008-02-08 11:24:13 |
I don't think we can consider this a regression, the global registers just makes an already register starved target even more register starved. We go from having 6 registers down to 3 in this case. works with -O3 (unrolled loop) on trunk, fails with 2.95, 3.3, 4.1 and 4.2 as well. the original code uses -fomit-frame-pointer -fno-gcse -O2. I can verify that -O3 fixes the issue. new testcase:
-O2 -fno-gcse -fomit-frame-pointer
=== Cut ===
__extension__ typedef unsigned long long int uint64_t;
typedef unsigned int target_ulong;
register struct CPUX86State *env asm ("ebp");
register target_ulong T0 asm ("ebx");
register target_ulong T1 asm ("esi");
register target_ulong T2 asm ("edi");
typedef union
{
uint64_t _q[2];
}
XMMReg;
typedef struct CPUX86State
{
XMMReg xmm_regs[8];
}
CPUX86State;
save_raw_fp_state (CPUX86State * env, char * ptr)
{
int i, fpus, fptag, nb_xmm_regs;
char *addr;
nb_xmm_regs = 8 << 0;
addr = ptr + 0xa0;
for (i = 0; i < nb_xmm_regs; i++)
{
env->xmm_regs[i]._q[0] = *(uint64_t *) (addr);
addr += 16;
}
}
=== Cut ===
That's still twice as many global regs as register starved i386 can realistically handle. The new testcase works for me with older releases (-O2 is enough), but 2.95.4
fails as well. The difference from 4.2 to 4.3 is that 4.2 uses two induction
variables, while 4.3 uses one. After lreg 4.2 has
(insn 21 19 22 3 (set (reg:DI 68)
(mem:DI (plus:SI (plus:SI (reg:SI 64 [ ivtmp.44 ])
(reg/v/f:SI 67 [ ptr ]))
(const_int 160 [0xa0])) [0 S8 A64])) 80 {*movdi_2} (nil)
(expr_list:REG_EQUIV (mem:DI (plus:SI (plus:SI (reg:SI 64 [ ivtmp.44 ])
(reg/v/f:SI 67 [ ptr ]))
(const_int 160 [0xa0])) [0 S8 A64])
(nil)))
(insn 22 21 23 3 (set (mem/s/j:DI (reg/f:SI 63 [ ivtmp.51 ]) [0 <variable>._q+0 S8 A8])
(reg:DI 68)) 80 {*movdi_2} (insn_list:REG_DEP_TRUE 21 (nil))
(expr_list:REG_DEAD (reg:DI 68)
(nil)))
(insn 23 22 24 3 (parallel [
(set (reg:SI 64 [ ivtmp.44 ])
(plus:SI (reg:SI 64 [ ivtmp.44 ])
(const_int 16 [0x10])))
(clobber (reg:CC 17 flags))
]) 216 {*addsi_1} (nil)
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil)))
(insn 24 23 26 3 (parallel [
(set (reg/f:SI 63 [ ivtmp.51 ])
(plus:SI (reg/f:SI 63 [ ivtmp.51 ])
(const_int 16 [0x10])))
(clobber (reg:CC 17 flags))
]) 216 {*addsi_1} (nil)
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil)))
...
while 4.3 ends up with
(insn 14 13 15 3 t.c:25 (set (reg:DI 67)
(mem:DI (plus:SI (plus:SI (reg/v/f:SI 66 [ ptr ])
(reg:SI 63 [ ivtmp.15 ]))
(const_int 160 [0xa0])) [0 S8 A64])) 88 {*movdi_2} (expr_list:REG_EQUIV (mem:DI (plus:SI (plus:SI (reg/v/f:SI 66 [ ptr ])
(reg:SI 63 [ ivtmp.15 ]))
(const_int 160 [0xa0])) [0 S8 A64])
(nil)))
(insn 15 14 16 3 t.c:25 (set (mem/s/j:DI (plus:SI (reg/v/f:SI 65 [ env ])
(reg:SI 63 [ ivtmp.15 ])) [0 <variable>._q+0 S8 A8])
(reg:DI 67)) 88 {*movdi_2} (expr_list:REG_DEAD (reg:DI 67)
(nil)))
(insn 16 15 18 3 t.c:25 (parallel [
(set (reg:SI 63 [ ivtmp.15 ])
(plus:SI (reg:SI 63 [ ivtmp.15 ])
(const_int 16 [0x10])))
(clobber (reg:CC 17 flags))
]) 249 {*addsi_1} (expr_list:REG_UNUSED (reg:CC 17 flags)
(nil)))
Or before expand for 4.2:
<bb 2>:
ivtmp.51 = (unsigned int) &env->xmm_regs[0]._q[0];
ivtmp.44 = 0;
<L0>:;
MEM[index: ivtmp.51] = MEM[base: ptr, index: ivtmp.44, offset: 160];
ivtmp.44 = ivtmp.44 + 16;
ivtmp.51 = ivtmp.51 + 16;
if (ivtmp.44 != 128) goto <L0>; else goto <L2>;
<L2>:;
return;
while 4.3 starts with:
<bb 2>:
ivtmp.15 = 0;
<bb 3>:
MEM[base: env, index: ivtmp.15] = MEM[base: ptr, index: ivtmp.15, offset: 160];
ivtmp.15 = ivtmp.15 + 16;
if (ivtmp.15 != 128)
goto <bb 3>;
else
goto <bb 4>;
<bb 4>:
return;
Here is a "GENERAL_REGS" error for the Trunk. # gcc -v Using built-in specs. Target: i386-pc-solaris2.11 Configured with: ../gcc_trunk/configure --enable-languages=ada,c,c++,fortran,java,objc,obj-c++ --enable-shared --disable-static --enable-decimal-float --with-long-double-128 --with-included-gettext --enable-stage1-checking --enable-checking=release --with-tune=k8 --with-cpu=k8 --with-arch=k8 --with-gnu-as --with-as=/usr/local/bin/as --with-gnu-ld --with-ld=/usr/local/bin/ld Thread model: posix gcc version 4.4.0 20090131 (experimental) [trunk revision 143817] (GCC) wget -c ftp://ftp.gnu.org/gnu/gforth/gforth-0.7.0.tar.gz gunzip -d gforth-0.7.0.tar.gz gtar -xf gforth-0.7.0.tar export set CC="gcc -ffloat-store -msse3 -mssse3 -m3dnow -msse4.1 -mfpmath=sse,387" export set CXX="g++ -ffloat-store -msse3 -mssse3 -m3dnow -msse4.1 -mfpmath=sse,387" ./configure gmake ... gmake[3]: Entering directory `/usr/share/src/gforth-0.7.0/engine' gcc -ffloat-store -msse3 -mssse3 -m3dnow -msse4.1 -mfpmath=sse,387 -I./../arch/386 -I. -Wall -O2 -fomit-frame-pointer -fforce-addr -DHAVE_CONFIG_H -DFORCE_LL -DFORCE_REG -DDEFAULTPATH='".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.0:/usr/local/share/gforth/0.7.0"' -fexceptions -fno-gcse -fno-strict-aliasing -fno-crossjumping -fno-reorder-blocks -falign-labels=1 -falign-loops=1 -falign-jumps=1 -fno-defer-pop -fcaller-saves -fno-inline -o engine-fast-ll-reg.o -c ./engine.c ./engine.c: In function 'gforth_engine': ./engine.c:460: error: unable to find a register to spill in class 'GENERAL_REGS' ./engine.c:460: error: this is the insn: (insn:HI 2564 2563 2565 367 prim-fast.i:4090 (set (reg:DI 2196) (mem/s/j/c:DI (plus:SI (reg/f:SI 20 frame) (const_int -180 [0xffffffffffffff4c])) [0 _d.d+0 S8 A32])) 88 {*movdi_2} (nil)) ./engine.c:460: confused by earlier errors, bailing out gmake[3]: *** [engine-fast-ll-reg.o] Error 1 gmake[3]: Leaving directory `/usr/share/src/gforth-0.7.0/engine' ... Rob Sometimes you can skirt around the "GENERAL_REGS" error with other options.
When I use "-O0", "-O1", "-O2", "-O3", "-Os" I get different results.
Using "-O0" produces no screen output _or_ compiled file (thus it 'looks'
as though it compiled OK).
# gcc -ffloat-store -msse3 -mssse3 -m3dnow -msse4.1 -mfpmath=sse,387 -I./../arch/386 -I. -Wall -O0 -fomit-frame-pointer -fforce-addr -DHAVE_CONFIG_H -DFORCE_LL -DFORCE_REG -DDEFAULTPATH='".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.0:/usr/local/share/gforth/0.7.0"' -fexceptions -fno-gcse -fno-strict-aliasing -fno-crossjumping -fno-reorder-blocks -falign-labels=1 -falign-loops=1 -falign-jumps=1 -fno-defer-pop -fcaller-saves -fno-inline -o engine-fast-ll-reg.o -c ./engine.c
#
# ls -lrtA | tail -1
-rwxr-xr-x 1 root root 126938 Jan 31 12:20 gforth-fast-ll
#
See that "-O0" gives no screen output and no compiled file output.
# gcc -ffloat-store -msse3 -mssse3 -m3dnow -msse4.1 -mfpmath=sse,387 -I./../arch/386 -I. -Wall -O1 -fomit-frame-pointer -fforce-addr -DHAVE_CONFIG_H -DFORCE_LL -DFORCE_REG -DDEFAULTPATH='".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.0:/usr/local/share/gforth/0.7.0"' -fexceptions -fno-gcse -fno-strict-aliasing -fno-crossjumping -fno-reorder-blocks -falign-labels=1 -falign-loops=1 -falign-jumps=1 -fno-defer-pop -fcaller-saves -fno-inline -o engine-fast-ll-reg.o -c ./engine.c
./engine.c: In function 'gforth_engine':
./engine.c:460: error: unable to find a register to spill in class 'DIREG'
./engine.c:460: error: this is the insn:
(insn 5800 13080 5801 850 prim:1699 (parallel [
(set (reg:SI 2 cx [2364])
(unspec:SI [
(mem:BLK (reg/f:SI 1 dx [orig:2366 D.8048 ] [2366]) [0 A8])
(reg:QI 0 ax [2368])
(const_int 1 [0x1])
(reg:SI 2 cx [2367])
] 30))
(clobber (reg/f:SI 1 dx [orig:2366 D.8048 ] [2366]))
(clobber (reg:CC 17 flags))
]) 864 {*strlenqi_1} (expr_list:REG_DEAD (reg:QI 0 ax [2368])
(expr_list:REG_DEAD (reg:SI 2 cx [2367])
(expr_list:REG_DEAD (reg/f:SI 1 dx [orig:2366 D.8048 ] [2366])
(expr_list:REG_UNUSED (reg/f:SI 1 dx [orig:2366 D.8048 ] [2366])
(expr_list:REG_UNUSED (reg:CC 17 flags)
(nil)))))))
./engine.c:460: confused by earlier errors, bailing out
#
# gcc -ffloat-store -msse3 -mssse3 -m3dnow -msse4.1 -mfpmath=sse,387 -I./../arch/386 -I. -Wall -O3 -fomit-frame-pointer -fforce-addr -DHAVE_CONFIG_H -DFORCE_LL -DFORCE_REG -DDEFAULTPATH='".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.0:/usr/local/share/gforth/0.7.0"' -fexceptions -fno-gcse -fno-strict-aliasing -fno-crossjumping -fno-reorder-blocks -falign-labels=1 -falign-loops=1 -falign-jumps=1 -fno-defer-pop -fcaller-saves -fno-inline -o engine-fast-ll-reg.o -c ./engine.c
./engine.c: In function 'gforth_engine':
./engine.c:460: error: unable to find a register to spill in class 'GENERAL_REGS'
./engine.c:460: error: this is the insn:
(insn:HI 2564 2563 2565 367 prim-fast.i:4090 (set (reg:DI 2196)
(mem/s/j/c:DI (plus:SI (reg/f:SI 20 frame)
(const_int -180 [0xffffffffffffff4c])) [0 _d.d+0 S8 A32])) 88 {*movdi_2} (nil))
./engine.c:460: confused by earlier errors, bailing out
#
# gcc -ffloat-store -msse3 -mssse3 -m3dnow -msse4.1 -mfpmath=sse,387 -I./../arch/386 -I. -Wall -Os -fomit-frame-pointer -fforce-addr -DHAVE_CONFIG_H -DFORCE_LL -DFORCE_REG -DDEFAULTPATH='".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.0:/usr/local/share/gforth/0.7.0"' -fexceptions -fno-gcse -fno-strict-aliasing -fno-crossjumping -fno-reorder-blocks -falign-labels=1 -falign-loops=1 -falign-jumps=1 -fno-defer-pop -fcaller-saves -fno-inline -o engine-fast-ll-reg.o -c ./engine.c
./engine.c: In function 'gforth_engine':
./engine.c:460: error: unable to find a register to spill in class 'DIREG'
./engine.c:460: error: this is the insn:
(insn:HI 1623 1621 1624 230 prim:662 (parallel [
(set (reg:SI 2 cx [orig:2148 u ] [2148])
(const_int 0 [0x0]))
(set (reg/f:SI 0 ax [orig:2146 c_addr ] [2146])
(plus:SI (reg/v/f:SI 1943 [ c_addr ])
(reg/v:SI 2 cx [orig:1942 u ] [1942])))
(set (mem:BLK (reg/v/f:SI 1943 [ c_addr ]) [0 A8])
(const_int 0 [0x0]))
(use (subreg:QI (reg:SI 1 dx [orig:1278 spTOS.757 ] [1278]) 0))
(use (reg/v:SI 2 cx [orig:1942 u ] [1942]))
]) 858 {*rep_stosqi} (expr_list:REG_DEAD (reg/v/f:SI 1943 [ c_addr ])
(expr_list:REG_DEAD (reg/v:SI 2 cx [orig:1942 u ] [1942])
(expr_list:REG_DEAD (reg:SI 1 dx [orig:1278 spTOS.757 ] [1278])
(expr_list:REG_UNUSED (reg:SI 2 cx [orig:2148 u ] [2148])
(expr_list:REG_UNUSED (reg/f:SI 0 ax [orig:2146 c_addr ] [2146])
(nil)))))))
./engine.c:460: confused by earlier errors, bailing out
#
If I compile "-O1" and remove the "-fomit-frame-pointer" option then the
output (error message) is the same as: "-O1 -fomit-frame-pointer".
If I compile "-Os" and remove the "-fomit-frame-pointer" option then the
output (error message) is the same as: "-Os -fomit-frame-pointer".
If I compile "-O0", "-O2" or "-O3" and remove the "-fomit-frame-pointer"
option then the output (error message) is the same as if I had used:
"-O2 -fomit-frame-pointer".
Even stripping the gcc command to the bare minimum can not skirt
the lack of enough registers to compile this code:
# gcc -I./../arch/386 -I. -Wall -DHAVE_CONFIG_H -DFORCE_LL -DFORCE_REG -DDEFAULTPATH='".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.0:/usr/local/share/gforth/0.7.0"' -o engine-fast-ll-reg.o -c ./engine.c
./engine.c: In function 'gforth_engine':
./engine.c:460: error: unable to find a register to spill in class 'GENERAL_REGS'
./engine.c:460: error: this is the insn:
(insn 3333 3332 3334 360 prim-fast.i:3818 (set (reg:DI 4692)
(mem/s/j/c:DI (plus:SI (reg/f:SI 20 frame)
(const_int -4844 [0xffffffffffffed14])) [0 _d.d+0 S8 A32])) 88 {*movdi_2} (nil))
./engine.c:460: confused by earlier errors, bailing out
Thanks,
Rob
It can be compiled with ONE earlier version of gcc but not another - so this is a regression.
Works on 4.0.2:
# /opt/csw/gcc4/bin/gcc -v
Reading specs from /opt/csw/gcc4/lib/gcc/i386-pc-solaris2.8/4.0.2/specs
Target: i386-pc-solaris2.8
Configured with: ../sources/gcc-4.0.2/configure --prefix=/opt/csw/gcc4 --with-local-prefix=/opt/csw --with-gnu-as --with-as=/opt/csw/bin/gas --without-gnu-ld --with-ld=/usr/ccs/bin/ld --enable-threads=posix --enable-shared --enable-multilib --enable-nls --with-included-gettext --with-libiconv-prefix=/opt/csw --with-x --enable-java-awt=xlib --with-system-zlib --enable-languages=c,c++,f95,java,objc,ada
Thread model: posix
gcc version 4.0.2
# /opt/csw/gcc4/bin/gcc -I./../arch/386 -I. -Wall -DHAVE_CONFIG_H -DFORCE_LL -DFORCE_REG -DDEFAULTPATH='".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.0:/usr/local/share/gforth/0.7.0"' -O3 -fno-gcse -fomit-frame-pointer -o engine-fast-ll-reg.o -c ./engine.c
# ls -lrtA | tail -1
-rw-r--r-- 1 root root 45848 Jan 31 16:44 engine-fast-ll-reg.o
Broken on 3.4.5:
# /opt/csw/gcc3/bin/gcc -v
Reading specs from /opt/csw/gcc3/lib/gcc/i386-pc-solaris2.8/3.4.5/specs
Configured with: ../sources/gcc-3.4.5/configure --prefix=/opt/csw/gcc3 --with-local-prefix=/opt/csw --with-gnu-as --with-as=/opt/csw/bin/gas --without-gnu-ld --with-ld=/usr/ccs/bin/ld --enable-threads=posix --enable-shared --enable-multilib --enable-nls --with-included-gettext --with-libiconv-prefix=/opt/csw --with-x --enable-java-awt=xlib --enable-languages=all
Thread model: posix
gcc version 3.4.5
# /opt/csw/gcc3/bin/gcc -I./../arch/386 -I. -Wall -DHAVE_CONFIG_H -DFORCE_LL -DFORCE_REG -DDEFAULTPATH='".:/usr/local/lib/gforth/site-forth:/usr/local/share/gforth/site-forth:/usr/local/lib/gforth/0.7.0:/usr/local/share/gforth/0.7.0"' -O3 -fno-gcse -fomit-frame-pointer -o engine-fast-ll-reg.o -c ./engine.c
./engine.c: In function `gforth_engine':
./engine.c:460: error: unable to find a register to spill in class `DIREG'
./engine.c:460: error: this is the insn:
(insn:HI 10882 25685 10883 883 (parallel [
(set (reg:SI 2 cx [969])
(unspec:SI [
(mem:BLK (reg/v/f:SI 1 dx [orig:964 c_addr2 ] [964]) [0 A8])
(reg:QI 0 ax [973])
(const_int 1 [0x1])
(reg:SI 2 cx [972])
] 20))
(use (reg:SI 19 dirflag))
(clobber (reg/f:SI 1917 [ c_addr2 ]))
(clobber (reg:CC 17 flags))
]) 456 {*strlenqi_1} (insn_list 10878 (insn_list 10880 (insn_list 10881 (nil))))
(expr_list:REG_DEAD (reg:SI 19 dirflag)
(expr_list:REG_DEAD (reg:SI 2 cx [972])
(expr_list:REG_DEAD (reg:QI 0 ax [973])
(expr_list:REG_UNUSED (reg:CC 17 flags)
(expr_list:REG_UNUSED (reg/f:SI 1917 [ c_addr2 ])
(nil)))))))
./engine.c:460: confused by earlier errors, bailing out
Rob
*** This bug has been marked as a duplicate of 16185 *** |
gcc -v -O2 -c test.c === Cut === extension__ typedef unsigned long long int uint64_t; typedef unsigned target_ulong; register target_ulong T0 asm ("ebx"); register target_ulong T1 asm ("esi"); register target_ulong T2 asm ("edi"); typedef struct CPUX86State { uint64_t xmm_regs[8]; } CPUX86State; save_raw_fp_state (CPUX86State * env) { int i; char *addr; for (i = 0; i < 8; i++) env->xmm_regs[i] = *(uint64_t *) (addr); } === Cut === GNU C (SUSE Linux) version 4.3.0 20080131 (experimental) [trunk revision 131976] (i586-suse-linux) compiled by GNU C version 4.3.0 20080131 (experimental) [trunk revision 131976], GMP version 4.2.2, MPFR version 2.3.1. GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: 86307befc2a0b2e7a5d9beb62be4b74e test.c: In function ‘save_raw_fp_state’: test.c:18: error: unable to find a register to spill in class ‘GENERAL_REGS’ test.c:18: error: this is the insn: (insn:HI 14 13 15 3 test.c:17 (set (mem/s:DI (plus:SI (mult:SI (reg/v:SI 64 [ i ]) (const_int 8 [0x8])) (reg/v/f:SI 66 [ env ])) [2 <variable>.xmm_regs S8 A8]) (reg:DI 67)) 63 {*movdi_2} (expr_list:REG_DEAD (reg:DI 67) (nil))) test.c:18: confused by earlier errors, bailing out