mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-24 11:24:05 +08:00
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:
parent
4ce9b2b20f
commit
64e0f5ff1f
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
37
gcc/testsuite/g++.dg/tree-ssa/pr45605.C
Normal file
37
gcc/testsuite/g++.dg/tree-ssa/pr45605.C
Normal 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" } } */
|
@ -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. */
|
||||
|
@ -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. */
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user