Here it is again, without the DECL_COMDAT pieces; now that patch is in, this becomes just an optimization to improve devirtualization.

As you said before, because of caching we might miss new overrides that are introduced as a result of instantiating/synthesizing one of the overrides on the first pass. This seems likely to be rare, so perhaps it's not worth worrying about. What do you think?

Jason
commit 0271948001ca26f068935b04d13155a25c979af8
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Jul 29 12:42:51 2014 -0400

    gcc/
    	* ipa-devirt.c (possible_polymorphic_call_targets): Add overload
    	taking a single tree.
    	* ipa-utils.h: Declare it.
    gcc/cp/
    	* call.c (build_over_call): Call note_fn_called_virtually.
    	* class.c (get_vtable_decl): Create a varpool node.
    	* cp-tree.h (FNDECL_CALLED_VIRTUALLY): New.
    	* decl2.c (fns_called_virtually, note_fn_called_virtually): New.
    	(mark_virtual_overrides): New.
    	(cp_write_global_declarations): Call it.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4d37c65..969e730 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7364,6 +7364,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 				ba_any, NULL, complain);
       gcc_assert (binfo && binfo != error_mark_node);
 
+      note_fn_called_virtually (fn);
+
       /* Warn about deprecated virtual functions now, since we're about
 	 to throw away the decl.  */
       if (TREE_DEPRECATED (fn))
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 235c68a..1401069 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -817,6 +817,9 @@ get_vtable_decl (tree type, int complete)
   decl = build_vtable (type, get_vtable_name (type), vtbl_type_node);
   CLASSTYPE_VTABLES (type) = decl;
 
+  /* Make the vtable visible to build_type_inheritance_graph.  */
+  varpool_node::get_create (decl);
+
   if (complete)
     {
       DECL_EXTERNAL (decl) = 1;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0c0d804..c9f248a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -109,6 +109,7 @@ c-common.h, not after.
       BIND_EXPR_BODY_BLOCK (in BIND_EXPR)
       DECL_NON_TRIVIALLY_INITIALIZED_P (in VAR_DECL)
       CALL_EXPR_LIST_INIT_P (in CALL_EXPR, AGGR_INIT_EXPR)
+      FNDECL_CALLED_VIRTUALLY (in FUNCTION_DECL)
    4: TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
 	  or FIELD_DECL).
       IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE)
@@ -3222,6 +3223,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define FNDECL_USED_AUTO(NODE) \
   TREE_LANG_FLAG_2 (FUNCTION_DECL_CHECK (NODE))
 
+/* True if NODE was called through the vtable; used to avoid duplicates in
+   fns_called_virtually.  */
+#define FNDECL_CALLED_VIRTUALLY(NODE) \
+  TREE_LANG_FLAG_3 (FUNCTION_DECL_CHECK (NODE))
+
 /* Nonzero if NODE is a DECL which we know about but which has not
    been explicitly declared, such as a built-in function or a friend
    declared inside a class.  In the latter case DECL_HIDDEN_FRIEND_P
@@ -5381,6 +5387,7 @@ extern tree get_tls_wrapper_fn			(tree);
 extern void mark_needed				(tree);
 extern bool decl_needed_p			(tree);
 extern void note_vague_linkage_fn		(tree);
+extern void note_fn_called_virtually		(tree);
 extern tree build_artificial_parm		(tree, tree);
 extern bool possibly_inlined_p			(tree);
 extern int parm_index                           (tree);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index eafdce5..dbb669a 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -47,6 +47,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-common.h"
 #include "c-family/c-objc.h"
 #include "cgraph.h"
+/* For build_type_inheritance_graph and possible_polymorphic_call_targets.  */
+#include "ipa-utils.h"
 #include "tree-inline.h"
 #include "c-family/c-pragma.h"
 #include "dumpfile.h"
@@ -103,6 +105,10 @@ static GTY(()) vec<tree, va_gc> *deferred_fns;
    sure are defined.  */
 static GTY(()) vec<tree, va_gc> *no_linkage_decls;
 
