Makefile.in (ipa-devirt.o): Add dependency on diagnostic.h

* Makefile.in (ipa-devirt.o): Add dependency on diagnostic.h
	* ipa-devirt.c: Include diganostic.h
	(odr_type_d): Add types and types_set.
	(hash_type_name): Work for types with vtables during LTO.
	(odr_hasher::remove): Fix comment; destroy types_set.
	(add_type_duplicate): New function,
	(get_odr_type): Use it.
	(dump_type_inheritance_graph): Dump type duplicates.
	* ipa.c (symtab_remove_unreachable_nodes): Build type inheritance
	graph.
	* tree.c (types_same_for_odr): Give exact answers on types with
	virtual tables.

From-SVN: r202258
This commit is contained in:
Jan Hubicka 2013-09-04 16:14:28 +02:00 committed by Jan Hubicka
parent 24ba81955d
commit 61a74079b0
7 changed files with 258 additions and 14 deletions

View File

@ -1,3 +1,18 @@
2013-09-04 Jan Hubicka <jh@suse.cz>
* Makefile.in (ipa-devirt.o): Add dependency on diagnostic.h
* ipa-devirt.c: Include diganostic.h
(odr_type_d): Add types and types_set.
(hash_type_name): Work for types with vtables during LTO.
(odr_hasher::remove): Fix comment; destroy types_set.
(add_type_duplicate): New function,
(get_odr_type): Use it.
(dump_type_inheritance_graph): Dump type duplicates.
* ipa.c (symtab_remove_unreachable_nodes): Build type inheritance
graph.
* tree.c (types_same_for_odr): Give exact answers on types with
virtual tables.
2013-09-04 Dodji Seketeli <dodji@redhat.com>
* tree.h (DECL_BUILT_IN, DECL_IS_BUILTIN): Add more comments

View File

@ -2963,7 +2963,8 @@ ipa-profile.o : ipa-profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRA
ipa-inline.h
ipa-devirt.o : ipa-devirt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) \
$(GIMPLE_H) $(TARGET_H) $(GGC_H) pointer-set.h \
$(IPA_UTILS_H) $(HASH_TABLE_H) ipa-inline.h ipa-utils.h $(TREE_PRETTY_PRINT_H)
$(IPA_UTILS_H) $(HASH_TABLE_H) ipa-inline.h ipa-utils.h $(TREE_PRETTY_PRINT_H) \
$(DIAGNOSTIC_H)
ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(DIAGNOSTIC_H) \
$(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) \

View File

