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] Fix infinite loop in calculate_global_regs_live


On Fri, Nov 30, 2001 at 02:45:58PM -0800, Richard Henderson wrote:
> On Fri, Nov 30, 2001 at 09:58:20PM +0100, Jakub Jelinek wrote:
> > 	* gcc.c-torture/compile/20011130-1.c: New test.
> 
> Ok if you document what the original fault is at the top
> of the testcase.

Attached below for completeness, I'll commit it together with the fix if
it is approved.

The problem turned about to be buggy logical arithmetics in
{ior,and}_reg_cond.
Particularly:
ior_reg_cond(
(and (ne (reg:BI 272 p16 [429])
        (const_int 0 [0x0]))
    (eq (reg:BI 274 p18 [430])
        (const_int 0 [0x0]))),
(ne (reg:BI 274 p18 [430])
    (const_int 0 [0x0])),
1)
returned:
(ne (reg:BI 272 p16 [429])
    (const_int 0 [0x0]))
while it should have returned:
(ior (ne (reg:BI 272 p16 [429])
        (const_int 0 [0x0]))
    (ne (reg:BI 274 p18 [430])
        (const_int 0 [0x0])))
Also, the code was never differentiating between "optimized the expression
into old" and "!add and couldn't optimize the expression", which lead to
unnecessary IOR or ANDs.
Following patch uses NULL to signalize that ior_reg_cond (resp.
and_reg_cond) couldn't simplify the expression (old OP x). If one of the
subexpressions was simplified into 0 or 1 and it should return op0 resp.
op1 which couldn't be simplified, it calls gen_rtx_IOR resp. gen_rtx_AND on
that operand. Last, it optimizes some common cases:
(A | x) | x iff (A | x)
(A & x) | x iff x
(A & x) & x iff (A & x)
(A | x) & x iff x

Bootstrap pending on IA-64, ok to commit if it succeeds?

2001-12-03  Jakub Jelinek  <jakub@redhat.com>

	* flow.c (ior_reg_cond): Return NULL if ! add and rtx wasn't optimized.
	Return correct value if one of the subexpressions was optimized to
	0 resp. 1.  Optimize (x | A) | x and (x & A) | x.
	(and_reg_cond): Similarly.

	* gcc.c-torture/compile/20011130-2.c: New test.

--- gcc/flow.c.jj	Fri Nov 30 00:07:48 2001
+++ gcc/flow.c	Mon Dec  3 15:38:47 2001
@@ -2818,7 +2818,7 @@ ior_reg_cond (old, x, add)
 	  && REGNO (XEXP (x, 0)) == REGNO (XEXP (old, 0)))
 	return old;
       if (! add)
-	return old;
+	return NULL;
       return gen_rtx_IOR (0, old, x);
     }
 
@@ -2827,51 +2827,63 @@ ior_reg_cond (old, x, add)
     case IOR:
       op0 = ior_reg_cond (XEXP (old, 0), x, 0);
       op1 = ior_reg_cond (XEXP (old, 1), x, 0);
-      if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
+      if (op0 != NULL || op1 != NULL)
 	{
 	  if (op0 == const0_rtx)
-	    return op1;
+	    return op1 ? op1 : gen_rtx_IOR (0, XEXP (old, 1), x);
 	  if (op1 == const0_rtx)
-	    return op0;
+	    return op0 ? op0 : gen_rtx_IOR (0, XEXP (old, 0), x);
 	  if (op0 == const1_rtx || op1 == const1_rtx)
 	    return const1_rtx;
-	  if (op0 == XEXP (old, 0))
-	    op0 = gen_rtx_IOR (0, op0, x);
-	  else
-	    op1 = gen_rtx_IOR (0, op1, x);
+	  if (op0 == NULL)
+	    op0 = gen_rtx_IOR (0, XEXP (old, 0), x);
+	  else if (rtx_equal_p (x, op0))
+	    /* (x | A) | x ~ (x | A).  */
+	    return old;
+	  if (op1 == NULL)
+	    op1 = gen_rtx_IOR (0, XEXP (old, 1), x);
+	  else if (rtx_equal_p (x, op1))
+	    /* (A | x) | x ~ (A | x).  */
+	    return old;
 	  return gen_rtx_IOR (0, op0, op1);
 	}
       if (! add)
