]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
devirt-34.C: New testcase.
authorJan Hubicka <hubicka@ucw.cz>
Wed, 30 Jul 2014 07:48:13 +0000 (09:48 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Wed, 30 Jul 2014 07:48:13 +0000 (07:48 +0000)
* g++.dg/ipa/devirt-34.C: New testcase.
* ipa-devirt.c (polymorphic_call_target_d): Rename nonconstruction_targets
to speculative_targets
(get_class_context): Fix handling of contextes without outer type;
avoid matching non-polymorphic types in LTO.
(possible_polymorphic_call_targets): Trun nonconstruction_targetsp
parameter to speculative_targetsp; handle speculation.
(dump_possible_polymorphic_call_targets): Update dumping.

From-SVN: r213232

gcc/ChangeLog
gcc/common.opt
gcc/ipa-devirt.c
gcc/testsuite/g++.dg/ipa/devirt-34.C [new file with mode: 0644]

index 1bc809f0ca3961174e4b3361f57bcd7071fea68f..1076c0c5cefcd9fe76b3c29af50f03897061197d 100644 (file)
@@ -1,3 +1,18 @@
+2014-07-29  Jan Hubicka  <hubicka@ucw.cz>
+
+       * g++.dg/ipa/devirt-34.C: New testcase.
+       * ipa-devirt.c (polymorphic_call_target_d): Rename nonconstruction_targets
+       to speculative_targets
+       (get_class_context): Fix handling of contextes without outer type;
+       avoid matching non-polymorphic types in LTO.
+       (possible_polymorphic_call_targets): Trun nonconstruction_targetsp
+       parameter to speculative_targetsp; handle speculation.
+       (dump_possible_polymorphic_call_targets): Update dumping.
+
+2014-07-29  Jan Hubicka  <hubicka@ucw.cz>
+
+       * common.opt (Wodr): Enable by default.
+
 2014-07-29  Olivier Hainque  <hainque@adacore.com>
 
        * config/vxworksae.h (VXWORKS_OVERRIDE_OPTIONS): Define.
index 3b04044e07eef2764fbb9d79888f42de3efd8d6a..927e0edf9a45386df6db098303d2ba8d1f4794ab 100644 (file)
@@ -588,7 +588,7 @@ Wmissing-noreturn
 Common Alias(Wsuggest-attribute=noreturn)
 
 Wodr
-Common Var(warn_odr_violations) Warning
+Common Var(warn_odr_violations) Init(1) Warning
 Warn about some C++ One Definition Rule violations during link time optimization
 
 Woverflow
index 4b5b2a659c0f60b1b46fa3fcd497c4b129265d72..1c6d19dbc886c441d090b9954137a0926bc85f53 100644 (file)
@@ -1615,7 +1615,7 @@ struct polymorphic_call_target_d
   ipa_polymorphic_call_context context;
   odr_type type;
   vec <cgraph_node *> targets;
-  int nonconstruction_targets;
+  int speculative_targets;
   bool complete;
 };
 
