Bug 24265 - [4.1 Regression] ICE: in extract_insn, at recog.c:2084 with -O -fgcse -fmove-loop-invariants -mtune=pentiumpro
Summary: [4.1 Regression] ICE: in extract_insn, at recog.c:2084 with -O -fgcse -fmove-...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.1.0
: P2 normal
Target Milestone: 4.1.0
Assignee: Not yet assigned to anyone
URL:
Keywords: ice-on-valid-code
Depends on:
Blocks: 24408
  Show dependency treegraph
 
Reported: 2005-10-07 19:48 UTC by Ferdinand
Modified: 2005-11-11 19:39 UTC (History)
6 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work: 4.0.0
Known to fail: 4.1.0
Last reconfirmed: 2005-10-07 19:58:56


Attachments
Patch to fix the ice (953 bytes, patch)
2005-11-08 12:40 UTC, Uroš Bizjak
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ferdinand 2005-10-07 19:48:48 UTC
/tmp/gcc41/libexec/gcc/i686-pc-linux-gnu/4.1.0/cc1 -quiet -v test.c -dumpbase test.c -mtune=pentiumpro -auxbase-strip test.o -O -version -fmove-loop-invariants -fgcse -o test.o

GNU C version 4.1.0 20051007 (experimental) (i686-pc-linux-gnu)
        compiled by GNU C version 4.1.0 20051007 (experimental).
GGC heuristics: --param ggc-min-expand=99 --param ggc-min-heapsize=129306
Compiler executable checksum: a278381769db4d67bad1ec630ceb45dd
test.c: In function 'foo':
test.c:14: error: unrecognizable insn:
(insn 21 16 39 0 (set (reg:DF 64)
        (const_double:DF -858993460 [0xcccccccc] 2.00000000000000011102230246251565404236316680908e-1 [0x0.ccccccccccccdp-2])) -1 (nil)
    (nil))
test.c:14: internal compiler error: in extract_insn, at recog.c:2084

Configured with: ../gcc/configure --prefix=/tmp/gcc41 --enable-languages=c
--disable-nls --enable-checking=assert,rtlflag,misc

========================================================

void dset (double d1, double d2);

void foo ()
{
  int i;
  double m, d = 0.2;

  dset (m,d);

  for (i=1; i<=3; i++) {
    dset (m,d);
  }

}

========================================================

d needs to have the same value in both calls to dset for this ICE to occur.
Comment 1 Andrew Pinski 2005-10-07 19:58:56 UTC
Confirmed, a regression from 4.0.0.

I think this is a target bug as you had:
(set (mem:DF (plus:SI (reg/f:SI 7 sp)
                 (const_int 8 [0x8])) [0 S8 A32])
        (const_double:DF -858993460 [0xcccccccc] 2.00000000000000011102230246251565404236316680908e-1 [0x0.ccccccccccccdp-2]))

before loop-invariant but after, you have:
(insn 21 16 17 0 (set (reg:DF 64)
+        (const_double:DF -858993460 [0xcccccccc] 2.00000000000000011102230246251565404236316680908e-1 [0x0.ccccccccccccdp-2])) -1 (nil)
+    (nil))

Unless -fmove-loop-invariants is not calling emit_move_insn which might be the issue.
Comment 2 Janis Johnson 2005-10-08 00:03:24 UTC
A regression hunt using an i686-linux cross compiler identified this patch
from hagog@gcc.gnu.org:

  http://gcc.gnu.org/ml/gcc-cvs/2005-06/msg00015.html
Comment 3 Steven Bosscher 2005-10-17 18:54:09 UTC
The patch identified in comment #2 has nothing to do with this problem.  Pinski is right in comment #1, loop-invariant.c does not verify that the insns it moves/inserts are valid.  Using emit_move_insn is just one thing it should do.  Another thing is verifying that a reg-reg move exists for expressions moved out of a loop into a register before the loop.  There are a few other issues I found some time ago, but I don't recall the details.
Comment 4 Mark Mitchell 2005-10-31 06:07:27 UTC
Does the analysis in Comment #3 imply that -fmove-loop-invariants is really not ready for use by the general public?
Comment 5 Jan Hubicka 2005-11-03 19:38:22 UTC
This is ineed move-loop-invariants bug.  It assumes that destination of memory store can be changed to register without validating
that is not the case on i386 - you can write arbitrary floating point value to memory, but you can load only 0 and 1 to register by single direct move.
Comment 6 Steven Bosscher 2005-11-06 01:20:41 UTC
Oh well, I'll try and fix this...
Comment 7 Uroš Bizjak 2005-11-08 12:40:49 UTC
Created attachment 10173 [details]
Patch to fix the ice

This patch fixes the failure for me, but...
Comment 8 Uroš Bizjak 2005-11-08 12:53:41 UTC
> This patch fixes the failure for me, but...

