Ignore cxa_pure_virtual in ipa-devirt's target lists

Jan Hubicka hubicka@ucw.cz
Mon Apr 14 20:06:00 GMT 2014


Hi,
as discussed in February, it is safe for ipa-devirt to skip all cxa_pure_virtual
calls from virtual tables.  Since cxa_pure_virtual is not a builtin, I simply
implemented this by making maybe_record_node to skip everything that is not
of METHOD_TYPE.

Other drawback of cxa_pure_virtual is that it requires a global relocation in
vtable and for large apps, like libreoffice there are very many of them.  Given
that the effect is undefined, I wonder if we don't want to make it simply NULL
at least with optimization enabled.

Less intrusive fix seems to be to introduce hidden cxa_pure_virtual into every
DSO. Jason, I see several options:

1) write backend pass that walks vtables and for every non-hidden noreturn function
   it can produce hidden COMDAT wrapper with a fixed (GCC local) mangling.
   Perhaps with a command line option to do so for all virtual functions; while this
   would introduce extra call into most of virtual calls, this may not be too bad
   with LTO, where we can do that only for virtuals that are exported from unit.
2) make something similar in C++ FE (probably not so cool idea because of the comment
   above)
3) introduce hidden local_cxa_pure_virtual into bits that are linked into every
   DSO so we do not need to play with COMDAT.

What do you think?
Honza
	* ipa-devirt.c (maybe_record_node): Ignore all non-methods (including
	cxa_pure_virtual).
Index: ipa-devirt.c
===================================================================
--- ipa-devirt.c	(revision 209386)
+++ ipa-devirt.c	(working copy)
@@ -611,7 +611,12 @@ maybe_record_node (vec <cgraph_node *> &
 		   bool *completep)
 {
   struct cgraph_node *target_node;
-  enum built_in_function fcode;
+
+  /* cxa_pure_virtual and __builtin_unreachable do not need to be added into
+     list of targets; the runtime effect of calling them is undefined.
+     Only "real" virtual methods should be accounted.  */
+  if (target && TREE_CODE (TREE_TYPE (target)) != METHOD_TYPE)
+    return;
 
   if (!can_refer)
     {
@@ -619,22 +624,19 @@ maybe_record_node (vec <cgraph_node *> &
 	 is when we completely optimized it out.  */
       if (flag_ltrans
 	  || !target 
-          || !type_in_anonymous_namespace_p (DECL_CONTEXT (target)))
+	  || !type_in_anonymous_namespace_p (DECL_CONTEXT (target)))
 	*completep = false;
       return;
     }
 
-  if (!target
-      /* Those are used to mark impossible scenarios.  */
-      || (fcode = DECL_FUNCTION_CODE (target))
-	  == BUILT_IN_UNREACHABLE
-      || fcode == BUILT_IN_TRAP)
+  if (!target)
     return;
 
   target_node = cgraph_get_node (target);
 
   if (target_node != NULL
-      && (TREE_PUBLIC (target)
+      && ((TREE_PUBLIC (target)
+	   || DECL_EXTERNAL (target))
 	  || target_node->definition)
       && symtab_real_symbol_p (target_node))
     {



More information about the Gcc-patches mailing list