This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
reload and earlyclobber operands
- To: egcs-patches at gcc dot gnu dot org
- Subject: reload and earlyclobber operands
- From: Philip Blundell <pb at nexus dot co dot uk>
- Date: Tue, 27 Jul 1999 13:55:48 +0100
- Cc: Richard Earnshaw <rearnsha at arm dot com>, Scott Bambrough <scottb at netwinder dot org>
This morning I got bitten by the bug described in
<http://egcs.cygnus.com/ml/gcc-bugs/1999-06/msg00853.html>, which spurred me
into trying to do something about it.
In the testcase I'm looking at (not quite the same as the one in the original
report) the problematic code is like this:
(insn 6 50 14 (set (reg/v:SI 33)
(reg:SI 1 r1)) 176 {*movsi_insn} (nil)
(expr_list:REG_DEAD (reg:SI 1 r1)
(nil)))
(insn 14 6 20 (set (reg/v:SI 40)
(mult:SI (reg/v:SI 33)
(reg/v:SI 33))) 41 {mulsi3} (insn_list/j/c 6 (nil))
(nil))
The second insn has an earlyclobber of reg 40; both regs 33 and 40 have failed
to get hard registers and need reloading. What happens is that reload spots
that reg 33 is equivalent to R1 at this time and uses the latter for the
input reload -- this is ok, since it doesn't conflict with pseudo 40 yet.
Unfortunately, when the second reload is being handled, R1 also happens to
be the first available spill register and so alloc_reload_reg chooses it
for the output reload as well. So we wind up with this (invalid) result:
(insn 14 6 291 (set (reg:SI 1 r1)
(mult:SI (reg:SI 1 r1)
(reg:SI 1 r1))) 41 {mulsi3} (insn_list/j/c 6 (nil))
(nil))
Here's a patch I cooked up to address this issue. I'm not sure it's the right
thing to do though (and this isn't a part of the compiler I'm familiar with);
does anybody have any comments?
Thanks
p.
Tue Jul 27 13:48:46 1999 Philip Blundell <pb@nexus.co.uk>
* reload1.c (allocate_reload_reg): Don't allow earlyclobber
outputs to conflict with previously-reloaded inputs.
Index: reload1.c
===================================================================
RCS file: /home/cvs/repository/gnu/egcs/gcc/reload1.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 reload1.c
--- reload1.c 1999/07/22 12:47:19 1.1.1.3
+++ reload1.c 1999/07/27 12:46:07
@@ -5403,6 +5403,7 @@
{
rtx insn = chain->insn;
int i, pass, count, regno;
+ int is_earlyclobber = 0;
rtx new;
/* If we put this reload ahead, thinking it is a group,
@@ -5420,6 +5421,14 @@
int force_group = reload_nregs[r] > 1 && ! last_reload;
+ /* See if the output of the reload is an earlyclobber for this insn.
+ If so, we need to take care not to introduce conflicts with its
+ input operands. */
+ if (reload_out[r])
+ for (i = 0; i < n_earlyclobbers; i++)
+ if (rtx_equal_p (reload_earlyclobbers[i], reload_out[r]))
+ is_earlyclobber = 1;
+
/* If we want a single register and haven't yet found one,
take any reg in the right class and not in use.
If we want a consecutive group, here is where we look for it.
@@ -5458,6 +5467,19 @@
if (i >= n_spills)
i -= n_spills;
regnum = spill_regs[i];
+
+ if (is_earlyclobber)
+ {
+ /* Don't ever try to use a spill reg that conflicts with one
+ of the input reloads. */
+ int i1;
+ for (i1 = 0; i1 < n_reloads; i1++)
+ if (reload_in[i1] && reload_reg_rtx[i1]
+ && (REGNO (reload_reg_rtx[i1]) == regnum))
+ break;
+ if (i1 < n_reloads)
+ continue;
+ }
if ((reload_reg_free_p (regnum, reload_opnum[r],
reload_when_needed[r])