From 64e0f5ff1f3be1ddccc2a50cb371b5dce94124b1 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Mon, 20 Sep 2010 17:48:42 +0200 Subject: [PATCH] re PR tree-optimization/45605 (Missed devirtualization) PR tree-optimize/45605 * cgraph.h (const_value_known_p): Declare. (varpool_decide_const_value_known): Remove. * tree-ssa-ccp.c (get_base_constructor): Use it. * lto-cgraph.c (compute_ltrans_boundary): Likewise. * expr.c (string_constant): Likewise. * tree-ssa-loop-ivcanon.c (constant_after_peeling): Likewise. * ipa.c (ipa_discover_readonly_nonaddressable_var, function_and_variable_visibility): Likewise. * gimplify.c (gimplify_call_expr): Likewise. * gimple-fold.c (get_symbol_constant_value): Likewise. * varpool.c (varpool_decide_const_value_known): Replace by... (const_value_known_p): ... this one; handle other kinds of DECLs too and work for automatic vars. (varpool_finalize_decl): Use const_value_known_p. * lto.c (lto_promote_cross_file_statics): Use const_value_known_p. * g++.dg/tree-ssa/pr45605.C: New testcase. From-SVN: r164438 --- gcc/ChangeLog | 18 ++++++++++++ gcc/cgraph.h | 2 +- gcc/expr.c | 8 +---- gcc/gimple-fold.c | 4 +-- gcc/gimplify.c | 3 ++ gcc/ipa.c | 6 ++-- gcc/lto-cgraph.c | 3 +- gcc/lto/ChangeLog | 5 ++++ gcc/lto/lto.c | 2 +- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/g++.dg/tree-ssa/pr45605.C | 37 +++++++++++++++++++++++ gcc/tree-ssa-ccp.c | 4 +-- gcc/tree-ssa-loop-ivcanon.c | 6 ++-- gcc/varpool.c | 39 +++++++++++++++++++------ 14 files changed, 109 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr45605.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 648dc8efa4a..bb6ade73a11 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2010-09-20 Jan Hubicka + + PR tree-optimize/45605 + * cgraph.h (const_value_known_p): Declare. + (varpool_decide_const_value_known): Remove. + * tree-ssa-ccp.c (get_base_constructor): Use it. + * lto-cgraph.c (compute_ltrans_boundary): Likewise. + * expr.c (string_constant): Likewise. + * tree-ssa-loop-ivcanon.c (constant_after_peeling): Likewise. + * ipa.c (ipa_discover_readonly_nonaddressable_var, + function_and_variable_visibility): Likewise. + * gimplify.c (gimplify_call_expr): Likewise. + * gimple-fold.c (get_symbol_constant_value): Likewise. + * varpool.c (varpool_decide_const_value_known): Replace by... + (const_value_known_p): ... this one; handle other kinds of DECLs + too and work for automatic vars. + (varpool_finalize_decl): Use const_value_known_p. + 2010-09-20 Rafael Carre PR target/45726 diff --git a/gcc/cgraph.h b/gcc/cgraph.h index c868d329542..ec90894317e 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -728,7 +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); +bool const_value_known_p (tree); /* Walk all reachable static variables. */ #define FOR_EACH_STATIC_VARIABLE(node) \ diff --git a/gcc/expr.c b/gcc/expr.c index 16daddc370f..e99eabe6306 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -9851,16 +9851,10 @@ string_constant (tree arg, tree *ptr_offset) int length; /* Variables initialized to string literals can be handled too. */ - if (DECL_INITIAL (array) == NULL_TREE + if (!const_value_known_p (array) || TREE_CODE (DECL_INITIAL (array)) != STRING_CST) return 0; - /* If they are read-only, non-volatile and bind locally. */ - if (! TREE_READONLY (array) - || TREE_SIDE_EFFECTS (array) - || ! targetm.binds_local_p (array)) - return 0; - /* Avoid const char foo[4] = "abcde"; */ if (DECL_SIZE_UNIT (array) == NULL_TREE || TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 14031c8a960..8faadcc3752 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -122,9 +122,7 @@ canonicalize_constructor_val (tree cval) tree get_symbol_constant_value (tree sym) { - if ((TREE_STATIC (sym) || DECL_EXTERNAL (sym)) - && (TREE_CODE (sym) == CONST_DECL - || varpool_get_node (sym)->const_value_known)) + if (const_value_known_p (sym)) { tree val = DECL_INITIAL (sym); if (val) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 595316043c5..e5b011a6b79 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2479,8 +2479,11 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) { /* The CALL_EXPR in *EXPR_P is already in GIMPLE form, so all we have to do is replicate it as a GIMPLE_CALL tuple. */ + gimple_stmt_iterator gsi; call = gimple_build_call_from_tree (*expr_p); gimplify_seq_add_stmt (pre_p, call); + gsi = gsi_last (*pre_p); + fold_stmt (&gsi); *expr_p = NULL_TREE; } diff --git a/gcc/ipa.c b/gcc/ipa.c index e4835c1e03f..5ff7c149e15 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -570,7 +570,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); + vnode->const_value_known |= const_value_known_p (vnode->decl); } } if (dump_file) @@ -779,7 +779,7 @@ function_and_variable_visibility (bool whole_program) 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); + vnode->const_value_known |= const_value_known_p (vnode->decl); } for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) { @@ -814,7 +814,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); + vnode->const_value_known |= const_value_known_p (vnode->decl); gcc_assert (TREE_STATIC (vnode->decl)); } pointer_set_destroy (aliased_nodes); diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 22b35ee27ab..f009fccfe8c 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -813,8 +813,7 @@ compute_ltrans_boundary (struct lto_out_decl_state *state, if (DECL_INITIAL (vnode->decl) && !lto_varpool_encoder_encode_initializer_p (varpool_encoder, vnode) - && (DECL_IN_CONSTANT_POOL (vnode->decl) - || vnode->const_value_known)) + && const_value_known_p (vnode->decl)) { lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode); add_references (encoder, varpool_encoder, &vnode->ref_list); diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 59124ee3481..6aab1af6426 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,8 @@ +2010-09-20 Jan Hubicka + + PR tree-optimize/45605 + * lto.c (lto_promote_cross_file_statics): Use const_value_known_p. + 2010-09-18 Gerald Pfeifer * lto-elf.c (lto_obj_file_open): Also provide filename when diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 40816e51e8f..98a9387ce9d 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -1008,7 +1008,7 @@ lto_promote_cross_file_statics (void) from this partition that are not in this partition. This needs to be done recursively. */ for (vnode = varpool_nodes; vnode; vnode = vnode->next) - if ((vnode->const_value_known || DECL_IN_CONSTANT_POOL (vnode->decl)) + if (const_value_known_p (vnode->decl) && DECL_INITIAL (vnode->decl) && !varpool_node_in_set_p (vnode, vset) && referenced_from_this_partition_p (&vnode->ref_list, set, vset) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cef92c44b30..3d98cd951a9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-09-20 Jan Hubicka + + PR tree-optimize/45605 + * g++.dg/tree-ssa/pr45605.C: New testcase. + 2010-09-20 Michael Matz PR testsuite/45706 diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr45605.C b/gcc/testsuite/g++.dg/tree-ssa/pr45605.C new file mode 100644 index 00000000000..b47f91a133a --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr45605.C @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-ssa" } */ +extern "C" void abort(); +bool destructor_called = false; + +struct B { + virtual void Run(){}; +}; + +struct D : public B { + virtual void Run() + { + struct O { + ~O() { destructor_called = true; }; + } o; + + struct Raiser { + Raiser() throw( int ) {throw 1;}; + } raiser; + }; +}; + +int main() { + try { + D d; + static_cast(d).Run(); + } catch (...) {} + + if (!destructor_called) + abort (); +} + + + +/* We should devirtualize call to D::Run */ +/* { dg-final { scan-tree-dump-times "D::Run (" 1 "ssa"} } */ +/* { dg-final { cleanup-tree-dump "ssa" } } */ diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 42b8a58b9d3..cf4321aa038 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -1342,9 +1342,7 @@ get_base_constructor (tree base, tree *offset) switch (TREE_CODE (base)) { case VAR_DECL: - if (!TREE_READONLY (base) - || ((TREE_STATIC (base) || DECL_EXTERNAL (base)) - && !varpool_get_node (base)->const_value_known)) + if (!const_value_known_p (base)) return NULL_TREE; /* Fallthru. */ diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c index 2ced3070d48..187f53c7a66 100644 --- a/gcc/tree-ssa-loop-ivcanon.c +++ b/gcc/tree-ssa-loop-ivcanon.c @@ -162,10 +162,8 @@ constant_after_peeling (tree op, gimple stmt, struct loop *loop) /* First make fast look if we see constant array inside. */ while (handled_component_p (base)) base = TREE_OPERAND (base, 0); - if ((DECL_P (base) - && TREE_STATIC (base) - && TREE_READONLY (base) - && varpool_get_node (base)->const_value_known) + if ((DECL_P (base) == VAR_DECL + && const_value_known_p (base)) || CONSTANT_CLASS_P (base)) { /* If so, see if we understand all the indices. */ diff --git a/gcc/varpool.c b/gcc/varpool.c index 2b0809456ea..3ce3bac8ded 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -359,21 +359,42 @@ 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. */ +/* Return if DECL is constant and its initial value is known (so we can do + constant folding using DECL_INITIAL (decl)). */ bool -varpool_decide_const_value_known (struct varpool_node *node) +const_value_known_p (tree decl) { - tree decl = node->decl; + struct varpool_node *vnode; + + if (TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == RESULT_DECL) + return false; + + if (TREE_CODE (decl) == CONST_DECL + || DECL_IN_CONSTANT_POOL (decl)) + return true; - gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl)); gcc_assert (TREE_CODE (decl) == VAR_DECL); + if (!TREE_READONLY (decl)) return false; + + /* Gimplifier takes away constructors of local vars */ + if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) + return DECL_INITIAL (decl) != NULL; + + gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl)); + + /* In WHOPR mode we can put variable into one partition + and make it external in the other partition. In this + case we still know the value, but it can't be determined + from DECL flags. For this reason we keep const_value_known + flag in varpool nodes. */ + if ((vnode = varpool_get_node (decl)) + && vnode->const_value_known) + return true; + /* Variables declared 'const' without an initializer have zero as the initializer if they may not be overridden at link or run time. */ @@ -423,7 +444,7 @@ varpool_finalize_decl (tree decl) there. */ else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) varpool_mark_needed_node (node); - node->const_value_known |= varpool_decide_const_value_known (node); + node->const_value_known |= const_value_known_p (node->decl); if (cgraph_global_info_ready) varpool_assemble_pending_decls (); } -- 2.30.2