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 PR15791 (final)


This patch fixes PR15791 and related testcases by folding
comparisons between &a[i] and &a[j] or related forms to
comparisons of i and j, if possible.  I chose to be conservative
with index types for now.

Bootstrapped and tested on x86_64-unknown-linux-gnu with
no regressions for c,c++,f95,java and objc.  New testcases
were verified to fail/pass before and pass after the patch.

Ok for mainline? (If yes, please commit)

Thanks,
Richard.

2005-Jan-28  Richard Guenther <richard.guenther@uni-tuebingen.de>

	PR tree-optimization/15791

	* fold-const.c (extract_array_ref): new function.
	(fold): fold comparisons between &a[i] and &a[j] or
	semantically equivalent trees.
	testsuite/gcc.dg/tree-ssa/pr15791-1.c: new testcase.
	testsuite/gcc.dg/tree-ssa/pr15791-2.c: likewise.
	testsuite/gcc.dg/tree-ssa/pr15791-3.c: likewise.
	testsuite/gcc.dg/tree-ssa/pr15791-4.c: likewise.
	testsuite/gcc.dg/tree-ssa/pr15791-5.c: likewise.
	testsuite/g++.dg/tree-ssa/pr15791-1.C: likewise.
	testsuite/g++.dg/tree-ssa/pr15791-2.C: likewise.
	testsuite/g++.dg/tree-ssa/pr15791-3.C: likewise.
	testsuite/g++.dg/tree-ssa/pr15791-4.C: likewise.
	testsuite/g++.dg/tree-ssa/pr15791-5.C: likewise.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.497
diff -u -c -3 -p -r1.497 fold-const.c
*** fold-const.c	23 Jan 2005 15:05:29 -0000	1.497
--- fold-const.c	28 Jan 2005 12:23:53 -0000
*************** extract_muldiv_1 (tree t, tree c, enum t
*** 5356,5361 ****
--- 5356,5412 ----

    return 0;
  }
+
+
+ /* Return true if expr looks like an ARRAY_REF and set base and
+    offset to the appropriate trees.  If there is no offset,
+    offset is set to NULL_TREE.  */
+
+ static bool
+ extract_array_ref (tree expr, tree *base, tree *offset)
+ {
+   /* We have to be careful with stripping nops as with the
+      base type the meaning of the offset can change.  */
+   tree inner_expr = expr;
+   STRIP_NOPS (inner_expr);
+   /* One canonical form is a PLUS_EXPR with the first
+      argument being an ADDR_EXPR with a possible NOP_EXPR
+      attached.  */
+   if (TREE_CODE (expr) == PLUS_EXPR)
+     {
+       tree op0 = TREE_OPERAND (expr, 0);
+       STRIP_NOPS (op0);
+       if (TREE_CODE (op0) == ADDR_EXPR)
+ 	{
+ 	  *base = TREE_OPERAND (expr, 0);
+ 	  *offset = TREE_OPERAND (expr, 1);
+ 	  return true;
+ 	}
+     }
+   /* Other canonical form is an ADDR_EXPR of an ARRAY_REF,
+      which we transform into an ADDR_EXPR with appropriate
+      offset.  For other arguments to the ADDR_EXPR we assume
+      zero offset and as such do not care about the ADDR_EXPR
+      type and strip possible nops from it.  */
+   else if (TREE_CODE (inner_expr) == ADDR_EXPR)
+     {
+       tree op0 = TREE_OPERAND (inner_expr, 0);
+       if (TREE_CODE (op0) == ARRAY_REF)
+ 	{
+ 	  *base = build_fold_addr_expr (TREE_OPERAND (op0, 0));
+ 	  *offset = TREE_OPERAND (op0, 1);
+ 	}
+       else
+ 	{
+ 	  *base = inner_expr;
+ 	  *offset = NULL_TREE;
+ 	}
+       return true;
+     }
+
+   return false;
+ }
+

  /* Return a node which has the indicated constant VALUE (either 0 or
     1), and is of the indicated TYPE.  */
*************** fold (tree expr)
*** 8245,8250 ****
--- 8296,8328 ----
  				      ? code == EQ_EXPR : code != EQ_EXPR,
  				      type);

