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]

[3.4 PATCH] Fix record_value_for_reg (PR rtl-optimization/15139)


Hi!

The following testcase on x86-64 eats needs I guess at least a dozen
gigabytes of memory to compile.  The problem is that after unrolling, we
have 30 really similar maxdf instructions updating one pseudo, there
are 2 occurences of the pseudo in the insn
(set (reg:DF 61) (if_then_else:DF (gt (reg:DF 61) (reg:DF 67))
		  		  (reg:DF 61) (reg:DF 67)))
and as
  /* If VALUE contains REG and we have a previous value for REG, substitute
     the previous value.  */
  if (value && insn && reg_overlap_mentioned_p (reg, value))
is true, on each maxdf instruction the size of the recorded get_last_value*
for (reg:DF 61) more than doubles.

The following patch adds a cap on the size of the last value if it is going
to replace it into two or more places.  The 10000 rtxs was completely random
number high enough that it IMHO shouldn't trigger too often, but still small
enough that the testcase compiles instantly.
Is this ok for gcc-3_4-branch if it bootstraps & testing succeeds?

Because of tree-SSA, the problem is not reproduceable on mainline, but I
think we should avoid exponential growth there too.

2005-01-11  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/15139
	* combine.c (count_rtxs): New function.
	(record_value_for_reg): If replace_rtx would replace at least
	2 occurrences of REG in VALUE and TEM is really large, replace REG with
	(clobber (const_int 0)) instead of TEM.

	* gcc.dg/20050111-2.c: New test.

--- gcc/combine.c.jj	2004-11-24 23:26:46.000000000 +0100
+++ gcc/combine.c	2005-01-11 21:58:37.038907557 +0100
@@ -11353,6 +11353,47 @@ reversed_comparison (rtx exp, enum machi
     return gen_binary (reversed_code, mode, op0, op1);
 }
 
+/* Utility function for record_value_for_reg.  Count number of
+   rtxs in X.  */
+static int
+count_rtxs (rtx x)
+{
+  enum rtx_code code = GET_CODE (x);
+  const char *fmt;
+  int i, ret = 1;
+
+  if (GET_RTX_CLASS (code) == '2'
+      || GET_RTX_CLASS (code) == 'c')
+    {
+      rtx x0 = XEXP (x, 0);
+      rtx x1 = XEXP (x, 1);
+
+      if (x0 == x1)
+	return 1 + 2 * count_rtxs (x0);
+
+      if ((GET_RTX_CLASS (GET_CODE (x1)) == '2'
+	   || GET_RTX_CLASS (GET_CODE (x1)) == 'c')
+	  && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+	return 2 + 2 * count_rtxs (x0)
+	       + count_rtxs (x == XEXP (x1, 0)
+			     ? XEXP (x1, 1) : XEXP (x1, 0));
+
+      if ((GET_RTX_CLASS (GET_CODE (x0)) == '2'
+	   || GET_RTX_CLASS (GET_CODE (x0)) == 'c')
+	  && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+	return 2 + 2 * count_rtxs (x1)
+	       + count_rtxs (x == XEXP (x0, 0)
+			     ? XEXP (x0, 1) : XEXP (x0, 0));
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    if (fmt[i] == 'e')
+      ret += count_rtxs (XEXP (x, i));
+
+  return ret;
+}
+
 /* Utility function for following routine.  Called when X is part of a value
    being stored into reg_last_set_value.  Sets reg_last_set_table_tick
    for each register mentioned.  Similar to mention_regs in cse.c  */
@@ -11459,6 +11500,13 @@ record_value_for_reg (rtx reg, rtx insn,
 	      && GET_CODE (XEXP (tem, 0)) == CLOBBER
 	      && GET_CODE (XEXP (tem, 1)) == CLOBBER)
 	    tem = XEXP (tem, 0);
+	  else if (count_occurrences (value, reg, 1) >= 2)
+	    {
+	      /* If there are two or more occurrences of REG in VALUE,
+		 prevent the value from growing too much.  */
+	      if (count_rtxs (tem) > 10000)
+		tem = gen_rtx_CLOBBER (GET_MODE (tem), const0_rtx);
+	    }
 
 	  value = replace_rtx (copy_rtx (value), reg, tem);
 	}
--- gcc/testsuite/gcc.dg/20050111-2.c.jj	2005-01-11 22:10:11.678542323 +0100
+++ gcc/testsuite/gcc.dg/20050111-2.c	2005-01-11 22:10:29.884307421 +0100
@@ -0,0 +1,21 @@
+/* PR rtl-optimization/15139 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -funroll-loops" } */
+
+void
+foo (double **a, double **z)
+{
+  long int i, j;
+  double d = -1.0;
+
+  for (i = 0; i < 6; i++)
+    for (j = 0; j < 5; j++)
+      d = z[i][j] > d ? z[i][j] : d;
+
+  for (i = 0; i < 6; i++)
+    for (j = 0; j < 5; j++)
+      z[i][j] /= d;
+
+  for (i = 0; i < 5; i++)
+    a[i][j] = z[i][j];
+}

	Jakub


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