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
This commit is contained in:
Jan Hubicka 2010-09-20 17:48:42 +02:00 committed by Jan Hubicka
parent 4ce9b2b20f
commit 64e0f5ff1f
14 changed files with 109 additions and 33 deletions

View File

@ -1,3 +1,21 @@
2010-09-20 Jan Hubicka <jh@suse.cz>
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 <rafael.carre@gmail.com>
PR target/45726

View File

@ -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) \

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -1,3 +1,8 @@
2010-09-20 Jan Hubicka <jh@suse.cz>
PR tree-optimize/45605
* lto.c (lto_promote_cross_file_statics): Use const_value_known_p.
2010-09-18 Gerald Pfeifer <gerald@pfeifer.com>
* lto-elf.c (lto_obj_file_open): Also provide filename when

View File

@ -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)

View File

@ -1,3 +1,8 @@
2010-09-20 Jan Hubicka <jh@suse.cz>
PR tree-optimize/45605
* g++.dg/tree-ssa/pr45605.C: New testcase.
2010-09-20 Michael Matz <matz@suse.de>
PR testsuite/45706

View File

@ -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<B&>(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" } } */

View File

@ -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. */

View File

@ -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. */

View File

@ -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 ();
}