[PATCH] Fix constant array ARRAY_REF[constant index] optimization (PR middle-end/28755)

Jakub Jelinek jakub@redhat.com
Thu Aug 17 12:40:00 GMT 2006


Hi!

As shown by the attached testcase, the constant array ARRAY_REF
with constant index optimization is in some cases really big pessimization.
If expand_expr decides to put a CONSTRUCTOR into memory, then we just waste
rodata memory, while we in that case really should just use the original
array entry.
The following patches (attached 4.1 and 4.2 versions) check for this and
if it determines it is not a win, it falls back to using the actual
original array reference.  On 4.1 that works without a problem,
unfortunately in 4.2 it seems -fsection-anchors kills the garbage collection
of unused deferred constants.  I have worked around it in the patch, but
think it should be eventually fixed in the -fsection-anchors handling
instead and then this hack can be removed.

Ok for 4.1/4.2?

	Jakub
-------------- next part --------------
2006-08-17  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/28755
	* expr.c (expand_expr_real_1) <case ARRAY_REF>: Make sure
	the const array field optimization doesn't create an extra constant
	MEM.

	* gcc.dg/pr28755.c: New test.

--- gcc/expr.c.jj	2006-08-07 15:08:38.000000000 +0200
+++ gcc/expr.c	2006-08-17 12:37:56.000000000 +0200
@@ -7283,13 +7283,40 @@ expand_expr_real_1 (tree exp, rtx target
 					      field, value)
 		      if (tree_int_cst_equal (field, index))
 			{
-			  if (!TREE_SIDE_EFFECTS (value))
+			  int save_section_anchors;
+
+			  if (TREE_SIDE_EFFECTS (value))
+			    break;
+
+			  if (TREE_CODE (value) != CONSTRUCTOR)
 			    return expand_expr (fold (value), target, tmode,
 						modifier);
+
+			  /* For CONSTRUCTOR this optimization is not always
+			     a win - if expand_expr creates a temporary
+			     constant, we just waste unnecessarily rodata
+			     space.
+			     The section_anchors hack is ugly, but ATM
+			     flag_section_anchors kills the ability to
+			     garbage collect unused deferred constants
+			     and we need that here.  */
+			  save_section_anchors = flag_section_anchors;
+			  flag_section_anchors = 0;
+			  temp = expand_expr (value, target, tmode, modifier);
+			  flag_section_anchors = save_section_anchors;
+			  if (temp == target
+			      || (temp && GET_CODE (temp) != MEM))
+			    {
+			      if (modifier != EXPAND_INITIALIZER
+				  && temp != target
+				  && temp)
+				temp = use_anchored_address (temp);
+			      return temp;
+			    }
 			  break;
 			}
 		  }
-		else if(TREE_CODE (init) == STRING_CST)
+		else if (TREE_CODE (init) == STRING_CST)
 		  {
 		    tree index1 = index;
 		    tree low_bound = array_ref_low_bound (exp);
--- gcc/testsuite/gcc.dg/pr28755.c.jj	2006-08-17 12:52:15.000000000 +0200
+++ gcc/testsuite/gcc.dg/pr28755.c	2006-08-17 12:51:36.000000000 +0200
@@ -0,0 +1,22 @@
+/* PR middle-end/28755 */
+/* { dg-do compile } */
+/* { dg-options "-Os" } */
+/* { dg-final { scan-assembler-times "2112543726\|7deadbee" 2 } } */
+
+struct S
+{
+  void *s1;
+  unsigned s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14;
+};
+
+const struct S array[] = {
+  { (void *) 0, 60, 640, 2112543726, 39682, 48, 16, 33, 10, 96, 2, 0, 0, 4 },
+  { (void *) 0, 60, 2112543726, 192, 18251, 16, 33, 10, 96, 2, 0, 0, 4, 212 }
+};
+
+void
+foo (struct S *x)
+{
+  x[0] = array[0];
+  x[5] = array[1];
+}
-------------- next part --------------
2006-08-17  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/28755
	* expr.c (expand_expr_real_1) <case ARRAY_REF>: Make sure
	the const array field optimization doesn't create an extra constant
	MEM.

	* gcc.dg/pr28755.c: New test.

--- gcc/expr.c.jj	2006-08-09 17:54:03.000000000 +0200
+++ gcc/expr.c	2006-08-17 13:00:33.000000000 +0200
@@ -7105,13 +7105,25 @@ expand_expr_real_1 (tree exp, rtx target
 					      field, value)
 		      if (tree_int_cst_equal (field, index))
 			{
-			  if (!TREE_SIDE_EFFECTS (value))
+			  if (TREE_SIDE_EFFECTS (value))
+			    break;
+
+			  if (TREE_CODE (value) != CONSTRUCTOR)
 			    return expand_expr (fold (value), target, tmode,
 						modifier);
+
+			  /* For CONSTRUCTOR this optimization is not always
+			     a win - if expand_expr creates a temporary
+			     constant, we just waste unnecessarily rodata
+			     space.  */
+			  temp = expand_expr (value, target, tmode, modifier);
+			  if (temp == target
+			      || (temp && GET_CODE (temp) != MEM))
+			    return temp;
 			  break;
 			}
 		  }
-		else if(TREE_CODE (init) == STRING_CST)
+		else if (TREE_CODE (init) == STRING_CST)
 		  {
 		    tree index1 = index;
 		    tree low_bound = array_ref_low_bound (exp);
--- gcc/testsuite/gcc.dg/pr28755.c.jj	2006-08-17 12:59:57.000000000 +0200
+++ gcc/testsuite/gcc.dg/pr28755.c	2006-08-17 12:59:57.000000000 +0200
@@ -0,0 +1,22 @@
+/* PR middle-end/28755 */
+/* { dg-do compile } */
+/* { dg-options "-Os" } */
+/* { dg-final { scan-assembler-times "2112543726\|7deadbee" 2 } } */
+
+struct S
+{
+  void *s1;
+  unsigned s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14;
+};
+
+const struct S array[] = {
+  { (void *) 0, 60, 640, 2112543726, 39682, 48, 16, 33, 10, 96, 2, 0, 0, 4 },
+  { (void *) 0, 60, 2112543726, 192, 18251, 16, 33, 10, 96, 2, 0, 0, 4, 212 }
+};
+
+void
+foo (struct S *x)
+{
+  x[0] = array[0];
+  x[5] = array[1];
+}


More information about the Gcc-patches mailing list