[gnu.gcc.bug] cse bug in gcc

mike@lynx.uucp (Mike Bunnell) (07/11/89)

    Version of gcc:     1.35
    Command line:       gcc -O test.c
    Tm.h:               tm-i386.h
    Md:                 i386.md
    Machine:            Lynx 386 RTW running LynxOS
    Behavoir:           cc1 aborts in cse_insn

I have found a bug in common sub-expression elimination.  It has to
do with performing common sub-expression elimination on insns of type
PARALLEL.  A common source of a PARALLEL insn is in an insn with a SET and
a CLOBBER. For example a divide instruction on a '386. The divide
instruction is changed to a reg which is good, but the problem is the
new insn (see dump below) does not match any template so recog() returns
a -1 which causes an abort ins_extract().

I have included the template for divide (which I got off the net), the
source code, and an insn dump with and without optimization.

I've temporarily fixed the problem by skipping any common sub-expression
elimination within a PARALLEL insn. I stuck a return in cse_insn if
the insn is PARALLEL.  I am interested in a better solution.  Please respond
on the net or mail to me directly.  Thanks.

#
#	Output template for divide
#
(define_insn "divsi3"
   [(set (match_operand:SI 0 "general_operand" "=&a")
	(div:SI (match_operand:SI 1 "general_operand" "0")
		(match_operand:SI 2 "general_operand" "rm")))
	(clobber (reg:SI 1))]
  ""
  "cltd\;idiv%L0 %2")
#
#	Source code
#

unsigned i, j;

func()
{
    int n;

    while (n) {
	i = n / j;
	n /= j;			/* or n %= j */
    }
}
#
#	Without optimization	
#
;; Function func

(note 1 0 2 "" NOTE_INSN_DELETED)

(note 2 1 3 "" NOTE_INSN_BLOCK_BEG)

(note 3 2 4 "" NOTE_INSN_LOOP_BEG)

(code_label 4 3 5 2)

(insn 5 4 6 (set (cc0)
       (mem:SI (plus:SI (reg:SI 6)
               (const_int -4)))) -1 (nil)
   (nil))

(jump_insn 6 5 7 (set (pc)
       (if_then_else (ne (cc0)
               (const_int 0))
           (pc)
           (label_ref 15))) -1 (nil)
   (nil))

(note 7 6 8 "" NOTE_INSN_DELETED)

(insn 8 7 9 (parallel[ 
           (set (reg:SI 10)
               (udiv:SI (mem:SI (plus:SI (reg:SI 6)
                           (const_int -4)))
                   (mem:SI (symbol_ref:SI ("j")))))
           (clobber (reg:SI 1))
       ] ) -1 (nil)
   (nil))

(insn 9 8 10 (set (mem:SI (symbol_ref:SI ("i")))
       (reg:SI 10)) -1 (nil)
   (nil))

#### This is the insn that gets changed ####
(insn 10 9 11 (parallel[ 
           (set (reg:SI 11)
               (udiv:SI (mem:SI (plus:SI (reg:SI 6)
                           (const_int -4)))
                   (mem:SI (symbol_ref:SI ("j")))))
           (clobber (reg:SI 1))
       ] ) -1 (nil)
   (nil))

(insn 11 10 12 (set (mem:SI (plus:SI (reg:SI 6)
               (const_int -4)))
       (reg:SI 11)) -1 (nil)
   (nil))

(jump_insn 12 11 13 (set (pc)
       (label_ref 4)) -1 (nil)
   (nil))

(barrier 13 12 14)

(note 14 13 15 "" NOTE_INSN_LOOP_END)

(code_label 15 14 16 3)

(note 16 15 17 "" NOTE_INSN_BLOCK_END)

(note 17 16 18 "" NOTE_INSN_FUNCTION_END)

(code_label 18 17 0 1)

#
#	This is the code after optimization
#
;; Function func

(note 1 0 2 "" NOTE_INSN_DELETED)

(note 2 1 3 "" NOTE_INSN_BLOCK_BEG)

(note 3 2 12 "" NOTE_INSN_LOOP_BEG)

(jump_insn 12 3 13 (set (pc)
       (label_ref 4)) -1 (nil)
   (nil))

(barrier 13 12 11)

(code_label 11 13 7 4)

(note 7 11 8 "" NOTE_INSN_DELETED)

(insn 8 7 9 (parallel[ 
           (set (reg:SI 11)
               (udiv:SI (reg/v:SI 10)
                   (mem:SI (symbol_ref:SI ("j")))))
           (clobber (reg:SI 1))
       ] ) -1 (nil)
   (nil))

(insn 9 8 10 (set (mem:SI (symbol_ref:SI ("i")))
       (reg:SI 11)) -1 (nil)
   (nil))

#### This is the new insn ###

(insn 10 9 4 (parallel[
           (set (reg/v:SI 10)
               (reg:SI 11))
           (clobber (reg:SI 1))
       ] ) -1 (nil)
   (nil))

(code_label 4 10 5 2)

(insn 5 4 6 (set (cc0)
       (reg/v:SI 10)) -1 (nil)
   (nil))

(jump_insn 6 5 16 (set (pc)
       (if_then_else (ne (cc0)
               (const_int 0))
           (label_ref 11)
           (pc))) -1 (nil)
   (nil))

(note 16 6 18 "" NOTE_INSN_LOOP_END)

(note 18 16 0 "" NOTE_INSN_BLOCK_END)