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]

[patch] Invalid register modes in combine


When backporting the combine patch mentioned below to csl-arm-branch I noticed 
that there are a few other places in combine.c where we do the same 
transformation, but do not do all the validity checks.

http://gcc.gnu.org/ml/gcc-patches/2005-03/msg01842.html
2005-03-19  Bernd Schmidt  <bernd.schmidt@analog.com>

        * combine.c (try_combine): When changing the mode of a hard reg, make
        sure that doing so is valid.

The attached patch moves this logic into a common function.

Tested with cross to arm-none-eabi bootstrapped i686-linux.
Ok?

Paul

2005-08-03  Paul Brook  <paul@codesourcery.com>

	* combine.c (can_change_dest_mode): New function.
	(try_combine, simplify_set): Use it.

:ADDPATCH middle-end (combine):
Index: gcc/combine.c
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/combine.c,v
retrieving revision 1.499
diff -u -p -r1.499 combine.c
--- gcc/combine.c	22 Jul 2005 11:55:42 -0000	1.499
+++ gcc/combine.c	3 Aug 2005 02:30:41 -0000
@@ -1663,6 +1663,27 @@ adjust_for_new_dest (rtx insn)
   distribute_links (gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX));
 }
 
+/* Return TRUE if combine can reuse reg X in mode MODE.
+   ADDED_SETS is nonzero if the original set is still required.  */
+static bool
+can_change_dest_mode (rtx x, int added_sets, enum machine_mode mode)
+{
+  unsigned int regno;
+
+  /* The mode can be changed for hard registers and single use pseudos. */
+  if (!REG_P(x))
+    return false;
+
+  regno = REGNO (x);
+  if (regno < FIRST_PSEUDO_REGISTER)
+    return (HARD_REGNO_MODE_OK (regno, mode)
+	    && (hard_regno_nregs[regno][GET_MODE (x)]
+		== hard_regno_nregs[regno][mode]));
+
+  return (REG_N_SETS (regno) == 1 && !added_sets
+	  && !REG_USERVAR_P (x));
+}
+
 /* Try to combine the insns I1 and I2 into I3.
    Here I1 and I2 appear earlier than I3.
    I1 can be zero; then we combine just I2 into I3.
@@ -2117,9 +2138,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 	  unsigned int regno = REGNO (SET_DEST (newpat));
 	  rtx new_dest = gen_rtx_REG (compare_mode, regno);
 
-	  if (regno < FIRST_PSEUDO_REGISTER
-	      || (REG_N_SETS (regno) == 1 && ! added_sets_2
-		  && ! REG_USERVAR_P (SET_DEST (newpat))))
+	  if (can_change_dest_mode(SET_DEST (newpat), added_sets_2,
+				   compare_mode))
 	    {
 	      if (regno >= FIRST_PSEUDO_REGISTER)
 		SUBST (regno_reg_rtx[regno], new_dest);
@@ -2353,14 +2373,12 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 
       if (m_split == 0 && ! reg_overlap_mentioned_p (ni2dest, newpat))
 	{
+ 	  enum machine_mode new_mode = GET_MODE (SET_DEST (newpat));
 	  /* If I2DEST is a hard register or the only use of a pseudo,
 	     we can change its mode.  */
-	  if (GET_MODE (SET_DEST (newpat)) != GET_MODE (i2dest)
-	      && GET_MODE (SET_DEST (newpat)) != VOIDmode
-	      && REG_P (i2dest)
-	      && (REGNO (i2dest) < FIRST_PSEUDO_REGISTER
-		  || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
-		      && ! REG_USERVAR_P (i2dest))))
+ 	  if (new_mode != GET_MODE (i2dest)
+ 	      && new_mode != VOIDmode
+ 	      && can_change_dest_mode (i2dest, added_sets_2, new_mode))
 	    ni2dest = gen_rtx_REG (GET_MODE (SET_DEST (newpat)),
 				   REGNO (i2dest));
 
@@ -2468,13 +2486,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int
 	     isn't valid for it, or change the number of registers.  */
 	  && (GET_MODE (*split) == GET_MODE (i2dest)
 	      || GET_MODE (*split) == VOIDmode
-	      || (REGNO (i2dest) < FIRST_PSEUDO_REGISTER
-		  && HARD_REGNO_MODE_OK (REGNO (i2dest), GET_MODE (*split))
-		  && (hard_regno_nregs[REGNO (i2dest)][GET_MODE (i2dest)]
-		      == hard_regno_nregs[REGNO (i2dest)][GET_MODE (*split)]))
-	      || (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER
-		  && REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
-		  && ! REG_USERVAR_P (i2dest)))
+	      || can_change_dest_mode (i2dest, added_sets_2,
+				       GET_MODE (*split)))
 	  && (next_real_insn (i2) == i3
 	      || ! use_crosses_set_p (*split, INSN_CUID (i2)))
 	  /* We can't overwrite I2DEST if its value is still used by
@@ -5282,8 +5295,7 @@ simplify_set (rtx x)
 	  unsigned int regno = REGNO (dest);
 	  rtx new_dest = gen_rtx_REG (compare_mode, regno);
 
-	  if (regno < FIRST_PSEUDO_REGISTER
-	      || (REG_N_SETS (regno) == 1 && ! REG_USERVAR_P (dest)))
+	  if (can_change_dest_mode (dest, 0, compare_mode))
 	    {
 	      if (regno >= FIRST_PSEUDO_REGISTER)
 		SUBST (regno_reg_rtx[regno], new_dest);

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