@@ -1770,8 +1770,8 @@ get_class_context (ipa_polymorphic_call_context *context,
 
  if (!context->outer_type)
    {
-     context->outer_type = expected_type;
-     context->offset = offset;
+     type = context->outer_type = expected_type;
+     context->offset = offset = 0;
    }
   /* See if speculative type seem to be derrived from outer_type.
      Then speculation is valid only if it really is a derivate and derived types
@@ -1807,6 +1807,10 @@ get_class_context (ipa_polymorphic_call_context *context,
 
       /* On a match, just return what we found.  */
       if (TREE_CODE (type) == TREE_CODE (expected_type)
+         && (!in_lto_p
+             || (TREE_CODE (type) == RECORD_TYPE
+                 && TYPE_BINFO (type)
+                 && polymorphic_type_binfo_p (TYPE_BINFO (type))))
          && types_same_for_odr (type, expected_type))
        {
          if (speculative)
@@ -2518,9 +2522,10 @@ devirt_variable_node_removal_hook (varpool_node *n,
    in the target cache.  If user needs to visit every target list
    just once, it can memoize them.
 
-   NONCONSTRUCTION_TARGETS specify number of targets with asumption that
-   the type is not in the construction.  Those targets appear first in the
-   vector returned.
+   SPECULATION_TARGETS specify number of targets that are speculatively
+   likely.  These include targets specified by the speculative part
+   of polymoprhic call context and also exclude all targets for classes
+   in construction.
 
    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
@@ -2532,7 +2537,7 @@ possible_polymorphic_call_targets (tree otr_type,
                                   ipa_polymorphic_call_context context,
                                   bool *completep,
                                   void **cache_token,
-                                  int *nonconstruction_targetsp)
+                                  int *speculative_targetsp)
 {
   static struct cgraph_node_hook_list *node_removal_hook_holder;
   pointer_set_t *inserted;
@@ -2557,8 +2562,8 @@ possible_polymorphic_call_targets (tree otr_type,
        *completep = false;
       if (cache_token)
        *cache_token = NULL;
-      if (nonconstruction_targetsp)
-       *nonconstruction_targetsp = 0;
+      if (speculative_targetsp)
+       *speculative_targetsp = 0;
       return nodes;
     }
 
@@ -2569,8 +2574,8 @@ possible_polymorphic_call_targets (tree otr_type,
        *completep = true;
       if (cache_token)
        *cache_token = NULL;
-      if (nonconstruction_targetsp)
-       *nonconstruction_targetsp = 0;
+      if (speculative_targetsp)
+       *speculative_targetsp = 0;
       return nodes;
     }
 
@@ -2581,15 +2586,15 @@ possible_polymorphic_call_targets (tree otr_type,
              || TYPE_MAIN_VARIANT (context.outer_type) == context.outer_type);
 
   /* Lookup the outer class type we want to walk.  */
-  if (context.outer_type
+  if ((context.outer_type || context.speculative_outer_type)
       && !get_class_context (&context, otr_type))
     {
       if (completep)
        *completep = false;
       if (cache_token)
        *cache_token = NULL;
-      if (nonconstruction_targetsp)
-       *nonconstruction_targetsp = 0;
+      if (speculative_targetsp)
+       *speculative_targetsp = 0;
       return nodes;
     }
 
@@ -2638,8 +2643,8 @@ possible_polymorphic_call_targets (tree otr_type,
     {
       if (completep)
        *completep = (*slot)->complete;
-      if (nonconstruction_targetsp)
-       *nonconstruction_targetsp = (*slot)->nonconstruction_targets;
+      if (speculative_targetsp)
+       *speculative_targetsp = (*slot)->speculative_targets;
       return (*slot)->targets;
     }
 
@@ -2653,10 +2658,57 @@ possible_polymorphic_call_targets (tree otr_type,
   (*slot)->type = type;
   (*slot)->otr_token = otr_token;
   (*slot)->context = context;
+  (*slot)->speculative_targets = 0;
 
   inserted = pointer_set_create ();
   matched_vtables = pointer_set_create ();
 
+  if (context.speculative_outer_type)
+    {
+      odr_type speculative_outer_type;
+      speculative_outer_type = get_odr_type (context.speculative_outer_type, true);
+      if (TYPE_FINAL_P (speculative_outer_type->type))
+       context.speculative_maybe_derived_type = false;
+      binfo = get_binfo_at_offset (TYPE_BINFO (speculative_outer_type->type),
+                                  context.speculative_offset, otr_type);
+      if (binfo)
+       target = gimple_get_virt_method_for_binfo (otr_token, binfo,
+                                                  &can_refer);
+      else
+       target = NULL;
+
+      if (target)
+       {
+         /* In the case we get complete method, we don't need 
+            to walk derivations.  */
+         if (DECL_FINAL_P (target))
+           context.speculative_maybe_derived_type = false;
+       }
+      if (type_possibly_instantiated_p (speculative_outer_type->type))
+       maybe_record_node (nodes, target, inserted, can_refer, &complete);
+      if (binfo)
+       pointer_set_insert (matched_vtables, BINFO_VTABLE (binfo));
+      /* Next walk recursively all derived types.  */
+      if (context.speculative_maybe_derived_type)
+       {
+         /* For anonymous namespace types we can attempt to build full type.
+            All derivations must be in this unit (unless we see partial unit).  */
+         if (!type->all_derivations_known)
+           complete = false;
+         for (i = 0; i < speculative_outer_type->derived_types.length(); i++)
+           possible_polymorphic_call_targets_1 (nodes, inserted,
+                                                matched_vtables,
+                                                otr_type,
+                                                speculative_outer_type->derived_types[i],
+                                                otr_token, speculative_outer_type->type,
+                                                context.speculative_offset, &complete,
+                                                bases_to_consider,
+                                                false);
+       }
+      /* Finally walk bases, if asked to.  */
+      (*slot)->speculative_targets = nodes.length();
+    }
+
   /* First see virtual method of type itself.  */
   binfo = get_binfo_at_offset (TYPE_BINFO (outer_type->type),
                               context.offset, otr_type);
@@ -2713,7 +2765,8 @@ possible_polymorphic_call_targets (tree otr_type,
     }
 
   /* Finally walk bases, if asked to.  */
-  (*slot)->nonconstruction_targets = nodes.length();
+  if (!(*slot)->speculative_targets)
+    (*slot)->speculative_targets = nodes.length();
 
   /* Destructors are never called through construction virtual tables,
      because the type is always known.  One of entries may be cxa_pure_virtual
@@ -2742,8 +2795,8 @@ possible_polymorphic_call_targets (tree otr_type,
   (*slot)->complete = complete;
   if (completep)
     *completep = complete;
-  if (nonconstruction_targetsp)
-    *nonconstruction_targetsp = (*slot)->nonconstruction_targets;
+  if (speculative_targetsp)
+    *speculative_targetsp = (*slot)->speculative_targets;
 
   pointer_set_destroy (inserted);
   pointer_set_destroy (matched_vtables);
@@ -2763,13 +2816,13 @@ dump_possible_polymorphic_call_targets (FILE *f,
   bool final;
   odr_type type = get_odr_type (TYPE_MAIN_VARIANT (otr_type), false);
   unsigned int i;
-  int nonconstruction;
+  int speculative;
 
   if (!type)
     return;
   targets = possible_polymorphic_call_targets (otr_type, otr_token,
                                               ctx,
-                                              &final, NULL, &nonconstruction);
+                                              &final, NULL, &speculative);
   fprintf (f, "  Targets of polymorphic call of type %i:", type->id);
   print_generic_expr (f, type->type, TDF_SLIM);
   fprintf (f, " token %i\n", (int)otr_token);
@@ -2780,18 +2833,25 @@ dump_possible_polymorphic_call_targets (FILE *f,
       fprintf (f, " at offset "HOST_WIDE_INT_PRINT_DEC"\n",
               ctx.offset);
     }
+  if (ctx.speculative_outer_type)
+    {
+      fprintf (f, "    Speculatively contained in type:");
+      print_generic_expr (f, ctx.speculative_outer_type, TDF_SLIM);
+      fprintf (f, " at offset "HOST_WIDE_INT_PRINT_DEC"\n",
+              ctx.speculative_offset);
+    }
 
-  fprintf (f, "    %s%s%s\n      ",
+  fprintf (f, "    %s%s%s%s\n      ",
           final ? "This is a complete list." :
           "This is partial list; extra targets may be defined in other units.",
           ctx.maybe_in_construction ? " (base types included)" : "",
-          ctx.maybe_derived_type ? " (derived types included)" : "");
+          ctx.maybe_derived_type ? " (derived types included)" : "",
+          ctx.speculative_maybe_derived_type ? " (speculative derived types included)" : "");
   for (i = 0; i < targets.length (); i++)
     {
       char *name = NULL;
-      if (i == (unsigned)nonconstruction)
-       fprintf (f, "\n     If the type is in construction,"
-                " then additional tarets are:\n"
+      if (i == (unsigned)speculative)
+       fprintf (f, "\n     Targets that are not likely:\n"
                 "      ");
       if (in_lto_p)
        name = cplus_demangle_v3 (targets[i]->asm_name (), 0);
@@ -2921,10 +2981,10 @@ ipa_devirt (void)
            struct cgraph_node *likely_target = NULL;
            void *cache_token;
            bool final;
-           int nonconstruction_targets;
+           int speculative_targets;
            vec <cgraph_node *>targets
               = possible_polymorphic_call_targets
-                   (e, &final, &cache_token, &nonconstruction_targets);
+                   (e, &final, &cache_token, &speculative_targets);
            unsigned int i;
 
            if (dump_file)
@@ -2963,7 +3023,7 @@ ipa_devirt (void)
                {
                  if (likely_target)
                    {
-                     if (i < (unsigned) nonconstruction_targets)
+                     if (i < (unsigned) speculative_targets)
                        {
                          likely_target = NULL;
                          if (dump_file)
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-34.C b/gcc/testsuite/g++.dg/ipa/devirt-34.C
new file mode 100644 (file)
index 0000000..258a2ad
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-devirt"  } */
+struct A {virtual int t(){return 42;}};
+struct B:A {virtual int t(){return 1;}};
+int
+t(struct B *b)
+{
+  struct A *a=b;
+  a->t();
+}
+
+/* We should guess that the pointer of type B probably points to an instance
+   of B or its derivates and exclude A::t from list of likely targets.  */
+
+/* { dg-final { scan-ipa-dump "Targets that are not likely"  "devirt"  } } */
+/* { dg-final { scan-ipa-dump "1 speculatively devirtualized"  "devirt"  } } */
+/* { dg-final { cleanup-ipa-dump "devirt" } } */