From 155c92a7a0a4ce7738d1d8851e572ea790f34ffb Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Fri, 3 Sep 2010 12:15:54 +0200 Subject: [PATCH] cgraph.h (struct varpool_node): Add const_value_known. * cgraph.h (struct varpool_node): Add const_value_known. (varpool_decide_const_value_known): Declare. * tree-ssa-ccp.c (fold_const_aggregate_ref): Update initializer folding. * lto-cgraph.c (lto_output_varpool_node): Store const_value_known. (input_varpool_node): Restore const_value_known. * tree-ssa-loop-ivcanon (constant_after_peeling): Check varpool for initializer folding. * ipa.c (ipa_discover_readonly_nonaddressable_var, function_and_variable_visibility): Compute const_value_known. * gimple-fold.c (get_symbol_constant_value): Use varpool for initializer folding. * varpool.c (varpool_decide_const_value_known): New function. From-SVN: r163808 --- gcc/ChangeLog | 15 +++++++++++++++ gcc/cgraph.h | 3 +++ gcc/gimple-fold.c | 8 +++----- gcc/ipa.c | 5 +++++ gcc/lto-cgraph.c | 2 ++ gcc/tree-ssa-ccp.c | 9 ++++++--- gcc/tree-ssa-loop-ivcanon.c | 4 +--- gcc/varpool.c | 31 +++++++++++++++++++++++++++++++ 8 files changed, 66 insertions(+), 11 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bfd0889d13b..612e0205399 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2010-09-03 Jan Hubicka + + * cgraph.h (struct varpool_node): Add const_value_known. + (varpool_decide_const_value_known): Declare. + * tree-ssa-ccp.c (fold_const_aggregate_ref): Update initializer folding. + * lto-cgraph.c (lto_output_varpool_node): Store const_value_known. + (input_varpool_node): Restore const_value_known. + * tree-ssa-loop-ivcanon (constant_after_peeling): Check varpool for + initializer folding. + * ipa.c (ipa_discover_readonly_nonaddressable_var, + function_and_variable_visibility): Compute const_value_known. + * gimple-fold.c (get_symbol_constant_value): Use varpool for initializer + folding. + * varpool.c (varpool_decide_const_value_known): New function. + 2010-09-03 Uros Bizjak * config/i386/i386.md: Remove empty prepartion statements diff --git a/gcc/cgraph.h b/gcc/cgraph.h index f77a280d12f..c868d329542 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -503,6 +503,8 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node { During WPA output it is used to mark nodes that are present in multiple partitions. */ unsigned in_other_partition : 1; + /* True when variable is constant and its value is known. */ + unsigned int const_value_known : 1; }; /* Every top level asm statement is put into a cgraph_asm_node. */ @@ -726,6 +728,7 @@ void varpool_empty_needed_queue (void); bool varpool_extra_name_alias (tree, tree); const char * varpool_node_name (struct varpool_node *node); void varpool_reset_queue (void); +bool varpool_decide_const_value_known (struct varpool_node *node); /* Walk all reachable static variables. */ #define FOR_EACH_STATIC_VARIABLE(node) \ diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 8a48316f00d..033023a9fa7 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -38,9 +38,9 @@ along with GCC; see the file COPYING3. If not see tree get_symbol_constant_value (tree sym) { - if (TREE_STATIC (sym) - && (TREE_READONLY (sym) - || TREE_CODE (sym) == CONST_DECL)) + if ((TREE_STATIC (sym) || DECL_EXTERNAL (sym)) + && (TREE_CODE (sym) == CONST_DECL + || varpool_get_node (sym)->const_value_known)) { tree val = DECL_INITIAL (sym); if (val) @@ -65,8 +65,6 @@ get_symbol_constant_value (tree sym) have zero as the initializer if they may not be overridden at link or run time. */ if (!val - && !DECL_EXTERNAL (sym) - && targetm.binds_local_p (sym) && (INTEGRAL_TYPE_P (TREE_TYPE (sym)) || SCALAR_FLOAT_TYPE_P (TREE_TYPE (sym)))) return fold_convert (TREE_TYPE (sym), integer_zero_node); diff --git a/gcc/ipa.c b/gcc/ipa.c index 021398b6748..b199796fcdb 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -561,6 +561,7 @@ ipa_discover_readonly_nonaddressable_vars (void) if (dump_file) fprintf (dump_file, " %s (read-only)", varpool_node_name (vnode)); TREE_READONLY (vnode->decl) = 1; + vnode->const_value_known |= varpool_decide_const_value_known (vnode); } } if (dump_file) @@ -767,6 +768,9 @@ function_and_variable_visibility (bool whole_program) || ! (ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl)))))) DECL_COMMON (vnode->decl) = 0; + /* Even extern variables might have initializers known. + See, for example testsuite/g++.dg/opt/static3.C */ + vnode->const_value_known |= varpool_decide_const_value_known (vnode); } for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) { @@ -801,6 +805,7 @@ function_and_variable_visibility (bool whole_program) gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl)); cgraph_make_decl_local (vnode->decl); } + vnode->const_value_known |= varpool_decide_const_value_known (vnode); gcc_assert (TREE_STATIC (vnode->decl)); } pointer_set_destroy (aliased_nodes); diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 22b49161067..dac5c321814 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -575,6 +575,7 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node bp_pack_value (&bp, node->force_output, 1); bp_pack_value (&bp, node->finalized, 1); bp_pack_value (&bp, node->alias, 1); + bp_pack_value (&bp, node->const_value_known, 1); gcc_assert (!node->alias || !node->extra_name); gcc_assert (node->finalized || !node->analyzed); gcc_assert (node->needed); @@ -1106,6 +1107,7 @@ input_varpool_node (struct lto_file_decl_data *file_data, node->force_output = bp_unpack_value (&bp, 1); node->finalized = bp_unpack_value (&bp, 1); node->alias = bp_unpack_value (&bp, 1); + node->const_value_known = bp_unpack_value (&bp, 1); node->analyzed = node->finalized; node->used_from_other_partition = bp_unpack_value (&bp, 1); node->in_other_partition = bp_unpack_value (&bp, 1); diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 5551df2d5a3..8c42a633665 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -1348,7 +1348,8 @@ fold_const_aggregate_ref (tree t) case VAR_DECL: if (!TREE_READONLY (base) || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE - || !targetm.binds_local_p (base)) + || ((TREE_STATIC (base) || DECL_EXTERNAL (base)) + && !varpool_get_node (base)->const_value_known)) return NULL_TREE; ctor = DECL_INITIAL (base); @@ -1435,7 +1436,8 @@ fold_const_aggregate_ref (tree t) case VAR_DECL: if (!TREE_READONLY (base) || TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE - || !targetm.binds_local_p (base)) + || ((TREE_STATIC (base) || DECL_EXTERNAL (base)) + && !varpool_get_node (base)->const_value_known)) return NULL_TREE; ctor = DECL_INITIAL (base); @@ -1509,7 +1511,8 @@ fold_const_aggregate_ref (tree t) if (!TREE_READONLY (base) || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE - || !targetm.binds_local_p (base)) + || ((TREE_STATIC (base) || DECL_EXTERNAL (base)) + && !varpool_get_node (base)->const_value_known)) return NULL_TREE; ctor = DECL_INITIAL (base); diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c index b0d45bc4b41..2ced3070d48 100644 --- a/gcc/tree-ssa-loop-ivcanon.c +++ b/gcc/tree-ssa-loop-ivcanon.c @@ -165,9 +165,7 @@ constant_after_peeling (tree op, gimple stmt, struct loop *loop) if ((DECL_P (base) && TREE_STATIC (base) && TREE_READONLY (base) - && (DECL_INITIAL (base) - || (!DECL_EXTERNAL (base) - && targetm.binds_local_p (base)))) + && varpool_get_node (base)->const_value_known) || CONSTANT_CLASS_P (base)) { /* If so, see if we understand all the indices. */ diff --git a/gcc/varpool.c b/gcc/varpool.c index 817a3197901..eac488fa79b 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -359,6 +359,37 @@ decide_is_variable_needed (struct varpool_node *node, tree decl) return true; } +/* Return if NODE is constant and its initial value is known (so we can do + constant folding). The decision depends on whole program decisions + and can not be recomputed at ltrans stage for variables from other + partitions. For this reason the new value should be always combined + with the previous knowledge. */ + +bool +varpool_decide_const_value_known (struct varpool_node *node) +{ + tree decl = node->decl; + + gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl)); + gcc_assert (TREE_CODE (decl) == VAR_DECL); + if (!TREE_READONLY (decl)) + return false; + /* Variables declared 'const' without an initializer + have zero as the initializer if they may not be + overridden at link or run time. */ + if (!DECL_INITIAL (decl) + && (DECL_EXTERNAL (decl) + || DECL_REPLACEABLE_P (decl))) + return false; + + /* Variables declared `const' with an initializer are considered + to not be overwritable with different initializer by default. + + ??? Previously we behaved so for scalar variables but not for array + accesses. */ + return true; +} + /* Mark DECL as finalized. By finalizing the declaration, frontend instruct the middle end to output the variable to asm file, if needed or externally visible. */ -- 2.30.2