summaryrefslogtreecommitdiff
path: root/gcc/ipa-devirt.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2013-09-04 14:14:28 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2013-09-04 14:14:28 +0000
commit4befb9f45e01a38d5cf225ca9d2d3e0b7a60c653 (patch)
tree37a2f18b9ddc64a6fda6a6cc4c075c72734d0ce7 /gcc/ipa-devirt.c
parent2f90489d16664569d24c3bc621f4cd99b49c1180 (diff)
downloadgcc-4befb9f45e01a38d5cf225ca9d2d3e0b7a60c653.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202258 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ipa-devirt.c')
-rw-r--r--gcc/ipa-devirt.c185
1 files changed, 180 insertions, 5 deletions
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index f9a5ae3f7a1..743f30ca5ee 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -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.