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
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 ***