[gnu.gcc.bug] reload bug

csmith@convex.uucp (Chris Smith) (02/06/89)

gcc generates bad code for this program when compiled -O with 1.33:

 /usr/local/lib/gcc-cc1 /tmp/cc010022.cpp -quiet -dumpbase t.c -dl -g -O -version -o t.s
GNU C version 1.33 (convex) compiled by GNU C version 1.33.

getdec()
{
  int n = 0;
  int c = getch();
  while (c) {
    n = n * 10 + (c - '0');
    c = getch();
  }
  return n;
}

	.stabd 68,0,6			
	ld.w -4(fp),s0			<-- computing n * 10
	shf.w #2,s0
	ld.w -4(fp),s2			  (s2 is the spill register)
	add.w s2,s0
	add.w s0,s0
	st.w s0,-4(fp)			<-- it's in s0
	add.w #-48,s2			<-- suddenly shifts to s2
	st.w s2,-4(fp)
	add.w s1,s2
L5:
	st.w s2,-4(fp)

Here is an annotated lreg dump, look for <-- below

;; Function getdec

20 registers.

Register 16 used 16 times across 17 insns; dies in 2 places; crosses calls.

Register 17 used 8 times across 11 insns.

Register 18 used 4 times across 2 insns in block 1.

Register 19 used 4 times across 2 insns in block 1.

3 basic blocks.

Basic block 0: first insn 5, last 42.

Registers live at start: 8

Basic block 1: first insn 24, last 13.

Registers live at start: 8 16 17

Basic block 2: first insn 41, last 34.

Registers live at start: 16

;; Register 18 in 0.
;; Register 19 in 0.
(note 1 0 2 ("t.c") 2)

(note 2 1 3 "" -1)

(note 3 2 4 "" -2)

(note 4 3 5 ("t.c") 3)

(insn 5 4 6 (set (reg/v:SI 16)
       (const_int 0)) 15 (nil)
   (nil))

(note 6 5 7 ("t.c") 4)

(call_insn 7 6 8 (set (reg:SI 0)
       (call (mem:QI (symbol_ref:SI ("getch")))
           (const_int 0))) 130 (nil)
   (nil))

(insn 8 7 9 (set (reg/v:SI 17)
       (reg:SI 0)) 15 (nil)
   (expr_list:QI (reg:SI 0)
       (nil)))

(note 9 8 40 ("t.c") 5)

(insn 40 9 42 (set (cc0)
       (reg/v:SI 17)) 0 (insn_list 8 (nil))
   (nil))

(jump_insn 42 40 10 (set (pc)
       (if_then_else (ne (cc0)
               (const_int 0))
           (pc)
           (label_ref 41))) 120 (nil)
   (nil))

(note 10 42 24 "" -4)

(code_label 24 10 14 3)

(note 14 24 15 "" -1)

(note 15 14 16 ("t.c") 6)

(insn 16 15 17 (set (reg:SI 18)
       (ashift:SI (reg/v:SI 16)
           (const_int 2))) 95 (nil)
   (nil))

(insn 17 16 18 (set (reg:SI 19)
       (plus:SI (reg:SI 18)
           (reg/v:SI 16))) 50 (insn_list 16 (nil))
   (expr_list:QI (reg:SI 18)
       (expr_list:QI (reg/v:SI 16)
           (nil))))

(insn 18 17 19 (set (reg/v:SI 16)
       (ashift:SI (reg:SI 19)
           (const_int 1))) 95 (insn_list 17 (nil))
   (expr_list:QI (reg:SI 19)
       (nil)))			<---- at choose_reload_targets, this insn is 

			(insn:QI 18 17 19 (set (reg/v:SI 16)
			       (ashift:SI (reg:SI 0)
				   (const_int 1))) 95 (insn_list 17 (nil))
			   (expr_list:QI (reg:SI 0)
			       (nil)))

				reload_in (reg:SI 0)
				reload_out (reg:SI 16)
				reg_reloaded_contents[2] = 16
				reg_last_reload_reg[16] = (reg:SI 2)

				picks reload_reg_rtx (reg:SI 0)	
				generates output reload
				(insn 46 18 19 (set (reg/v:SI 16)
				       (reg:SI 0)) -1 (nil)
				   (nil))


(insn 19 18 20 (set (reg/v:SI 16)
       (plus:SI (reg/v:SI 16)
           (const_int -48))) 50 (insn_list 18 (nil))
   (nil))

				reload_in (reg:SI 16)
				reload_out (reg:SI 16)
				reg_reloaded_contents[2] = 16
				reg_last_reload_reg[16] = (reg:SI 2)

				picks reload_reg_rtx (reg:SI 2)	
				generates output reload
				(insn 47 19 20 (set (reg/v:SI 16)
				       (reg:SI 2)) -1 (nil)
				   (nil))

The output reload for insn 18 clobbers reg 16, which is then used in
the following insn.  I have no slightest idea what ought to be happening
here, but here is a brute-force fix:  (in choose_reload_targets)

	  /* Output the reload insn.  */
	  store_insn = emit_insn_after (gen_move_insn (old, reloadreg), insn);
+	  /* Output reload might have written into a reg
+	     whose contents we were remembering */
+ 	  forget_old_reloads (PATTERN (store_insn));
	  /* If final will look at death notes for this reg,