Bug 38900 - ICE: unable to find a register to spill
Summary: ICE: unable to find a register to spill
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.4.0
: P3 normal
Target Milestone: ---
Assignee: Kai Tietz
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-01-17 23:17 UTC by Dmitry Gorbachev
Modified: 2009-07-08 17:03 UTC (History)
5 users (show)

See Also:
Host:
Target: i386-pc-mingw32
Build:
Known to work:
Known to fail: 4.3.2 4.3.3 4.4.0
Last reconfirmed: 2009-07-06 12:38:34


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dmitry Gorbachev 2009-01-17 23:17:12 UTC
gcc -S -O1 -foptimize-sibling-calls bug.c

bug.c: In function 'f':
bug.c:9: error: unable to find a register to spill in class 'CREG'
bug.c:9: error: this is the insn:
(call_insn/j 11 9 12 2 bug.c:8 (call (mem:QI (reg/f:SI 3 bx [59]) [0 S1 A8])
        (const_int 0 [0x0])) 468 {*sibcall_1} (expr_list:REG_DEAD (reg/f:SI 3 bx [59])
        (expr_list:REG_DEAD (reg:SI 2 cx)
            (nil)))
    (expr_list:REG_DEP_TRUE (use (reg:SI 2 cx))
        (nil)))
bug.c:9: internal compiler error: in spill_failure, at reload1.c:2093
Comment 1 Dmitry Gorbachev 2009-01-17 23:19:41 UTC
bug.c:

void __attribute__((dllimport,fastcall)) h(int);

void f(int i)
{
    static void (__attribute__((fastcall)) *g)(int) = h;

    g(i);
    g(i);
}
Comment 2 Dmitry Gorbachev 2009-01-17 23:20:28 UTC
ok.c:

void __attribute__((dllimport,fastcall)) h(int);

void f(int i)
{
    static void (__attribute__((fastcall)) *g)(int);

    g = h;

    g(i);
    g(i);
}
Comment 3 Francois-Xavier Coudert 2009-05-13 20:04:31 UTC
Simpler testcase, confirmed on native i386-pc-mingw32 (trunk, SVN rev. 147441):

$ cat a.c
void __attribute__((dllimport,fastcall)) h(int);

void f()
{
  h(2);
  h(1);
}

$ gcc -S -O1 a.c -foptimize-sibling-calls
a.c: In function 'f':
a.c:7: error: unable to find a register to spill in class 'CREG'
a.c:7: error: this is the insn:
(call_insn/j 10 8 11 2 a.c:6 (call (mem:QI (reg/f:SI 3 bx [58]) [0 S1 A8])
        (const_int 0 [0x0])) 468 {*sibcall_1} (expr_list:REG_DEAD (reg/f:SI 3 bx [58])
        (expr_list:REG_DEAD (reg:SI 2 cx)
            (nil)))
    (expr_list:REG_DEP_TRUE (use (reg:SI 2 cx))
        (nil)))
