diff options
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/Makefile.in | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/pr14841.c | 29 | ||||
-rw-r--r-- | gcc/tree-ssa-ccp.c | 131 |
4 files changed, 165 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0da6d512a80..cc33cabace6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +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 Jakub Jelinek <jakub@redhat.com> * config/ia64/ia64.c (ia64_override_options): Don't set diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 531c003efd0..de723704b57 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2078,7 +2078,7 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_FLOW_H) $(CONFIG_H) \ $(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) \ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr14841.c b/gcc/testsuite/gcc.dg/tree-ssa/pr14841.c new file mode 100644 index 00000000000..4acc6ce3fc8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr14841.c @@ -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" } } */ diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 2d16957a120..58b8c2c01be 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -209,6 +209,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #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 +1111,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)) { |