[patch] tree-ssa-ccp.c: Fold references into constant aggregates.

Kazu Hirata kazu@cs.umass.edu
Sun May 8 21:41:00 GMT 2005


Hi Richard,

> >   Richard Henderson said that the TREE_SIDE_EFFECTS check in Steven's
> >   original patch was useless, but expr.c:6945 checks
> >   TREE_SIDE_EFFECTS.  Could that be a problem?
> 
> I might guess that the expr.c check is there for cases that can't
> happen anymore.  You could assert no side effects if you like.  Or
> I guess just leave it alone for now.

OK.

> > +      if (compare_tree_int (idx, list_length (CONSTRUCTOR_ELTS (ctor))) < 0)
> > +	{
> > +	  /* Whoo-hoo!  I'll fold ya baby.  Yeah!  */
> > +	  HOST_WIDE_INT i;
> > +
> > +	  for (elt = CONSTRUCTOR_ELTS (ctor), i = TREE_INT_CST_LOW (idx);
> > +	       elt != 0 && i != 0;
> > +	       i--, elt = TREE_CHAIN (elt))
> > +	    /* Find that element.  */
> > +	    ;
> 
> You're traversing the list twice here.

Oops.  Fixed.

> Plus I believe you'll have to deal with RANGE_EXPRs from the C++
> front end.  So there is not in fact a 1-1 mapping for indicies.

Constant arrays from the C++ front end don't have TREE_READONLY set.
Since I don't have know any other language independent way of checking
whether an array is declared with const or not, I just left the issue
alone for now.

Here is the final patch that I committed.  I removed TREE_SIDE_EFFECTS
that I was using in the previous iteration of this patch.

Kazu Hirata

2005-05-08  Steven Bosscher  <stevenb@suse.de>
	    Kazu Hirata  <kazu@cs.umass.edu>

	PR tree-optimization/14841, tree-optimization/15838
	* tree-ssa-ccp.c (fold_const_aggregate_ref): New.
	(evaluate_stmt): Call it.

2005-05-08  Steven Bosscher  <stevenb@suse.de>
	    Kazu Hirata  <kazu@cs.umass.edu>

	PR tree-optimization/14841, tree-optimization/15838
	* gcc.dg/tree-ssa/pr14841.c: New.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1480
diff -u -d -p -r1.1480 Makefile.in
--- Makefile.in	8 May 2005 01:15:17 -0000	1.1480
+++ Makefile.in	8 May 2005 02:28:02 -0000
@@ -2078,7 +2078,7 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_F
    $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \
    $(DIAGNOSTIC_H) errors.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h \
    $(TREE_DUMP_H) $(BASIC_BLOCK_H) tree-pass.h langhooks.h \
-   tree-ssa-propagate.h $(FLAGS_H)
+   tree-ssa-propagate.h $(FLAGS_H) $(TARGET_H)
 tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) errors.h $(TREE_H) $(RTL_H) \
     $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) tree-inline.h \
     $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_GIMPLE_H) \
Index: tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-ccp.c,v
retrieving revision 2.69
diff -u -d -p -r2.69 tree-ssa-ccp.c
--- tree-ssa-ccp.c	3 May 2005 14:14:19 -0000	2.69
+++ tree-ssa-ccp.c	8 May 2005 02:28:03 -0000
@@ -209,6 +209,7 @@ Software Foundation, 59 Temple Place - S
 #include "tree-pass.h"
 #include "tree-ssa-propagate.h"
 #include "langhooks.h"
+#include "target.h"
 
 
 /* Possible lattice values.  */
@@ -970,6 +971,127 @@ ccp_fold (tree stmt)
 }
 
 
