[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