@ -119,6 +119,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-utils.h"
#include "gimple.h"
#include "ipa-inline.h"
#include "diagnostic.h"
/* Pointer set of all call targets appearing in the cache. */
static pointer_set_t *cached_polymorphic_call_targets;
@ -136,6 +137,11 @@ struct GTY(()) odr_type_d
/* All derrived types with virtual methods seen in unit. */
vec<odr_type> GTY((skip)) derived_types;
/* All equivalent types, if more than one. */
vec<tree, va_gc> *types;
/* Set of all equivalent types, if NON-NULL. */
pointer_set_t * GTY((skip)) types_set;
/* Unique ID indexing the type in odr_types array. */
int id;
/* Is it in anonymous namespace? */
@ -185,6 +191,26 @@ hash_type_name (tree t)
if (type_in_anonymous_namespace_p (t))
return htab_hash_pointer (t);
/* For polymorphic types, we can simply hash the virtual table. */
if (TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t)))
{
tree v = BINFO_VTABLE (TYPE_BINFO (t));
hashval_t hash = 0;
if (TREE_CODE (v) == POINTER_PLUS_EXPR)
{
hash = TREE_INT_CST_LOW (TREE_OPERAND (v, 1));
v = TREE_OPERAND (TREE_OPERAND (v, 0), 0);
}
v = DECL_ASSEMBLER_NAME (v);
#ifdef ENABLE_CHECKING
gcc_assert (!strchr (IDENTIFIER_POINTER (v), '.'));
#endif
hash = iterative_hash_hashval_t (hash, htab_hash_pointer (v));
return hash;
}
/* Rest is not implemented yet. */
gcc_unreachable ();
}
@ -220,6 +246,8 @@ odr_hasher::remove (value_type *v)
{
v->bases.release ();
v->derived_types.release ();
if (v->types_set)
pointer_set_destroy (v->types_set);
ggc_free (v);
}
@ -235,6 +263,132 @@ static odr_hash_type odr_hash;
static GTY(()) vec <odr_type, va_gc> *odr_types_ptr;
#define odr_types (*odr_types_ptr)
/* TYPE is equivalent to VAL by ODR, but its tree representation differs
from VAL->type. This may happen in LTO where tree merging did not merge
all variants of the same type. It may or may not mean the ODR violation.
Add it to the list of duplicates and warn on some violations. */
static void
add_type_duplicate (odr_type val, tree type)
{
if (!val->types_set)
val->types_set = pointer_set_create ();
/* See if this duplicate is new. */
if (!pointer_set_insert (val->types_set, type))
{
bool merge = true;
bool base_mismatch = false;
gcc_assert (in_lto_p);
vec_safe_push (val->types, type);
unsigned int i,j;
/* First we compare memory layout. */
if (!types_compatible_p (val->type, type))
{
merge = false;
if (BINFO_VTABLE (TYPE_BINFO (val->type))
&& warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0,
"type %qD violates one definition rule ",
type))
inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)),
"a type with the same name but different layout is "
"defined in another translation unit");
debug_tree (BINFO_VTABLE (TYPE_BINFO (type)));
debug_tree (BINFO_VTABLE (TYPE_BINFO (val->type)));
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file, "ODR violation or merging or ODR type bug?\n");
print_node (cgraph_dump_file, "", val->type, 0);
putc ('\n',cgraph_dump_file);
print_node (cgraph_dump_file, "", type, 0);
putc ('\n',cgraph_dump_file);
}
}
/* Next sanity check that bases are the same. If not, we will end
up producing wrong answers. */
for (j = 0, i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++)
if (polymorphic_type_binfo_p (BINFO_BASE_BINFO (TYPE_BINFO (type), i)))
{
odr_type base = get_odr_type
(BINFO_TYPE
(BINFO_BASE_BINFO (TYPE_BINFO (type),
i)),
true);
if (val->bases.length () <= j || val->bases[j] != base)
base_mismatch = true;
j++;
}
if (base_mismatch)
{
merge = false;
if (warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (type)), 0,
"type %qD violates one definition rule ",
type))
inform (DECL_SOURCE_LOCATION (TYPE_NAME (val->type)),
"a type with the same name but different bases is "
"defined in another translation unit");
if (cgraph_dump_file)
{
fprintf (cgraph_dump_file, "ODR bse violation or merging bug?\n");
print_node (cgraph_dump_file, "", val->type, 0);
putc ('\n',cgraph_dump_file);
print_node (cgraph_dump_file, "", type, 0);
putc ('\n',cgraph_dump_file);
}
}
/* Regularize things a little. During LTO same types may come with
different BINFOs. Either because their virtual table was
not merged by tree merging and only later at decl merging or
because one type comes with external vtable, while other
with internal. We want to merge equivalent binfos to conserve
memory and streaming overhead.
The external vtables are more harmful: they contain references
to external declarations of methods that may be defined in the
merged LTO unit. For this reason we absolutely need to remove
them and replace by internal variants. Not doing so will lead
to incomplete answers from possible_polymorphic_call_targets. */
if (!flag_ltrans && merge)
{
tree master_binfo = TYPE_BINFO (val->type);
tree v1 = BINFO_VTABLE (master_binfo);
tree v2 = BINFO_VTABLE (TYPE_BINFO (type));
if (TREE_CODE (v1) == POINTER_PLUS_EXPR)
{
gcc_assert (TREE_CODE (v2) == POINTER_PLUS_EXPR
&& operand_equal_p (TREE_OPERAND (v1, 1),
TREE_OPERAND (v2, 1), 0));
v1 = TREE_OPERAND (TREE_OPERAND (v1, 0), 0);
v2 = TREE_OPERAND (TREE_OPERAND (v2, 0), 0);
}
gcc_assert (DECL_ASSEMBLER_NAME (v1)
== DECL_ASSEMBLER_NAME (v2));
if (DECL_EXTERNAL (v1) && !DECL_EXTERNAL (v2))
{
unsigned int i;
TYPE_BINFO (val->type) = TYPE_BINFO (type);
for (i = 0; i < val->types->length(); i++)
{
if (TYPE_BINFO ((*val->types)[i])
== master_binfo)
TYPE_BINFO ((*val->types)[i]) = TYPE_BINFO (type);
}
}
else
TYPE_BINFO (type) = master_binfo;
}
}
}
/* Get ODR type hash entry for TYPE. If INSERT is true, create
possibly new entry. */
@ -257,11 +411,10 @@ get_odr_type (tree type, bool insert)
{
val = *slot;
/* With LTO we will need to support multiple tree representation of
the same ODR type. For now we ignore this. */
if (val->type == type)
return val;
gcc_unreachable ();
/* With LTO we need to support multiple tree representation of
the same ODR type. */
if (val->type != type)
add_type_duplicate (val, type);
}
else
{
@ -340,6 +493,28 @@ dump_type_inheritance_graph (FILE *f)
if (odr_types[i]->bases.length() == 0)
dump_odr_type (f, odr_types[i]);
}
for (i = 0; i < odr_types.length(); i++)
{
if (odr_types[i]->types && odr_types[i]->types->length())
{
unsigned int j;
fprintf (f, "Duplicate tree types for odr type %i\n", i);
print_node (f, "", odr_types[i]->type, 0);
for (j = 0; j < odr_types[i]->types->length(); j++)
{
tree t;
fprintf (f, "duplicate #%i\n", j);
print_node (f, "", (*odr_types[i]->types)[j], 0);
t = (*odr_types[i]->types)[j];
while (TYPE_P (t) && TYPE_CONTEXT (t))
{
t = TYPE_CONTEXT (t);
print_node (f, "", t, 0);
}
putc ('\n',f);
}
}
}
}
/* Given method type T, return type of class it belongs to.

View File

@ -218,6 +218,8 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
#ifdef ENABLE_CHECKING
verify_symtab ();
#endif
if (optimize && flag_devirtualize)
build_type_inheritance_graph ();
if (file)
fprintf (file, "\nReclaiming functions:");
#ifdef ENABLE_CHECKING

View File

@ -124,8 +124,11 @@ output_type_ref (struct output_block *ob, tree node)
static bool
tree_is_indexable (tree t)
{
/* Parameters and return values of functions of variably modified types
must go to global stream, because they may be used in the type
definition. */
if (TREE_CODE (t) == PARM_DECL || TREE_CODE (t) == RESULT_DECL)
return false;
return variably_modified_type_p (TREE_TYPE (DECL_CONTEXT (t)), NULL_TREE);
else if (TREE_CODE (t) == VAR_DECL && decl_function_context (t)
&& !TREE_STATIC (t))
return false;

