This is a severe, but very rare, bug in combine, that one of the recent changes have exposed. I don't know which.

Basically, combine will not try combining across call instructions, but on the other hand it will not invalidate equivalences with registers that are explicitly set in the call instruction. This patch teaches it about this case.

Also, record_value_for_reg had a comment saying

 "If INSN is zero, don't update reg_stat[].last_set; this is
  only permitted with VALUE also zero and is used to invalidate the
  register"

However, this feature was never used, and as implemented it was not sufficient to fix the bug. So, I made combine set "last_set_invalid" too when INSN == VALUE == NULL_RTX.

Combine already has a loop that tries to invalidate call-clobbered register. The logic is the same as calling record_value_for_reg *before* my bug fix. However I did not change this because I was not sure if it was necessary -- and anyway, call-clobbered hard regs should only be present in combine if the user is using the "register ... asm" extension. In this case, the user cannot rely much on their semantics across function calls if they specify call-clobbered registers.

This patch was bootstrapped on powerpc-apple-darwin8.3.0, and H-P Nilsson tested on cris-axis-elf that it causes no assembly code generation difference on the testsuite (except for fixing the bug!) and CSiBE.

Ok for mainline?
2005-01-07  Paolo Bonzini  <[EMAIL PROTECTED]>

        * combine.c (record_value_for_reg): Invalidate registers
        if INSN is null.
        (record_dead_and_set_regs_1): Likewise, by passing them to
        record_value_for_reg.
        (record_dead_and_set_regs): Invalidate stores made by a
        call.  We do not combine across a call, but we still
        relied on equivalences.

Index: combine.c
===================================================================
--- combine.c   (revision 109374)
+++ combine.c   (working copy)
@@ -10823,7 +10826,7 @@ record_value_for_reg (rtx reg, rtx insn,
   for (i = regno; i < endregno; i++)
     {
       reg_stat[i].last_set_label = label_tick;
-      if (value && reg_stat[i].last_set_table_tick == label_tick)
+      if (!insn || (value && reg_stat[i].last_set_table_tick == label_tick))
        reg_stat[i].last_set_invalid = 1;
       else
        reg_stat[i].last_set_invalid = 0;
@@ -10872,6 +10874,13 @@ record_dead_and_set_regs_1 (rtx dest, rt
   if (GET_CODE (dest) == SUBREG)
     dest = SUBREG_REG (dest);
 
+  if (!record_dead_insn)
+    {
+      if (REG_P (dest))
+       record_value_for_reg (dest, NULL_RTX, NULL_RTX);
+      return;
+    }
+
   if (REG_P (dest))
     {
       /* If we are setting the whole register, we know its value.  Otherwise
@@ -10944,15 +10953,14 @@ record_dead_and_set_regs (rtx insn)
 
       last_call_cuid = mem_last_set = INSN_CUID (insn);
 
-      /* Don't bother recording what this insn does.  It might set the
-        return value register, but we can't combine into a call
-        pattern anyway, so there's no point trying (and it may cause
-        a crash, if e.g. we wind up asking for last_set_value of a
-        SUBREG of the return value register).  */
-      return;
+      /* We can't combine into a call pattern.  Remember, though, that
+        the return value register is set at this CUID.  We could
+        still replace a register with the return value from the
+        wrong subroutine call!  */
+      note_stores (PATTERN (insn), record_dead_and_set_regs_1, NULL_RTX);
     }
-
-  note_stores (PATTERN (insn), record_dead_and_set_regs_1, insn);
+  else
+    note_stores (PATTERN (insn), record_dead_and_set_regs_1, insn);
 }
 
 /* If a SUBREG has the promoted bit set, it is in fact a property of the

Reply via email to