This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

reload and earlyclobber operands


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])



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]