Commit eefe9a99 by Jan Hubicka Committed by Jan Hubicka

Makeifle-in (ipa-devirt.o): New.


	* Makeifle-in (ipa-devirt.o): New.
	(GTFILES): Add ipa-utils.h and ipa-devirt.c
	* cgraphunit.c (decide_is_symbol_needed): Do not care about virtuals.
	(analyze_functions): Look into possible targets of polymorphic call.
	* dumpfile.c (dump_files): Add type-inheritance dump.
	* dumpfile.h (TDI_inheritance): New.
	* ipa-devirt.c: New file.
	* ipa-utils.h (odr_type_d): Forward declare.
	(odr_type): New type.
	(build_type_inheritance_graph): Declare.
	(possible_polymorphic_call_targets): Declare and introduce inline
	variant when only edge is pased.
	(dump_possible_polymorphic_call_targets): Likewise.
	* timevar.def (TV_IPA_INHERITANCE, TV_IPA_VIRTUAL_CALL): New.
	* tree.c (type_in_anonymous_namespace_p): Break out from ...
	(types_same_for_odr): ... here.
	* tree.h (type_in_anonymous_namespace_p): Declare.

	* g++.dg/ipa/type-inheritance-1.C: New testcase.

From-SVN: r201836
parent 5eb5ec2f
2013-08-18 Jan Hubicka <jh@suse.cz>
* Makeifle-in (ipa-devirt.o): New.
(GTFILES): Add ipa-utils.h and ipa-devirt.c
* cgraphunit.c (decide_is_symbol_needed): Do not care about virtuals.
(analyze_functions): Look into possible targets of polymorphic call.
* dumpfile.c (dump_files): Add type-inheritance dump.
* dumpfile.h (TDI_inheritance): New.
* ipa-devirt.c: New file.
* ipa-utils.h (odr_type_d): Forward declare.
(odr_type): New type.
(build_type_inheritance_graph): Declare.
(possible_polymorphic_call_targets): Declare and introduce inline
variant when only edge is pased.
(dump_possible_polymorphic_call_targets): Likewise.
* timevar.def (TV_IPA_INHERITANCE, TV_IPA_VIRTUAL_CALL): New.
* tree.c (type_in_anonymous_namespace_p): Break out from ...
(types_same_for_odr): ... here.
* tree.h (type_in_anonymous_namespace_p): Declare.
2013-08-18 Jakub Jelinek <jakub@redhat.com> 2013-08-18 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/58006 PR tree-optimization/58006
......
...@@ -1275,6 +1275,7 @@ OBJS = \ ...@@ -1275,6 +1275,7 @@ OBJS = \
init-regs.o \ init-regs.o \
internal-fn.o \ internal-fn.o \
ipa-cp.o \ ipa-cp.o \
ipa-devirt.o \
ipa-split.o \ ipa-split.o \
ipa-inline.o \ ipa-inline.o \
ipa-inline-analysis.o \ ipa-inline-analysis.o \
...@@ -2945,6 +2946,9 @@ ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) \ ...@@ -2945,6 +2946,9 @@ ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) \
$(TREE_PASS_H) $(GIMPLE_H) $(TARGET_H) $(GGC_H) pointer-set.h \ $(TREE_PASS_H) $(GIMPLE_H) $(TARGET_H) $(GGC_H) pointer-set.h \
$(IPA_UTILS_H) tree-inline.h $(HASH_TABLE_H) profile.h $(PARAMS_H) \ $(IPA_UTILS_H) tree-inline.h $(HASH_TABLE_H) profile.h $(PARAMS_H) \
$(LTO_STREAMER_H) $(DATA_STREAMER_H) $(LTO_STREAMER_H) $(DATA_STREAMER_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-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.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) \ 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) \ $(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) \
...@@ -3784,7 +3788,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ ...@@ -3784,7 +3788,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \ $(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \
$(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \ $(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \
$(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \
$(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c \ $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-utils.h \
$(srcdir)/dbxout.c \ $(srcdir)/dbxout.c \
$(srcdir)/dwarf2out.h \ $(srcdir)/dwarf2out.h \
$(srcdir)/dwarf2asm.c \ $(srcdir)/dwarf2asm.c \
...@@ -3826,7 +3830,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ ...@@ -3826,7 +3830,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/ipa-inline.h \ $(srcdir)/ipa-inline.h \
$(srcdir)/vtable-verify.c \ $(srcdir)/vtable-verify.c \
$(srcdir)/asan.c \ $(srcdir)/asan.c \
$(srcdir)/tsan.c \ $(srcdir)/tsan.c $(srcdir)/ipa-devirt.c \
@all_gtfiles@ @all_gtfiles@
# Compute the list of GT header files from the corresponding C sources, # Compute the list of GT header files from the corresponding C sources,
......
...@@ -1292,10 +1292,13 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e) ...@@ -1292,10 +1292,13 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
struct ipa_ref *ref; struct ipa_ref *ref;
cgraph_speculative_call_info (e, e, e2, ref); cgraph_speculative_call_info (e, e, e2, ref);
if (gimple_call_fndecl (e->call_stmt)) /* If there already is an direct call (i.e. as a result of inliner's substitution),
e = cgraph_resolve_speculation (e, gimple_call_fndecl (e->call_stmt)); forget about speculating. */
if (!gimple_check_call_matching_types (e->call_stmt, e->callee->symbol.decl, if (decl)
true)) e = cgraph_resolve_speculation (e, decl);
/* If types do not match, speculation was likely wrong. */
else if (!gimple_check_call_matching_types (e->call_stmt, e->callee->symbol.decl,
true))
{ {
e = cgraph_resolve_speculation (e, NULL); e = cgraph_resolve_speculation (e, NULL);
if (dump_file) if (dump_file)
...@@ -1304,6 +1307,7 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e) ...@@ -1304,6 +1307,7 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
xstrdup (cgraph_node_name (e->caller)), e->caller->symbol.order, xstrdup (cgraph_node_name (e->caller)), e->caller->symbol.order,
xstrdup (cgraph_node_name (e->callee)), e->callee->symbol.order); xstrdup (cgraph_node_name (e->callee)), e->callee->symbol.order);
} }
/* Expand speculation into GIMPLE code. */
else else
{ {
if (dump_file) if (dump_file)
......
...@@ -235,10 +235,6 @@ decide_is_symbol_needed (symtab_node node) ...@@ -235,10 +235,6 @@ decide_is_symbol_needed (symtab_node node)
if (!node->symbol.definition) if (!node->symbol.definition)
return false; return false;
/* Devirtualization may access these. */
if (DECL_VIRTUAL_P (decl) && optimize)
return true;
if (DECL_EXTERNAL (decl)) if (DECL_EXTERNAL (decl))
return false; return false;
...@@ -838,6 +834,7 @@ analyze_functions (void) ...@@ -838,6 +834,7 @@ analyze_functions (void)
struct cgraph_node *first_handled = first_analyzed; struct cgraph_node *first_handled = first_analyzed;
static struct varpool_node *first_analyzed_var; static struct varpool_node *first_analyzed_var;
struct varpool_node *first_handled_var = first_analyzed_var; struct varpool_node *first_handled_var = first_analyzed_var;
struct pointer_set_t *reachable_call_targets = pointer_set_create ();
symtab_node node, next; symtab_node node, next;
int i; int i;
...@@ -853,6 +850,8 @@ analyze_functions (void) ...@@ -853,6 +850,8 @@ analyze_functions (void)
FOR_EACH_SYMBOL (node) FOR_EACH_SYMBOL (node)
if (node->symbol.cpp_implicit_alias) if (node->symbol.cpp_implicit_alias)
fixup_same_cpp_alias_visibility (node, symtab_alias_target (node)); fixup_same_cpp_alias_visibility (node, symtab_alias_target (node));
if (optimize && flag_devirtualize)
build_type_inheritance_graph ();
/* Analysis adds static variables that in turn adds references to new functions. /* Analysis adds static variables that in turn adds references to new functions.
So we need to iterate the process until it stabilize. */ So we need to iterate the process until it stabilize. */
...@@ -875,6 +874,8 @@ analyze_functions (void) ...@@ -875,6 +874,8 @@ analyze_functions (void)
changed = true; changed = true;
if (cgraph_dump_file) if (cgraph_dump_file)
fprintf (cgraph_dump_file, " %s", symtab_node_asm_name (node)); fprintf (cgraph_dump_file, " %s", symtab_node_asm_name (node));
if (!changed && cgraph_dump_file)
fprintf (cgraph_dump_file, "\n");
} }
if (node == (symtab_node)first_analyzed if (node == (symtab_node)first_analyzed
|| node == (symtab_node)first_analyzed_var) || node == (symtab_node)first_analyzed_var)
...@@ -919,6 +920,29 @@ analyze_functions (void) ...@@ -919,6 +920,29 @@ analyze_functions (void)
for (edge = cnode->callees; edge; edge = edge->next_callee) for (edge = cnode->callees; edge; edge = edge->next_callee)
if (edge->callee->symbol.definition) if (edge->callee->symbol.definition)
enqueue_node ((symtab_node)edge->callee); enqueue_node ((symtab_node)edge->callee);
if (optimize && flag_devirtualize)
{
for (edge = cnode->indirect_calls; edge; edge = edge->next_callee)
if (edge->indirect_info->polymorphic)
{
unsigned int i;
void *cache_token;
vec <cgraph_node *>targets
= possible_polymorphic_call_targets
(edge, NULL, &cache_token);
if (!pointer_set_insert (reachable_call_targets,
cache_token))
{
if (cgraph_dump_file)
dump_possible_polymorphic_call_targets
(cgraph_dump_file, edge);
for (i = 0; i < targets.length(); i++)
enqueue_node ((symtab_node) targets[i]);
}
}
}
/* If decl is a clone of an abstract function, /* If decl is a clone of an abstract function,
mark that abstract function so that we don't release its body. mark that abstract function so that we don't release its body.
...@@ -999,6 +1023,7 @@ analyze_functions (void) ...@@ -999,6 +1023,7 @@ analyze_functions (void)
dump_symtab (cgraph_dump_file); dump_symtab (cgraph_dump_file);
} }
bitmap_obstack_release (NULL); bitmap_obstack_release (NULL);
pointer_set_destroy (reachable_call_targets);
ggc_collect (); ggc_collect ();
} }
......
...@@ -52,6 +52,8 @@ static struct dump_file_info dump_files[TDI_end] = ...@@ -52,6 +52,8 @@ static struct dump_file_info dump_files[TDI_end] =
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0}, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0},
{".cgraph", "ipa-cgraph", NULL, NULL, NULL, NULL, NULL, TDF_IPA, {".cgraph", "ipa-cgraph", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
0, 0, 0, 0, 0}, 0, 0, 0, 0, 0},
{".type-inheritance", "ipa-type-inheritance", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
0, 0, 0, 0, 0},
{".tu", "translation-unit", NULL, NULL, NULL, NULL, NULL, TDF_TREE, {".tu", "translation-unit", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
0, 0, 0, 0, 1}, 0, 0, 0, 0, 1},
{".class", "class-hierarchy", NULL, NULL, NULL, NULL, NULL, TDF_TREE, {".class", "class-hierarchy", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
......
...@@ -29,6 +29,7 @@ enum tree_dump_index ...@@ -29,6 +29,7 @@ enum tree_dump_index
{ {
TDI_none, /* No dump */ TDI_none, /* No dump */
TDI_cgraph, /* dump function call graph. */ TDI_cgraph, /* dump function call graph. */
TDI_inheritance, /* dump type inheritance graph. */
TDI_tu, /* dump the whole translation unit. */ TDI_tu, /* dump the whole translation unit. */
TDI_class, /* dump class hierarchy. */ TDI_class, /* dump class hierarchy. */
TDI_original, /* dump each function before optimizing it */ TDI_original, /* dump each function before optimizing it */
......
...@@ -36,7 +36,6 @@ struct ipa_dfs_info { ...@@ -36,7 +36,6 @@ struct ipa_dfs_info {
}; };
/* In ipa-utils.c */ /* In ipa-utils.c */
void ipa_print_order (FILE*, const char *, struct cgraph_node**, int); void ipa_print_order (FILE*, const char *, struct cgraph_node**, int);
int ipa_reduced_postorder (struct cgraph_node **, bool, bool, int ipa_reduced_postorder (struct cgraph_node **, bool, bool,
...@@ -46,7 +45,48 @@ vec<cgraph_node_ptr> ipa_get_nodes_in_cycle (struct cgraph_node *); ...@@ -46,7 +45,48 @@ vec<cgraph_node_ptr> ipa_get_nodes_in_cycle (struct cgraph_node *);
int ipa_reverse_postorder (struct cgraph_node **); int ipa_reverse_postorder (struct cgraph_node **);
tree get_base_var (tree); tree get_base_var (tree);
/* In ipa-devirt.c */
struct odr_type_d;
typedef odr_type_d *odr_type;
void build_type_inheritance_graph (void);
vec <cgraph_node *>
possible_polymorphic_call_targets (tree, HOST_WIDE_INT,
bool *final = NULL,
void **cache_token = NULL);
odr_type get_odr_type (tree, bool insert = false);
void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT);
/* Return vector containing possible targets of polymorphic call E.
If FINALP is non-NULL, store true if the list is complette.
CACHE_TOKEN (if non-NULL) will get stored to an unique ID of entry
in the target cache. If user needs to visit every target list
just once, it can memoize them.
Returned vector is placed into cache. It is NOT caller's responsibility
to free it. The vector can be freed on cgraph_remove_node call if
the particular node is a virtual function present in the cache. */
inline vec <cgraph_node *>
possible_polymorphic_call_targets (struct cgraph_edge *e,
bool *final = NULL,
void **cache_token = NULL)
{
gcc_checking_assert (e->indirect_info->polymorphic);
return possible_polymorphic_call_targets (e->indirect_info->otr_type,
e->indirect_info->otr_token,
final, cache_token);
}
/* Dump possible targets of a polymorphic call E into F. */
inline void
dump_possible_polymorphic_call_targets (FILE *f, struct cgraph_edge *e)
{
gcc_checking_assert (e->indirect_info->polymorphic);
dump_possible_polymorphic_call_targets (f, e->indirect_info->otr_type,
e->indirect_info->otr_token);
}
#endif /* GCC_IPA_UTILS_H */ #endif /* GCC_IPA_UTILS_H */
2013-08-18 Jan Hubicka <jh@suse.cz>
* g++.dg/ipa/type-inheritance-1.C: New testcase.
2013-08-19 Janus Weil <janus@gcc.gnu.org> 2013-08-19 Janus Weil <janus@gcc.gnu.org>
PR fortran/46271 PR fortran/46271
......
/* Verify that callgraph construction keeps FOO for possible devirtualization
and removes BAR. */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-ipa-visibility" } */
extern "C" void abort (void);
class A
{
public:
virtual int foo (void)
{
return 4;
}
virtual int bar (void)
{
return 5;
}
};
int t(class A *a)
{
return a->foo();
}
/* { dg-final { scan-ipa-dump "A::foo" "visibility" } } */
/* { dg-final { scan-ipa-dump-not "A::bar" "visibility" } } */
/* { dg-final { cleanup-ipa-dump "visibility" } } */
...@@ -64,6 +64,8 @@ DEFTIMEVAR (TV_PCH_CPP_RESTORE , "PCH preprocessor state restore") ...@@ -64,6 +64,8 @@ DEFTIMEVAR (TV_PCH_CPP_RESTORE , "PCH preprocessor state restore")
DEFTIMEVAR (TV_CGRAPH , "callgraph construction") DEFTIMEVAR (TV_CGRAPH , "callgraph construction")
DEFTIMEVAR (TV_CGRAPHOPT , "callgraph optimization") DEFTIMEVAR (TV_CGRAPHOPT , "callgraph optimization")
DEFTIMEVAR (TV_IPA_INHERITANCE , "ipa inheritance graph")
DEFTIMEVAR (TV_IPA_VIRTUAL_CALL , "ipa virtual call target")
DEFTIMEVAR (TV_IPA_CONSTANT_PROP , "ipa cp") DEFTIMEVAR (TV_IPA_CONSTANT_PROP , "ipa cp")
DEFTIMEVAR (TV_IPA_INLINING , "ipa inlining heuristics") DEFTIMEVAR (TV_IPA_INLINING , "ipa inlining heuristics")
DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting") DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting")
......
...@@ -11845,11 +11845,8 @@ types_same_for_odr (tree type1, tree type2) ...@@ -11845,11 +11845,8 @@ types_same_for_odr (tree type1, tree type2)
/* Check for anonymous namespaces. Those have !TREE_PUBLIC /* Check for anonymous namespaces. Those have !TREE_PUBLIC
on the corresponding TYPE_STUB_DECL. */ on the corresponding TYPE_STUB_DECL. */
if (TYPE_STUB_DECL (type1) != TYPE_STUB_DECL (type2) if (type_in_anonymous_namespace_p (type1)
&& (!TYPE_STUB_DECL (type1) || type_in_anonymous_namespace_p (type2))
|| !TYPE_STUB_DECL (type2)
|| !TREE_PUBLIC (TYPE_STUB_DECL (type1))
|| !TREE_PUBLIC (TYPE_STUB_DECL (type2))))
return false; return false;
if (!TYPE_NAME (type1)) if (!TYPE_NAME (type1))
...@@ -11904,6 +11901,14 @@ obj_type_ref_class (tree ref) ...@@ -11904,6 +11901,14 @@ obj_type_ref_class (tree ref)
return TREE_TYPE (ref); return TREE_TYPE (ref);
} }
/* Return true if T is in anonymous namespace. */
bool
type_in_anonymous_namespace_p (tree t)
{
return (TYPE_STUB_DECL (t) && !TREE_PUBLIC (TYPE_STUB_DECL (t)));
}
/* Try to find a base info of BINFO that would have its field decl at offset /* Try to find a base info of BINFO that would have its field decl at offset
OFFSET within the BINFO type and which is of EXPECTED_TYPE. If it can be OFFSET within the BINFO type and which is of EXPECTED_TYPE. If it can be
found, return, otherwise return NULL_TREE. */ found, return, otherwise return NULL_TREE. */
......
...@@ -5980,6 +5980,7 @@ extern bool types_same_for_odr (tree type1, tree type2); ...@@ -5980,6 +5980,7 @@ extern bool types_same_for_odr (tree type1, tree type2);
extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *, extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *,
HOST_WIDE_INT *, HOST_WIDE_INT *); HOST_WIDE_INT *, HOST_WIDE_INT *);
extern bool contains_bitfld_component_ref_p (const_tree); extern bool contains_bitfld_component_ref_p (const_tree);
extern bool type_in_anonymous_namespace_p (tree);
/* In tree-nested.c */ /* In tree-nested.c */
extern tree build_addr (tree, tree); extern tree build_addr (tree, tree);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment