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]
Other format: [Raw text]

[vta, vta4.4] fix mode-change debug info propagation in combine


Jakub told me about a crash in combine on ppc, caused by an invalid
SUBREG in a debug insn, and we worked together to come up with a
complete fix for the problem.

It was caused by an earlier combine operation that had reused a pseudo
as a scratch register under a different mode.

The reference to the scratch register shouldn't have remained in debug
insns, regardless of the mode change.  This patch arranges for the value
previously stored in the scratch register, always i2dest, to be
propagated to uses in debug insns between i2 and i3.

Furthermore, for mode changes to the output register of i3, we use
subregs to adjust the modes of references to it in debug insns between
i3 and the other_insn that is the sole non-debug use of that pseudo.

This is the final patch, that I'm checking in, vta and vta4.4 branches.

for gcc/ChangeLog.vta
from  Alexandre Oliva  <aoliva@redhat.com>,  Jakub Jelinek  <jakub@redhat.com>

	* combine.c (try_combine): If there were any REG mode changes,
	adjust DEBUG_INSNs.

Index: gcc/combine.c
===================================================================
--- gcc/combine.c.orig	2009-08-04 04:44:39.000000000 -0300
+++ gcc/combine.c	2009-08-04 09:00:10.000000000 -0300
@@ -2423,6 +2423,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int
   rtx i3dest_killed = 0;
   /* SET_DEST and SET_SRC of I2 and I1.  */
   rtx i2dest = 0, i2src = 0, i1dest = 0, i1src = 0;
+  /* Set if I2DEST was reused as a scratch register.  */
+  bool i2scratch = false;
   /* PATTERN (I1) and PATTERN (I2), or a copy of it in certain cases.  */
   rtx i1pat = 0, i2pat = 0;
   /* Indicates if I2DEST or I1DEST is in I2SRC or I1_SRC.  */
@@ -3212,6 +3214,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 		  undobuf.frees = buf;
 		}
 	    }
+
+	  i2scratch = m_split != 0;
 	}
 
       /* If recog_for_combine has discarded clobbers, try to use them
@@ -3306,6 +3310,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 	  bool subst_done = false;
 	  newi2pat = NULL_RTX;
 
+	  i2scratch = true;
+
 	  /* Get NEWDEST as a register in the proper mode.  We have already
 	     validated that we can do this.  */
 	  if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
@@ -3608,6 +3614,67 @@ try_combine (rtx i3, rtx i2, rtx i1, int
       return 0;
     }
 
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      struct undo *undo;
+
+      for (undo = undobuf.undos; undo; undo = undo->next)
+	if (undo->kind == UNDO_MODE)
+	  {
+	    rtx reg = *undo->where.r;
+	    enum machine_mode new_mode = GET_MODE (reg);
+	    enum machine_mode old_mode = undo->old_contents.m;
+
+	    /* Temporarily revert mode back.  */
+	    adjust_reg_mode (reg, old_mode);
+
+	    if (reg == i2dest && i2scratch)
+	      {
+		/* If we used i2dest as a scratch register with a
+		   different mode, substitute it for the original
+		   i2src while its original mode is temporarily
+		   restored, and then clear i2scratch so that we don't
+		   do it again later.  */
+		propagate_for_debug (i2, i3, reg, i2src, false);
+		i2scratch = false;
+		/* Put back the new mode.  */
+		adjust_reg_mode (reg, new_mode);
+	      }
+	    else
+	      {
+		rtx tempreg = gen_raw_REG (old_mode, REGNO (reg));
+		rtx first, last;
+
+		if (reg == i2dest)
+		  {
+		    first = i2;
+		    last = i3;
+		  }
+		else
+		  {
+		    first = i3;
+		    last = undobuf.other_insn;
+		    gcc_assert (last);
+		  }
+
+		/* We're dealing with a reg that changed mode but not
+		   meaning, so we want to turn it into a subreg for
+		   the new mode.  However, because of REG sharing and
+		   because its mode had already changed, we have to do
+		   it in two steps.  First, replace any debug uses of
+		   reg, with its original mode temporarily restored,
+		   with this copy we have created; then, replace the
+		   copy with the SUBREG of the original shared reg,
+		   once again changed to the new mode.  */
+		propagate_for_debug (first, last, reg, tempreg, false);
+		adjust_reg_mode (reg, new_mode);
+		propagate_for_debug (first, last, tempreg,
+				     lowpart_subreg (old_mode, reg, new_mode),
+				     false);
+	      }
+	  }
+    }
+
   /* If we will be able to accept this, we have made a
      change to the destination of I3.  This requires us to
      do a few adjustments.  */
@@ -3798,6 +3865,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 
     if (newi2pat)
       {
+	if (MAY_HAVE_DEBUG_INSNS && i2scratch)
+	  propagate_for_debug (i2, i3, i2dest, i2src, false);
 	INSN_CODE (i2) = i2_code_number;
 	PATTERN (i2) = newi2pat;
       }
-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

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