Patchwork Fix PR52355

login
register
mail settings
Submitter Richard Guenther
Date Feb. 24, 2012, 10:39 a.m.
Message ID <alpine.LNX.2.00.1202241138310.18230@zhemvz.fhfr.qr>
Download mbox | patch
Permalink /patch/142811/
State New
Headers show

Comments

Richard Guenther - Feb. 24, 2012, 10:39 a.m.
This fixes PR52355 by extending the existing folding of &a[i] - &a[j]
to cover multi-dimensional array access and non-equal base.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

Richard.

2012-02-24  Richard Guenther  <rguenther@suse.de>

	PR middle-end/52355
	* fold-const.c (fold_addr_of_array_ref_difference): New function.
	(fold_binary_loc): Use it to extend the existing &a[i] - &a[j]
	folding.

	* gcc.dg/pr52355.c: New testcase.

Patch

Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 184541)
+++ gcc/fold-const.c	(working copy)
@@ -9671,6 +9674,44 @@  fold_vec_perm (tree type, tree arg0, tre
     }
 }
 
+/* Try to fold a pointer difference of type TYPE two address expressions of
+   array references AREF0 and AREF1 using location LOC.  Return a
+   simplified expression for the difference or NULL_TREE.  */
+
+static tree
+fold_addr_of_array_ref_difference (location_t loc, tree type,
+				   tree aref0, tree aref1)
+{
+  tree base0 = TREE_OPERAND (aref0, 0);
+  tree base1 = TREE_OPERAND (aref1, 0);
+  tree base_offset = build_int_cst (type, 0);
+
+  /* If the bases are array references as well, recurse.  If the bases
+     are pointer indirections compute the difference of the pointers.
+     If the bases are equal, we are set.  */
+  if ((TREE_CODE (base0) == ARRAY_REF
+       && TREE_CODE (base1) == ARRAY_REF
+       && (base_offset
+	   = fold_addr_of_array_ref_difference (loc, type, base0, base1)))
+      || (INDIRECT_REF_P (base0)
+	  && INDIRECT_REF_P (base1)
+	  && (base_offset = fold_binary_loc (loc, MINUS_EXPR, type,
+					     TREE_OPERAND (base0, 0),
+					     TREE_OPERAND (base1, 0))))
+      || operand_equal_p (base0, base1, 0))
+    {
+      tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1));
+      tree op1 = fold_convert_loc (loc, type, TREE_OPERAND (aref1, 1));
+      tree esz = fold_convert_loc (loc, type, array_ref_element_size (aref0));
+      tree diff = build2 (MINUS_EXPR, type, op0, op1);
+      return fold_build2_loc (loc, PLUS_EXPR, type,
+			      base_offset,
+			      fold_build2_loc (loc, MULT_EXPR, type,
+					       diff, esz));
+    }
+  return NULL_TREE;
+}
+
 /* Fold a binary expression of code CODE and type TYPE with operands
    OP0 and OP1.  LOC is the location of the resulting expression.
    Return the folded expression if folding is successful.  Otherwise,
@@ -10582,19 +10623,11 @@  fold_binary_loc (location_t loc,
 	  && TREE_CODE (arg1) == ADDR_EXPR
 	  && TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF)
         {
-	  tree aref0 = TREE_OPERAND (arg0, 0);
-	  tree aref1 = TREE_OPERAND (arg1, 0);
-	  if (operand_equal_p (TREE_OPERAND (aref0, 0),
-			       TREE_OPERAND (aref1, 0), 0))
-	    {
-	      tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1));
-	      tree op1 = fold_convert_loc (loc, type, TREE_OPERAND (aref1, 1));
-	      tree esz = array_ref_element_size (aref0);
-	      tree diff = build2 (MINUS_EXPR, type, op0, op1);
-	      return fold_build2_loc (loc, MULT_EXPR, type, diff,
-			          fold_convert_loc (loc, type, esz));
-
-	    }
+	  tree tem = fold_addr_of_array_ref_difference (loc, type,
+							TREE_OPERAND (arg0, 0),
+							TREE_OPERAND (arg1, 0));
+	  if (tem)
+	    return tem;
 	}
 
       if (FLOAT_TYPE_P (type)
Index: gcc/testsuite/gcc.dg/pr52355.c
===================================================================
--- gcc/testsuite/gcc.dg/pr52355.c	(revision 0)
+++ gcc/testsuite/gcc.dg/pr52355.c	(revision 0)
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+
+void f(char a[16][16][16])
+{
+  asm volatile ("" : : "i" (&a[1][0][0] - &a[0][0][0]));
+}
+
+int main(void)
+{
+  char a[16][16][16];
+  f(a);
+  return 0;
+}