+       /* If this is a comparison of two exprs that look like an
+ 	 ARRAY_REF of the same object, then we can fold this to a
+ 	 comparison of the two offsets.  */
+       if (COMPARISON_CLASS_P (t))
+ 	{
+ 	  tree base0, offset0, base1, offset1;
+
+ 	  if (extract_array_ref (arg0, &base0, &offset0)
+ 	      && extract_array_ref (arg1, &base1, &offset1)
+ 	      && operand_equal_p (base0, base1, 0))
+ 	    {
+ 	      if (offset0 == NULL_TREE
+ 		  && offset1 == NULL_TREE)
+ 		{
+ 		  offset0 = integer_zero_node;
+ 		  offset1 = integer_zero_node;
+ 		}
+ 	      else if (offset0 == NULL_TREE)
+ 		offset0 = build_int_cst (TREE_TYPE (offset1), 0);
+ 	      else if (offset1 == NULL_TREE)
+ 		offset1 = build_int_cst (TREE_TYPE (offset0), 0);
+
+ 	      if (TREE_TYPE (offset0) == TREE_TYPE (offset1))
+ 		return fold (build2 (code, type, offset0, offset1));
+ 	    }
+ 	}
+
        if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
  	{
  	  tree targ0 = strip_float_extensions (arg0);

C testcases for gcc.dg/tree-ssa:

/* { dg-do link } */

void link_error ();

int main ()
{
  struct { int b[2]; } x;
  int b[2];
  if (&b[1] != &b[1])
    link_error ();
  if (&b[0] != b)
    link_error ();
  if (b == &b[2])
    link_error ();
  if (b != b)
    link_error ();
  if (&x.b[1] == &x.b[0])
    link_error ();
  if (x.b != &x.b[0])
    link_error ();
  if (&x.b[1] == x.b)
    link_error ();
  return 0;
}

/* { dg-do link } */
/* { dg-options "" } */

void link_error ();
struct a {};
int main ()
{
  struct a b[2];
  if (&b[0] != &b[1])
    link_error ();
  return 0;
}

/* { dg-do compile } */
/* { dg-options "-fdump-tree-gimple" } */

int f(int i, unsigned j)
{
      int b[2];
      if (&b[i] == &b[j])
	      return 1;
      return 0;
}

/* { dg-final { scan-tree-dump-times "i == j" 0 "gimple" } } */

/* { dg-do compile } */
/* { dg-options "-fdump-tree-gimple" } */

int f(int i, int j)
{
    int b[2][2];
    if (&b[1][i] == &b[0][j])
      return 1;
    return 0;
}

/* { dg-final { scan-tree-dump-times "i == j" 0 "gimple" } } */

/* { dg-do compile } */
/* { dg-options "-fdump-tree-gimple" } */

int foo(int i, int j)
{
	char g[16];
	if (&g[i] == &g[j])
		return 1;
	return 0;
}

/* { dg-final { scan-tree-dump-times "i == j" 1 "gimple" } } */


C++ testcases for g++.dg/tree-ssa:

/* { dg-do link } */

void link_error ();

int main ()
{
  struct { int b[2]; } x;
  int b[2];
  if (&b[1] != &b[1])
    link_error ();
  if (&b[0] != b)
    link_error ();
  if (b == &b[2])
    link_error ();
  if (b != b)
    link_error ();
  if (&x.b[1] == &x.b[0])
    link_error ();
  if (x.b != &x.b[0])
    link_error ();
  if (&x.b[1] == x.b)
    link_error ();
  return 0;
}

/* { dg-do link } */

void link_error ();
struct a {};
int main ()
{
  struct a b[2];
  if (&b[0] == &b[1])
    link_error ();
  return 0;
}

/* { dg-do compile } */
/* { dg-options "-fdump-tree-gimple" } */

int f(int i, unsigned j)
{
      int b[2];
      if (&b[i] == &b[j])
	      return 1;
      return 0;
}

/* { dg-final { scan-tree-dump-times "i == j" 0 "gimple" } } */

/* { dg-do compile } */
/* { dg-options "-fdump-tree-gimple" } */

int f(int i, int j)
{
    int b[2][2];
    if (&b[1][i] == &b[0][j])
      return 1;
    return 0;
}

/* { dg-final { scan-tree-dump-times "i == j" 0 "gimple" } } */

/* { dg-do compile } */
/* { dg-options "-fdump-tree-gimple" } */

int foo(int i, int j)
{
	char g[16];
	if (&g[i] == &g[j])
		return 1;
	return 0;
}

/* { dg-final { scan-tree-dump-times "i == j" 1 "gimple" } } */


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