-	return old;
+	return NULL;
       return gen_rtx_IOR (0, old, x);
 
     case AND:
       op0 = ior_reg_cond (XEXP (old, 0), x, 0);
       op1 = ior_reg_cond (XEXP (old, 1), x, 0);
-      if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
+      if (op0 != NULL || op1 != NULL)
 	{
 	  if (op0 == const1_rtx)
-	    return op1;
+	    return op1 ? op1 : gen_rtx_IOR (0, XEXP (old, 1), x);
 	  if (op1 == const1_rtx)
-	    return op0;
+	    return op0 ? op0 : gen_rtx_IOR (0, XEXP (old, 0), x);
 	  if (op0 == const0_rtx || op1 == const0_rtx)
 	    return const0_rtx;
-	  if (op0 == XEXP (old, 0))
-	    op0 = gen_rtx_IOR (0, op0, x);
-	  else
-	    op1 = gen_rtx_IOR (0, op1, x);
+	  if (op0 == NULL)
+	    op0 = gen_rtx_IOR (0, XEXP (old, 0), x);
+	  else if (rtx_equal_p (x, op0))
+	    /* (x & A) | x ~ x.  */
+	    return op0;
+	  if (op1 == NULL)
+	    op1 = gen_rtx_IOR (0, XEXP (old, 1), x);
+	  else if (rtx_equal_p (x, op1))
+	    /* (A & x) | x ~ x.  */
+	    return op1;
 	  return gen_rtx_AND (0, op0, op1);
 	}
       if (! add)
-	return old;
+	return NULL;
       return gen_rtx_IOR (0, old, x);
 
     case NOT:
       op0 = and_reg_cond (XEXP (old, 0), not_reg_cond (x), 0);
-      if (op0 != XEXP (old, 0))
+      if (op0 != NULL)
 	return not_reg_cond (op0);
       if (! add)
-	return old;
+	return NULL;
       return gen_rtx_IOR (0, old, x);
 
     default:
@@ -2921,7 +2933,7 @@ and_reg_cond (old, x, add)
 	  && REGNO (XEXP (x, 0)) == REGNO (XEXP (old, 0)))
 	return old;
       if (! add)
-	return old;
+	return NULL;
       return gen_rtx_AND (0, old, x);
     }
 
@@ -2930,62 +2942,63 @@ and_reg_cond (old, x, add)
     case IOR:
       op0 = and_reg_cond (XEXP (old, 0), x, 0);
       op1 = and_reg_cond (XEXP (old, 1), x, 0);
-      if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
+      if (op0 != NULL || op1 != NULL)
 	{
 	  if (op0 == const0_rtx)
-	    return op1;
+	    return op1 ? op1 : gen_rtx_AND (0, XEXP (old, 1), x);
 	  if (op1 == const0_rtx)
-	    return op0;
+	    return op0 ? op0 : gen_rtx_AND (0, XEXP (old, 0), x);
 	  if (op0 == const1_rtx || op1 == const1_rtx)
 	    return const1_rtx;
-	  if (op0 == XEXP (old, 0))
-	    op0 = gen_rtx_AND (0, op0, x);
-	  else
-	    op1 = gen_rtx_AND (0, op1, x);
+	  if (op0 == NULL)
+	    op0 = gen_rtx_AND (0, XEXP (old, 0), x);
+	  else if (rtx_equal_p (x, op0))
+	    /* (x | A) & x ~ x.  */
+	    return op0;
+	  if (op1 == NULL)
+	    op1 = gen_rtx_AND (0, XEXP (old, 1), x);
+	  else if (rtx_equal_p (x, op1))
+	    /* (A | x) & x ~ x.  */
+	    return op1;
 	  return gen_rtx_IOR (0, op0, op1);
 	}
       if (! add)
-	return old;
+	return NULL;
       return gen_rtx_AND (0, old, x);
 
     case AND:
       op0 = and_reg_cond (XEXP (old, 0), x, 0);
       op1 = and_reg_cond (XEXP (old, 1), x, 0);