+/* A list of functions called through the vtable, so we can mark their
+   overriders as used.  */
+static GTY(()) vec<tree, va_gc> *fns_called_virtually;
+
 /* Nonzero if we're done parsing and into end-of-file activities.  */
 
 int at_eof;
@@ -786,6 +792,19 @@ note_vague_linkage_fn (tree decl)
   vec_safe_push (deferred_fns, decl);
 }
 
+/* DECL is a function being called through the vtable.  Remember it so that
+   at the end of the translation unit we can mark as used any functions
+   that override it, for devirtualization.  */
+
+void
+note_fn_called_virtually (tree decl)
+{
+  if (FNDECL_CALLED_VIRTUALLY (decl))
+    return;
+  FNDECL_CALLED_VIRTUALLY (decl) = true;
+  vec_safe_push (fns_called_virtually, decl);
+}
+
 /* We have just processed the DECL, which is a static data member.
    The other parameters are as for cp_finish_decl.  */
 
@@ -4263,6 +4282,39 @@ dump_tu (void)
     }
 }
 
+/* Now that we've seen all the types in the translation unit, go back over
+   the list of functions called through the vtable and mark any overriders
+   as used so they're available for devirtualization.  */
+
+static bool
+mark_virtual_overrides (void)
+{
+  if (!fns_called_virtually)
+    return false;
+
+  build_type_inheritance_graph ();
+
+  bool reconsider = false;
+  size_t i; tree fn;
+  FOR_EACH_VEC_SAFE_ELT (fns_called_virtually, i, fn)
+    {
+      vec<cgraph_node*> targets
+	= possible_polymorphic_call_targets (fn);
+
+      size_t j; cgraph_node *n;
+      FOR_EACH_VEC_ELT (targets, j, n)
+	{
+	  if (!DECL_ODR_USED (n->decl))
+	    reconsider = true;
+	  mark_used (n->decl);
+	}
+    }
+
+  release_tree_vector (fns_called_virtually);
+  fns_called_virtually = NULL;
+  return reconsider;
+}
+
 /* This routine is called at the end of compilation.
    Its job is to create all the code needed to initialize and
    destroy the global aggregates.  We do the destruction
@@ -4376,6 +4428,11 @@ cp_write_global_declarations (void)
 	    }
 	}
 
+      /* If we've seen virtual function calls, mark any overriders of those
+	 functions as used so they get instantiated or synthesized.  */
+      if (mark_virtual_overrides ())
+	reconsider = true;
+
       /* Write out needed type info variables.  We have to be careful
 	 looping through unemitted decls, because emit_tinfo_decl may
 	 cause other variables to be needed. New elements will be
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 1c6d19d..bc79a7c 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -2804,6 +2804,17 @@ possible_polymorphic_call_targets (tree otr_type,
   return nodes;
 }
 
+/* Return vector containing possible targets of polymorphic call to
+   function FN.  */
+
+vec <cgraph_node *>
+possible_polymorphic_call_targets (tree fn)
+{
+  return possible_polymorphic_call_targets
+    (DECL_CONTEXT (fn), tree_to_uhwi (DECL_VINDEX (fn)),
+     ipa_dummy_polymorphic_call_context);
+}
+
 /* Dump all possible targets of a polymorphic call.  */
 
 void
diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h
index 1254304..807fbd5 100644
--- a/gcc/ipa-utils.h
+++ b/gcc/ipa-utils.h
@@ -84,6 +84,7 @@ possible_polymorphic_call_targets (tree, HOST_WIDE_INT,
 				   bool *final = NULL,
 				   void **cache_token = NULL,
 				   int *nonconstruction_targets = NULL);
+vec <cgraph_node *> possible_polymorphic_call_targets (tree fn);
 odr_type get_odr_type (tree, bool insert = false);
 void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT,
 					     const ipa_polymorphic_call_context &);

Reply via email to