+/* Return the tree representing the element referenced by T if T is an
+   ARRAY_REF or COMPONENT_REF into constant aggregates.  Return
+   NULL_TREE otherwise.  */
+
+static tree
+fold_const_aggregate_ref (tree t)
+{
+  prop_value_t *value;
+  tree base, ctor, idx, field, elt;
+
+  switch (TREE_CODE (t))
+    {
+    case ARRAY_REF:
+      /* Get a CONSTRUCTOR.  If BASE is a VAR_DECL, get its
+	 DECL_INITIAL.  If BASE is a nested reference into another
+	 ARRAY_REF or COMPONENT_REF, make a recursive call to resolve
+	 the inner reference.  */
+      base = TREE_OPERAND (t, 0);
+      switch (TREE_CODE (base))
+	{
+	case VAR_DECL:
+	  if (!TREE_READONLY (base)
+	      || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE
+	      || !targetm.binds_local_p (base))
+	    return NULL_TREE;
+
+	  ctor = DECL_INITIAL (base);
+	  break;
+
+	case ARRAY_REF:
+	case COMPONENT_REF:
+	  ctor = fold_const_aggregate_ref (base);
+	  break;
+
+	default:
+	  return NULL_TREE;
+	}
+
+      if (ctor == NULL_TREE
+	  || TREE_CODE (ctor) != CONSTRUCTOR
+	  || !TREE_STATIC (ctor))
+	return NULL_TREE;
+
+      /* Get the index.  If we have an SSA_NAME, try to resolve it
+	 with the current lattice value for the SSA_NAME.  */
+      idx = TREE_OPERAND (t, 1);
+      switch (TREE_CODE (idx))
+	{
+	case SSA_NAME:
+	  if ((value = get_value (idx, true))
+	      && value->lattice_val == CONSTANT
+	      && TREE_CODE (value->value) == INTEGER_CST)
+	    idx = value->value;
+	  else
+	    return NULL_TREE;
+	  break;
+
+	case INTEGER_CST:
+	  break;
+
+	default:
+	  return NULL_TREE;
+	}
+
+      /* Whoo-hoo!  I'll fold ya baby.  Yeah!  */
+      for (elt = CONSTRUCTOR_ELTS (ctor);
+	   (elt && !tree_int_cst_equal (TREE_PURPOSE (elt), idx));
+	   elt = TREE_CHAIN (elt))
+	;
+
+      if (elt)
+	return TREE_VALUE (elt);
+      break;
+
+    case COMPONENT_REF:
+      /* Get a CONSTRUCTOR.  If BASE is a VAR_DECL, get its
+	 DECL_INITIAL.  If BASE is a nested reference into another
+	 ARRAY_REF or COMPONENT_REF, make a recursive call to resolve
+	 the inner reference.  */
+      base = TREE_OPERAND (t, 0);
+      switch (TREE_CODE (base))
+	{
+	case VAR_DECL:
+	  if (!TREE_READONLY (base)
+	      || TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE
+	      || !targetm.binds_local_p (base))
+	    return NULL_TREE;
+
+	  ctor = DECL_INITIAL (base);
+	  break;
+
+	case ARRAY_REF:
+	case COMPONENT_REF:
+	  ctor = fold_const_aggregate_ref (base);
+	  break;
+
+	default:
+	  return NULL_TREE;
+	}
+
+      if (ctor == NULL_TREE
+	  || TREE_CODE (ctor) != CONSTRUCTOR
+	  || !TREE_STATIC (ctor))
+	return NULL_TREE;
+
+      field = TREE_OPERAND (t, 1);
+
+      for (elt = CONSTRUCTOR_ELTS (ctor); elt; elt = TREE_CHAIN (elt))
+	if (TREE_PURPOSE (elt) == field
+	    /* FIXME: Handle bit-fields.  */
+	    && ! DECL_BIT_FIELD (TREE_PURPOSE (elt)))
+	  return TREE_VALUE (elt);
+      break;
+
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+  
 /* Evaluate statement STMT.  */
 
 static prop_value_t
@@ -989,10 +1112,13 @@ evaluate_stmt (tree stmt)
      bother folding the statement.  */
   else if (likelyvalue == VARYING)
     simplified = get_rhs (stmt);
-  /* Otherwise the statement is likely to have an UNDEFINED value and
-     there will be nothing to do.  */
+  /* If the statement is an ARRAY_REF or COMPONENT_REF into constant
+     aggregates, extract the referenced constant.  Otherwise the
+     statement is likely to have an UNDEFINED value, and there will be
+     nothing to do.  Note that fold_const_aggregate_ref returns
+     NULL_TREE if the first case does not match.  */
   else
-    simplified = NULL_TREE;
+    simplified = fold_const_aggregate_ref (get_rhs (stmt));
 
   if (simplified && is_gimple_min_invariant (simplified))
     {
--- /dev/null	2005-05-05 09:22:29.000000000 -0400
+++ testsuite/gcc.dg/tree-ssa/pr14841.c	2005-05-07 17:42:23.000000000 -0400
@@ -0,0 +1,29 @@
+/* PR tree-optimization/14841
+   Make sure that we can fold a possible nested reference into a
+   constant aggregate.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-store_ccp-details" } */
+
+struct car {
+  int speed;
+  int tire_pressure[4];
+};
+
+const struct car cars[] = {
+  { 75, { 10, 20, 30, 40 } },
+  { 35, { 12, 34, 56, 78 } },
+  { 40, { 19, 28, 37, 46 } }
+};
+
+extern void link_error (void);
+
+void
+foo (void)
+{
+  if (cars[1].tire_pressure[2] != 56)
+    link_error ();
+}
+
+/* { dg-final { scan-tree-dump-times "with if \\(0\\)" 1 "store_ccp"} } */
+/* { dg-final { cleanup-tree-dump "store_ccp" } } */



More information about the Gcc-patches mailing list