Bug 35135 - unable to find a register to spill in class ‘GENERAL_REGS’ with global registers
Summary: unable to find a register to spill in class ‘GENERAL_REGS’ with global registers
Status: RESOLVED DUPLICATE of bug 16185
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-02-08 00:28 UTC by Dirk Mueller
Modified: 2009-03-12 17:48 UTC (History)
11 users (show)

See Also:
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


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dirk Mueller 2008-02-08 00:28:38 UTC
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
Comment 1 Andrew Pinski 2008-02-08 00:32:46 UTC
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.
Comment 2 Richard Biener 2008-02-08 11:24:13 UTC
works with -O3 (unrolled loop) on trunk, fails with 2.95, 3.3, 4.1 and 4.2 as well.
Comment 3 Dirk Mueller 2008-02-12 16:31:49 UTC
the original code uses -fomit-frame-pointer -fno-gcse -O2. I can verify that -O3 fixes the issue. 
Comment 4 Dirk Mueller 2008-02-12 17:18:56 UTC
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 ===
Comment 5 Jakub Jelinek 2008-02-12 17:27:57 UTC
That's still twice as many global regs as register starved i386 can realistically handle.
Comment 6 Richard Biener 2008-02-12 18:48:00 UTC
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;
Comment 7 Rob 2009-01-31 20:25:49 UTC
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
Comment 8 Rob 2009-01-31 21:01:21 UTC
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
Comment 9 Rob 2009-02-01 00:49:59 UTC
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
Comment 10 Uroš Bizjak 2009-03-12 17:48:40 UTC

*** This bug has been marked as a duplicate of 16185 ***