a.c:7: internal compiler error: in spill_failure, at reload1.c:2094
Comment 4 Ivan Maidanski 2009-06-25 10:31:24 UTC
Bug confirmed in mingw-w64 gcc v4.5.0 (32-bit target).
Bug also observed in MinGW gcc v3.4.5 and v4.2.1
Comment 5 Dmitry Gorbachev 2009-06-26 14:57:38 UTC
Perhaps there are two bugs, not one, as my more elaborate testcases show. Though they are seemingly equivalent, one triggers the bug, while another don't.
Comment 6 Kai Tietz 2009-07-06 10:33:12 UTC
(In reply to comment #5)
> Perhaps there are two bugs, not one, as my more elaborate testcases show.
> Though they are seemingly equivalent, one triggers the bug, while another
> don't.
> 

Ok, is the same issue occurring, when the attributes are set separately in different __attribute__ statements?

Cheers,
Kai 
Comment 7 Kai Tietz 2009-07-06 11:54:21 UTC
Ok, I think I found the issue. The following patch solved the ICE here. The ebx register wasn't allowed for sibcall_1 in i386.md, but for fastcall it can be used for sibcalling.

I have to do a regression test for it, but it seems to work well.

Index: config/i386/i386.md
===================================================================
--- config/i386/i386.md (revision 149152)
+++ config/i386/i386.md (working copy)
@@ -15536,7 +15536,7 @@
   [(set_attr "type" "call")])

 (define_insn "*sibcall_1"
-  [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,c,d,a"))
+  [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,c,d,a,b"))
         (match_operand 1 "" ""))]
   "SIBLING_CALL_P (insn) && !TARGET_64BIT"
 {
@@ -22183,7 +22183,7 @@

 (define_insn "*sibcall_value_1"
   [(set (match_operand 0 "" "")
-       (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,c,d,a"))
+       (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,c,d,a,b"))
              (match_operand:SI 2 "" "")))]
   "SIBLING_CALL_P (insn) && !TARGET_64BIT"
 {
Comment 8 Eric Botcazou 2009-07-06 12:49:48 UTC
 > Index: config/i386/i386.md
> ===================================================================
> --- config/i386/i386.md (revision 149152)
> +++ config/i386/i386.md (working copy)
> @@ -15536,7 +15536,7 @@
>    [(set_attr "type" "call")])
> 
>  (define_insn "*sibcall_1"
> -  [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,c,d,a"))
> +  [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,c,d,a,b"))
>          (match_operand 1 "" ""))]
>    "SIBLING_CALL_P (insn) && !TARGET_64BIT"
>  {
> @@ -22183,7 +22183,7 @@
> 
>  (define_insn "*sibcall_value_1"
>    [(set (match_operand 0 "" "")
> -       (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,c,d,a"))
> +       (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,c,d,a,b"))
>               (match_operand:SI 2 "" "")))]
>    "SIBLING_CALL_P (insn) && !TARGET_64BIT"
>  {

This cannot be correct in the general case as %ebx is call-saved, you cannot clobber it through a function call.  A solution could be to disparage the 'c' alternative, but a x86 maintainer will know better.
Comment 9 Kai Tietz 2009-07-06 13:17:34 UTC
(In reply to comment #8)
> This cannot be correct in the general case as %ebx is call-saved, you cannot
> clobber it through a function call.  A solution could be to disparage the 'c'
> alternative, but a x86 maintainer will know better.
> 

Well, why? For save or called saved registers the functions epilogue/prologue takes care. The reason why gcc tries to choose ebx for call address register here, is exactly this reason, as it can be sure that after the sibcall, the register is still valid.

Cheers,
Kai
Comment 10 Eric Botcazou 2009-07-06 15:31:22 UTC
> Well, why? For save or called saved registers the functions epilogue/prologue
> takes care. The reason why gcc tries to choose ebx for call address register
> here, is exactly this reason, as it can be sure that after the sibcall, the
> register is still valid.

What's the assembly code generated with your patch?
Comment 11 Kai Tietz 2009-07-06 16:12:36 UTC
(In reply to comment #10)
> > Well, why? For save or called saved registers the functions epilogue/prologue
> > takes care. The reason why gcc tries to choose ebx for call address register
> > here, is exactly this reason, as it can be sure that after the sibcall, the
> > register is still valid.
> 
> What's the assembly code generated with your patch?
> 

Compiling the test case with -O2

        .file   "c_impfast.c"
        .text
        .p2align 4,,15
.globl _f
        .def    _f;     .scl    2;      .type   32;     .endef
_f:
        pushl   %ebp
        movl    $2, %ecx
        movl    %esp, %ebp
        pushl   %ebx
        subl    $4, %esp
        movl    __imp_@h@4, %ebx
        call    *%ebx
        addl    $4, %esp
        movl    $1, %ecx
        popl    %ebx
        popl    %ebp
        jmp     *%ebx
Comment 12 Kai Tietz 2009-07-06 16:13:42 UTC
And this is pretty wrong :}
Comment 13 Kai Tietz 2009-07-06 16:41:33 UTC
By simply re-ording of arguments fos sibcall_1 and sibcall_value_1, so that c is last element, produced code is ok and no ICE I've seen. The ebx issue is pretty wrong here.

Index: gcc/gcc/config/i386/i386.md
===================================================================
--- gcc.orig/gcc/config/i386/i386.md    2009-07-06 18:14:36.155670000 +0200
+++ gcc/gcc/config/i386/i386.md 2009-07-06 18:36:54.453670100 +0200
@@ -15536,7 +15536,7 @@
   [(set_attr "type" "call")])

 (define_insn "*sibcall_1"
-  [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,c,d,a"))
+  [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,d,a,c"))
         (match_operand 1 "" ""))]
   "SIBLING_CALL_P (insn) && !TARGET_64BIT"
 {
@@ -22183,7 +22183,7 @@

 (define_insn "*sibcall_value_1"
   [(set (match_operand 0 "" "")
-       (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,c,d,a"))
+       (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,d,a,c"))
              (match_operand:SI 2 "" "")))]
   "SIBLING_CALL_P (insn) && !TARGET_64BIT"
 {
Comment 14 Eric Botcazou 2009-07-06 16:43:50 UTC
> By simply re-ording of arguments fos sibcall_1 and sibcall_value_1, so that c
> is last element, produced code is ok and no ICE I've seen.

Disparaging it ("s,!c,d,a") would be even more robust I think.
Comment 15 Kai Tietz 2009-07-06 17:02:02 UTC
(In reply to comment #14)
> > By simply re-ording of arguments fos sibcall_1 and sibcall_value_1, so that c
> > is last element, produced code is ok and no ICE I've seen.
> 
> Disparaging it ("s,!c,d,a") would be even more robust I think.
> 

yeah, this works, too. But the d needs the !, too. As when I alter my testcase by giving the dllimport'ed fastcall a second argument, it ICEs again.

$ /usr/local/bin/i686-pc-mingw32-gcc.exe -o t.s -S c_impfast2.c -O2
c_impfast2.c: In function 'f':
c_impfast2.c:7:1: error: unable to find a register to spill in class 'DREG'
c_impfast2.c:7:1: error: this is the insn:
(call_insn/j 12 10 13 2 c_impfast2.c:6 (call (mem:QI (reg/f:SI 3 bx [58]) [0 S1 A8])
        (const_int 0 [0x0])) 462 {*sibcall_1} (expr_list:REG_DEAD (reg/f:SI 3 bx [58])
        (expr_list:REG_DEAD (reg:SI 2 cx)
            (expr_list:REG_DEAD (reg:SI 1 dx)
                (nil))))
    (expr_list:REG_DEP_TRUE (use (reg:SI 2 cx))
        (expr_list:REG_DEP_TRUE (use (reg:SI 1 dx))
            (nil))))
c_impfast2.c:7:1: internal compiler error: in spill_failure, at reload1.c:2094
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.

So with both c and d changed to !c and !d for sibcall_1 and sibcall_value_1 it translates without ICE to:

        .file   "c_impfast2.c"
        .text
        .p2align 4,,15
.globl _f
        .def    _f;     .scl    2;      .type   32;     .endef
_f:
        pushl   %ebp
        movl    $1, %edx
        movl    %esp, %ebp
        movl    $2, %ecx
        pushl   %ebx
        subl    $4, %esp
        movl    __imp_@h@8, %ebx
        call    *%ebx
        addl    $4, %esp
        movl    $2, %edx
        movl    $1, %ecx
        movl    %ebx, %eax
        popl    %ebx
        popl    %ebp
        jmp     *%eax

New patch for i386.md (and you are right the !c,!d is more robust here) is:

Index: gcc/gcc/config/i386/i386.md
===================================================================
--- gcc.orig/gcc/config/i386/i386.md    2009-07-06 18:14:36.155670000 +0200
+++ gcc/gcc/config/i386/i386.md 2009-07-06 18:53:10.459670100 +0200
@@ -15536,7 +15536,7 @@
   [(set_attr "type" "call")])

 (define_insn "*sibcall_1"
-  [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,c,d,a"))
+  [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,!c,!d,a"))
         (match_operand 1 "" ""))]
   "SIBLING_CALL_P (insn) && !TARGET_64BIT"
 {
@@ -22183,7 +22183,7 @@

 (define_insn "*sibcall_value_1"
   [(set (match_operand 0 "" "")
-       (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,c,d,a"))
+       (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,!c,!d,a"))
              (match_operand:SI 2 "" "")))]
   "SIBLING_CALL_P (insn) && !TARGET_64BIT"
 {
Comment 16 Richard Henderson 2009-07-08 16:41:40 UTC
Subject: Bug 38900

Author: rth
Date: Wed Jul  8 16:41:23 2009
New Revision: 149373

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=149373
Log:
	PR target/38900
	* config/i386/i386.h (CONDITIONAL_REGISTER_USAGE): Move to i386.c.
	(enum reg_class): Add CLOBBERED_REGS.
	(REG_CLASS_NAMES, REG_CLASS_CONTENTS): Likewise.
	* config/i386/i386.c (ix86_conditional_register_usage): Moved
	from CONDITIONAL_REGISTER_USAGE; build CLOBBERED_REGS for 64-bit.
	(ix86_function_ok_for_sibcall): Tidy.  Disallow MS->SYSV sibcalls.
	(ix86_expand_call): Use sibcall_insn_operand when needed.  Don't
	force 64-bit sibcalls into R11.
	* config/i386/constraints.md (U): New constraint.
	* config/i386/i386.md (sibcall_1, sibcall_value_1): Use it.
	(sibcall_1_rex64, sibcall_value_1_rex64): Likewise.
	(sibcall_1_rex64_v, sibcall_value_1_rex64_v): Remove.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/i386/constraints.md
    trunk/gcc/config/i386/i386-protos.h
    trunk/gcc/config/i386/i386.c
    trunk/gcc/config/i386/i386.h
    trunk/gcc/config/i386/i386.md

Comment 17 Richard Henderson 2009-07-08 16:59:28 UTC
Subject: Bug 38900

Author: rth
Date: Wed Jul  8 16:59:15 2009
New Revision: 149374

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=149374
Log:
	PR target/38900
	* config/i386/i386.h (CONDITIONAL_REGISTER_USAGE): Move to i386.c.
	(enum reg_class): Add CLOBBERED_REGS.
	(REG_CLASS_NAMES, REG_CLASS_CONTENTS): Likewise.
	* config/i386/i386.c (ix86_conditional_register_usage): Moved
	from CONDITIONAL_REGISTER_USAGE; build CLOBBERED_REGS for 64-bit.
	(ix86_function_ok_for_sibcall): Tidy.  Disallow MS->SYSV sibcalls.
	(ix86_expand_call): Use sibcall_insn_operand when needed.  Don't
	force 64-bit sibcalls into R11.
	* config/i386/constraints.md (U): New constraint.
	* config/i386/i386.md (sibcall_1, sibcall_value_1): Use it.
	(sibcall_1_rex64, sibcall_value_1_rex64): Likewise.
	(sibcall_1_rex64_v, sibcall_value_1_rex64_v): Remove.

Modified:
    branches/gcc-4_4-branch/gcc/ChangeLog
    branches/gcc-4_4-branch/gcc/config/i386/constraints.md
    branches/gcc-4_4-branch/gcc/config/i386/i386-protos.h
    branches/gcc-4_4-branch/gcc/config/i386/i386.c
    branches/gcc-4_4-branch/gcc/config/i386/i386.h
    branches/gcc-4_4-branch/gcc/config/i386/i386.md

Comment 18 Richard Henderson 2009-07-08 17:03:02 UTC
Fixed.