[gnu.gcc.bug] GCC 1.28 can abort in reload_as_needed

cudcv@warwick.ac.uk (Rob McMahon) (09/25/88)

GCC 1.28, Gould PN6030

I hope I can explain this coherently, I'm sorry I can't give a test program.
During the first scan in reload, find_reloads can find a required value via
find_equiv_reg which is no longer available during the second scan in
reload_as_needed, due to reloads having taken place (optional in the case that
I hit).  If this means a block which didn't appear to need reloads first time
round now needs a reload, this can mean there is no spill reg available for
it, and the compiler aborts at the new test in reload_as_needed marked by the
comment:
	      /* If this block has not had spilling done,
		 ...
		 If we have any non-optionals that need a spill reg, abort.  */

The change I've made to get me going is to make find_equiv_reg ignore
instructions with reloads pending, around line 2499 in reload.c:

      p = PREV_INSN (p);
      if (p == 0 || GET_CODE (p) == CODE_LABEL)
	return 0;
=>    if (GET_CODE (p) == INSN
	  /* If we don't want spill regs (true for all calls in this file) */
	  && (! (reload_reg_p != 0 && reload_reg_p != (short *)1)

by changing the marked line to be

      if (GET_CODE (p) == INSN && GET_MODE (p) == VOIDmode

but I think this may be over conservative.

Here are some commented excerpts from the .lreg file to show what I mean.
FIRST_PSEUDO_REGISTER is 19.

| Register 21 used 7 times across 50 insns; dies in 4 places; crosses calls;
| 	pointer.
| Register 23 used 11 times across 118 insns; dies in 4 places; crosses calls;
| 	pref INDEX_REGS; pointer.
| Register 30 used 2 times across 2 insns in block 1; GP_REGS or none.
| 
| Basic block 0: first insn 3, last 24.
| Registers live at start: 10 16
| 
| Basic block 1: first insn 25, last 29.
| Registers live at start: 10 16 19 20 21 23 24 25
| 
| ;; Register 30 in 0.

reload then assigns:

reg_renumber[21] = 7
reg_renumber[23] = -1
reg_renumber[30] = 0

| (insn 5 4 6 (set (reg/v:SI 23)
|        (mem:SI (plus:SI (reg:SI 18) (const_int 8)))) 40 (nil)
|    (expr_list (mem:SI (plus:SI (reg:SI 18) (const_int 8))) (nil)))

insn 5 gets output reload for reg 23

| (insn 8 7 9 (set (reg/v:SI 21)
|        (reg/v:SI 23)) 40 (insn_list 5 (nil))
|    (nil))

insn 8 gets optional input reload for reg 23
basic block 0 needs reloads.

| (insn 27 25 28 (set (reg:SI 30)
|        (zero_extend:SI (mem/s:QI (plus:SI (reg/v:SI 23)
|                    (const_int 12))))) 55 (insn_list 25 (nil))
|    (expr_list:TI (zero_extend:SI (reg:QI 29)) (nil)))

insn 27 gets reload of reg 23 but finds reg 7 (was pseudo-reg 21) is
equivalent due to insn 8, so basic block 1 needs no reloads.

in reload_as_needed
insn 5 gets reg 3 for its output reload, and becomes

| (insn:QI 5 4 341 (set (reg:SI 3)
|        (mem:SI (plus:SI (reg:SI 18) (const_int 8)))) 40 (nil)
|    (expr_list (mem:SI (plus:SI (reg:SI 18) (const_int 8))) (nil)))
| 
| (insn 341 5 6 (set (reg/v:SI 23)
| 	 (reg:SI 3)) -1 (nil)
|     (expr_list:QI (reg:SI 3) (nil)))

insn 8 takes up on its optional reload, finding reg 23 still around in reg 3,
and becomes

| (insn:QI 8 7 9 (set (reg/v:SI 7)
| 	 (reg:SI 3)) 40 (insn_list 5 (nil))
|    (nil))

insn 27 now can't find an equivalent.  insn 8 is not what it was, insn 341 is
unusable because it is a reload insn.  So the instruction suddenly needs a
reload, but basic_block_needs is 0 for this block, so reload_as_needed aborts.

Hope this isn't too incomprehensible.

Rob
-- 
UUCP:   ...!mcvax!ukc!warwick!cudcv	PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick             ARPA:   cudcv@warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England