... we actually gain nothing here.

From .loop2_done, we have following sequence, where mem->reg load is pushed out
of the loop:

(insn 21 16 39 0 (set (reg:DF 64)
        (mem/u/c/i:DF (symbol_ref/u:SI ("*.LC0") [flags 0x2]) [0 S8 A64])) -1 (nil)
    (nil))
;; End of basic block 0, registers live:
 (nil)

(note 39 21 17 NOTE_INSN_LOOP_BEG)

;; Start of basic block 1, registers live: (nil)
(code_label 17 39 18 1 2 "" [1 uses])

(note 18 17 47 1 [bb 1] NOTE_INSN_BASIC_BLOCK)

(insn 47 18 22 1 (set (mem:DF (plus:SI (reg/f:SI 7 sp)
                (const_int 8 [0x8])) [0 S8 A32])
        (reg:DF 64)) -1 (nil)
    (nil))


However, in .postreload, the insn 21 (now insn 53) is moved back _into_ the loop (why?):

(note 21 16 39 0 NOTE_INSN_DELETED)
;; End of basic block 0, registers live:
 6 [bp] 7 [sp] 16 [argp] 20 [frame] 60 64

(note 39 21 17 NOTE_INSN_LOOP_BEG)

;; Start of basic block 1, registers live: 6 [bp] 7 [sp] 59 60 64
(code_label 17 39 18 1 2 "" [1 uses])

(note 18 17 53 1 [bb 1] NOTE_INSN_BASIC_BLOCK)

(insn 53 18 47 1 (set (reg:DF 8 st)
        (mem/u/c/i:DF (symbol_ref/u:SI ("*.LC0") [flags 0x2]) [0 S8 A64])) 63 {*movdf_noin
teger} (nil)
    (nil))

(insn 47 53 54 1 (set (mem:DF (plus:SI (reg/f:SI 7 sp)
                (const_int 8 [0x8])) [0 S8 A32])
        (reg:DF 8 st)) 63 {*movdf_nointeger} (nil)
    (nil))


Proposed patch thus only fixes the damage. Otherwise, all this register moving/copying doesn't gain anything, as reload fixes something on its own.

Also, REG_EQUAL notes are lost (before and after the patch). This results in following asm:

        ...
        movl $-1717986918, 8(%esp)
        movl $1070176665, 12(%esp)
        fldl -16(%ebp)
        fstpl   (%esp)
        call dset
        movl $1, %ebx
.L2:
        fldl .LC0          <<< reload moves this insn back into the loop
        fstpl   8(%esp)
        fldl -16(%ebp)
        fstpl   (%esp)
        call dset
        incl %ebx
        cmpl $4, %ebx
        jne  .L2
        addl $36, %esp
        ...
 
Comment 9 Uroš Bizjak 2005-11-08 13:23:04 UTC
Bah... set_unique_reg_note is needed:

  /* If new move insn is invalid (i.e. move of const_double to
     387 stack register), force constant into memory.  */
  if (recog_memoized (inv->insn) == -1)
    {
      rtx src = SET_SRC (set);

      if (GET_CODE (src) == CONST_DOUBLE)
	{
	  SET_SRC (set) = validize_mem (force_const_mem (mode, src));
	  set_unique_reg_note (inv->insn, REG_EQUAL, src);
	}
    }

to produce:

        movl $1, %ebx
.L2:
        movl $-1717986918, 8(%esp)
        movl $1070176665, 12(%esp)
        fldl -16(%ebp)
        fstpl   (%esp)
        call dset
        addl $1, %ebx
        cmpl $4, %ebx
        jne  .L2
 
Comment 10 Steven Bosscher 2005-11-08 13:45:33 UTC
The patch from comment #7 is wrong.

The proper fix is already on the killloop-branch.  You could try my patch for PR 24408, which should depend on this one.
Comment 11 Steven Bosscher 2005-11-11 19:34:42 UTC
Subject: Bug 24265

Author: steven
Date: Fri Nov 11 19:34:39 2005
New Revision: 106795

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=106795
Log:
	PR 24265
	* loop-invariant.c (may_assign_reg_p): Make sure a hard register
	can be assigned to.
	(find_invariant_insn): Do the cheapest check, may_assign_reg_p,
	before check_maybe_invariant.
	(move_invariant_reg): Use gen_move_insn instead of replacing
	SET_DEST with the temporary for the invariant.
	(move_loop_invariants): If checking is enabled, do internal
	consistency checks after completing the pass.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/loop-invariant.c

Comment 12 Steven Bosscher 2005-11-11 19:39:44 UTC
Fixed on mainline.  The bug is also on the GCC 4.0 branch, but I am not going to backport the patch.