View File

@ -232,8 +232,22 @@ bool
probably_never_executed_bb_p (struct function *fun, const_basic_block bb)
{
gcc_checking_assert (fun);
if (profile_info && flag_branch_probabilities)
return ((bb->count + profile_info->runs / 2) / profile_info->runs) == 0;
if (profile_status_for_function (fun) == PROFILE_READ)
{
if ((bb->count * 4 + profile_info->runs / 2) / profile_info->runs > 0)
return false;
if (!bb->frequency)
return true;
if (!ENTRY_BLOCK_PTR->frequency)
return false;
if (ENTRY_BLOCK_PTR->count && ENTRY_BLOCK_PTR->count < REG_BR_PROB_BASE)
{
return (RDIV (bb->frequency * ENTRY_BLOCK_PTR->count,
ENTRY_BLOCK_PTR->frequency)
< REG_BR_PROB_BASE / 4);
}
return true;
}
if ((!profile_info || !flag_branch_probabilities)
&& (cgraph_get_node (fun->decl)->frequency
== NODE_FREQUENCY_UNLIKELY_EXECUTED))

View File

@ -11853,11 +11853,6 @@ types_same_for_odr (tree type1, tree type2)
if (type1 == type2)
return true;
/* If types are not structuraly same, do not bother to contnue.
Match in the remainder of code would mean ODR violation. */
if (!types_compatible_p (type1, type2))
return false;
#ifndef ENABLE_CHECKING
if (!in_lto_p)
return false;
@ -11868,7 +11863,46 @@ types_same_for_odr (tree type1, tree type2)
if (type_in_anonymous_namespace_p (type1)
|| type_in_anonymous_namespace_p (type2))
return false;
/* When assembler name of virtual table is available, it is
easy to compare types for equivalence. */
if (TYPE_BINFO (type1) && TYPE_BINFO (type2)
&& BINFO_VTABLE (TYPE_BINFO (type1))
&& BINFO_VTABLE (TYPE_BINFO (type2)))
{
tree v1 = BINFO_VTABLE (TYPE_BINFO (type1));
tree v2 = BINFO_VTABLE (TYPE_BINFO (type2));
if (TREE_CODE (v1) == POINTER_PLUS_EXPR)
{
if (TREE_CODE (v2) != POINTER_PLUS_EXPR
|| !operand_equal_p (TREE_OPERAND (v1, 1),
TREE_OPERAND (v2, 1), 0))
return false;
v1 = TREE_OPERAND (TREE_OPERAND (v1, 0), 0);
v2 = TREE_OPERAND (TREE_OPERAND (v2, 0), 0);
}
v1 = DECL_ASSEMBLER_NAME (v1);
v2 = DECL_ASSEMBLER_NAME (v2);
/* If we ever start adding random .blah suffixes after
assembler names, we need to compare for match ignoring
these (and update odr_type_hash, too). */
#ifdef ENABLE_CHECKING
gcc_assert (!strchr (IDENTIFIER_POINTER (v1), '.')
&& !strchr (IDENTIFIER_POINTER (v2), '.'));
#endif
return (v1 == v2);
}
/* FIXME: the code comparing type names consider all instantiations of the
same template to have same name. This is because we have no access
to template parameters. For types with no virtual method tables
we thus can return false positives. At the moment we do not need
to compare types in other scenarios than devirtualization. */
/* If types are not structuraly same, do not bother to contnue.
Match in the remainder of code would mean ODR violation. */
if (!types_compatible_p (type1, type2))
return false;
if (!TYPE_NAME (type1))
return false;
if (!decls_same_for_odr (TYPE_NAME (type1), TYPE_NAME (type2)))