-      if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
+      if (op0 != NULL || op1 != NULL)
 	{
 	  if (op0 == const1_rtx)
-	    return op1;
+	    return op1 ? op1 : gen_rtx_AND (0, XEXP (old, 1), x);
 	  if (op1 == const1_rtx)
-	    return op0;
+	    return op0 ? op0 : gen_rtx_AND (0, XEXP (old, 0), x);
 	  if (op0 == const0_rtx || op1 == const0_rtx)
 	    return const0_rtx;
-	  if (op0 == XEXP (old, 0))
-	    op0 = gen_rtx_AND (0, op0, x);
-	  else
-	    op1 = gen_rtx_AND (0, op1, x);
+	  if (op0 == NULL)
+	    op0 = gen_rtx_AND (0, XEXP (old, 0), x);
+	  else if (rtx_equal_p (x, op0))
+	    /* (x & A) & x ~ (x & A).  */
+	    return old;
+	  if (op1 == NULL)
+	    op1 = gen_rtx_AND (0, XEXP (old, 1), x);
+	  else if (rtx_equal_p (x, op1))
+	    /* (A & x) & x ~ (A & x).  */
+	    return old;
 	  return gen_rtx_AND (0, op0, op1);
 	}
       if (! add)
-	return old;
-
-      /* If X is identical to one of the existing terms of the AND,
-	 then just return what we already have.  */
-      /* ??? There really should be some sort of recursive check here in
-	 case there are nested ANDs.  */
-      if ((GET_CODE (XEXP (old, 0)) == GET_CODE (x)
-	   && REGNO (XEXP (XEXP (old, 0), 0)) == REGNO (XEXP (x, 0)))
-	  || (GET_CODE (XEXP (old, 1)) == GET_CODE (x)
-	      && REGNO (XEXP (XEXP (old, 1), 0)) == REGNO (XEXP (x, 0))))
-	return old;
-
+	return NULL;
       return gen_rtx_AND (0, old, x);
 
     case NOT:
       op0 = ior_reg_cond (XEXP (old, 0), not_reg_cond (x), 0);
-      if (op0 != XEXP (old, 0))
+      if (op0 != NULL)
 	return not_reg_cond (op0);
       if (! add)
-	return old;
+	return NULL;
       return gen_rtx_AND (0, old, x);
 
     default:
--- gcc/testsuite/gcc.c-torture/compile/20011130-2.c.jj	Mon Dec  3 15:58:45 2001
+++ gcc/testsuite/gcc.c-torture/compile/20011130-2.c	Mon Dec  3 16:05:21 2001
@@ -0,0 +1,54 @@
+/* This testcase caused infinite loop in life info computation
+   after if conversion on IA-64.  Conditional register dead for
+   pseudo holding sign-extended k was improperly computed,
+   resulting in this pseudo beeing live at start of bb if it was
+   dead at the end and vice versa; as it was a bb which had edge
+   to itself, this resulted in alternative propagating this basic
+   block forever.  */
+
+typedef struct {
+  unsigned char a;
+  unsigned char b;
+} S0;
+
+typedef struct {
+  S0 *c;
+  int d;
+  unsigned int e;
+  unsigned char *f[3];
+  void *g;
+} S1;
+
+int bar (int, void *);
+
+int foo (S1 *x, float y)
+{
+  S0 *h;
+  int i, j, k, l, m;
+  float n, o, p;
+  unsigned char *q, *r[3];
+
+  h = x->c;
+  m = h->a;
+  l = h->b;
+  n = y;
+  o = 0.0;
+  if (x->d == 8)
+    for (j = 0; j < x->e; j++)
+      for (k = 0; k < 3; k++)
+	{
+	  n = y;
+	  o = 0.0;
+	  if (m)
+	    q = x->f[k] + x->e - 1 - j;
+	  else
+	    q = x->f[k] + j;
+	  p = (*q - o) * y / (n - o);
+	  p = 0.0 > p ? 0.0 : p;
+	  p = y < p ? y : p;
+	  if (l)
+	    p = r[k][(int) p];
+	  bar (p, x->g);
+	}
+  return 1;
+}

	Jakub


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