ipa-devirt.c (polymorphic_call_target_d): Add SPECULATIVE; reorder for better storage.
authorJan Hubicka <hubicka@ucw.cz>
Thu, 25 Sep 2014 18:57:44 +0000 (20:57 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Thu, 25 Sep 2014 18:57:44 +0000 (18:57 +0000)
* ipa-devirt.c (polymorphic_call_target_d): Add SPECULATIVE; reorder
for better storage.
(polymorphic_call_target_hasher::hash): Hash SPECULATIVE.
(possible_polymorphic_call_targets): Instead of computing both
speculative and non-speculative answers, do just one at a time.
Replace NONSPECULATIVE_TARGETSP parameter with SPECULATIVE flag.
(dump_targets): Break out from ...
(dump_possible_polymorphic_call_targets): ... here; dump both speculative
and non-speculative lists.
(ipa_devirt): Update for new possible_polymorphic_call_targets API.
* ipa-utils.h (possible_polymorphic_call_targets): Update.

* testsuite/g++.dg/ipa/devirt-34.C: Update template.

From-SVN: r215614

gcc/ChangeLog
gcc/ipa-devirt.c
gcc/ipa-utils.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ipa/devirt-34.C

index f48cc11314dbc0a9a28a75120e1ffe5083ab61e4..cfc1120c195d04ed9da3c4573c62e9fd9a058bdf 100644 (file)
@@ -1,3 +1,17 @@
+2014-09-25  Jan Hubicka  <hubicka@ucw.cz>
+
+       * ipa-devirt.c (polymorphic_call_target_d): Add SPECULATIVE; reorder
+       for better storage.
+       (polymorphic_call_target_hasher::hash): Hash SPECULATIVE.
+       (possible_polymorphic_call_targets): Instead of computing both
+       speculative and non-speculative answers, do just one at a time.
+       Replace NONSPECULATIVE_TARGETSP parameter with SPECULATIVE flag.
+       (dump_targets): Break out from ...
+       (dump_possible_polymorphic_call_targets): ... here; dump both speculative
+       and non-speculative lists.
+       (ipa_devirt): Update for new possible_polymorphic_call_targets API.
+       * ipa-utils.h (possible_polymorphic_call_targets): Update.
+
 2014-09-25  Uros Bizjak  <ubizjak@gmail.com>
 
        PR rtl-optimization/63348
index 0b6e12bef954f8c1f3887bac02dab329bebee462..357a506a651dde982ed76faeb2dfc09125e66601 100644 (file)
@@ -1884,10 +1884,10 @@ struct polymorphic_call_target_d
   ipa_polymorphic_call_context context;
   odr_type type;
   vec <cgraph_node *> targets;
-  int speculative_targets;
-  bool complete;
-  int type_warning;
   tree decl_warning;
+  int type_warning;
+  bool complete;
+  bool speculative;
 };
 
 /* Polymorphic call target cache helpers.  */
@@ -1917,6 +1917,7 @@ polymorphic_call_target_hasher::hash (const value_type *odr_query)
       hstate.merge_hash (TYPE_UID (odr_query->context.speculative_outer_type));
       hstate.add_wide_int (odr_query->context.speculative_offset);
     }
+  hstate.add_flag (odr_query->speculative);
   hstate.add_flag (odr_query->context.maybe_in_construction);
   hstate.add_flag (odr_query->context.maybe_derived_type);
   hstate.add_flag (odr_query->context.speculative_maybe_derived_type);
@@ -1931,6 +1932,7 @@ polymorphic_call_target_hasher::equal (const value_type *t1,
                                       const compare_type *t2)
 {
   return (t1->type == t2->type && t1->otr_token == t2->otr_token
+         && t1->speculative == t2->speculative
          && t1->context.offset == t2->context.offset
          && t1->context.speculative_offset == t2->context.speculative_offset
          && t1->context.outer_type == t2->context.outer_type
@@ -3667,10 +3669,8 @@ struct final_warning_record *final_warning_records;
    in the target cache.  If user needs to visit every target list
    just once, it can memoize them.
 
-   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.
+   If SPECULATIVE is set, the list will not contain targets that
+   are not speculatively taken.
 
    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
@@ -3682,7 +3682,7 @@ possible_polymorphic_call_targets (tree otr_type,
                                   ipa_polymorphic_call_context context,
                                   bool *completep,
                                   void **cache_token,
-                                  int *speculative_targetsp)
+                                  bool speculative)
 {
   static struct cgraph_node_hook_list *node_removal_hook_holder;
   vec <cgraph_node *> nodes = vNULL;
@@ -3706,13 +3706,11 @@ possible_polymorphic_call_targets (tree otr_type,
        *completep = context.invalid;
       if (cache_token)
        *cache_token = NULL;
-      if (speculative_targetsp)
-       *speculative_targetsp = 0;
       return nodes;
     }
 
   /* Do not bother to compute speculative info when user do not asks for it.  */
-  if (!speculative_targetsp || !context.speculative_outer_type)
+  if (!speculative || !context.speculative_outer_type)
     context.clear_speculation ();
 
   type = get_odr_type (otr_type, true);
@@ -3730,8 +3728,6 @@ possible_polymorphic_call_targets (tree otr_type,
        *completep = true;
       if (cache_token)
        *cache_token = NULL;
-      if (speculative_targetsp)
-       *speculative_targetsp = 0;
       return nodes;
     }
   gcc_assert (!context.invalid);
@@ -3783,6 +3779,7 @@ possible_polymorphic_call_targets (tree otr_type,
   /* Lookup cached answer.  */
   key.type = type;
   key.otr_token = otr_token;
+  key.speculative = speculative;
   key.context = context;
   slot = polymorphic_call_target_hash->find_slot (&key, INSERT);
   if (cache_token)
@@ -3791,15 +3788,13 @@ possible_polymorphic_call_targets (tree otr_type,
     {
       if (completep)
        *completep = (*slot)->complete;
-      if (speculative_targetsp)
-       *speculative_targetsp = (*slot)->speculative_targets;
       if ((*slot)->type_warning && final_warning_records)
        {
          final_warning_records->type_warnings[(*slot)->type_warning - 1].count++;
          final_warning_records->type_warnings[(*slot)->type_warning - 1].dyn_count
            += final_warning_records->dyn_count;
        }
-      if ((*slot)->decl_warning && final_warning_records)
+      if (!speculative && (*slot)->decl_warning && final_warning_records)
        {
          struct decl_warn_count *c =
             final_warning_records->decl_warnings.get ((*slot)->decl_warning);
@@ -3819,7 +3814,7 @@ possible_polymorphic_call_targets (tree otr_type,
   (*slot)->type = type;
   (*slot)->otr_token = otr_token;
   (*slot)->context = context;
-  (*slot)->speculative_targets = 0;
+  (*slot)->speculative = speculative;
 
   hash_set<tree> inserted;
   hash_set<tree> matched_vtables;
@@ -3864,137 +3859,136 @@ possible_polymorphic_call_targets (tree otr_type,
                                               &speculation_complete,
                                               bases_to_consider,
                                               false);
-      (*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);
-  if (binfo)
-    target = gimple_get_virt_method_for_binfo (otr_token, binfo,
-                                              &can_refer);
-  else
+  if (!speculative || !nodes.length ())
     {
-      gcc_assert (odr_violation_reported);
-      target = NULL;
-    }
+      /* First see virtual method of type itself.  */
+      binfo = get_binfo_at_offset (TYPE_BINFO (outer_type->type),
+                                  context.offset, otr_type);
+      if (binfo)
+       target = gimple_get_virt_method_for_binfo (otr_token, binfo,
+                                                  &can_refer);
+      else
+       {
+         gcc_assert (odr_violation_reported);
+         target = NULL;
+       }
 
-  /* Destructors are never called through construction virtual tables,
-     because the type is always known.  */
-  if (target && DECL_CXX_DESTRUCTOR_P (target))
-    context.maybe_in_construction = false;
+      /* Destructors are never called through construction virtual tables,
+        because the type is always known.  */
+      if (target && DECL_CXX_DESTRUCTOR_P (target))
+       context.maybe_in_construction = false;
 
-  if (target)
-    {
-      /* In the case we get complete method, we don't need 
-        to walk derivations.  */
-      if (DECL_FINAL_P (target))
-       context.maybe_derived_type = false;
-    }
+      if (target)
+       {
+         /* In the case we get complete method, we don't need 
+            to walk derivations.  */
+         if (DECL_FINAL_P (target))
+           context.maybe_derived_type = false;
+       }
 
-  /* If OUTER_TYPE is abstract, we know we are not seeing its instance.  */
-  if (type_possibly_instantiated_p (outer_type->type))
-    maybe_record_node (nodes, target, &inserted, can_refer, &complete);
-  else
-    skipped = true;
+      /* If OUTER_TYPE is abstract, we know we are not seeing its instance.  */
+      if (type_possibly_instantiated_p (outer_type->type))
+       maybe_record_node (nodes, target, &inserted, can_refer, &complete);
+      else
+       skipped = true;
 
-  if (binfo)
-    matched_vtables.add (BINFO_VTABLE (binfo));
+      if (binfo)
+       matched_vtables.add (BINFO_VTABLE (binfo));
 
-  /* Next walk recursively all derived types.  */
-  if (context.maybe_derived_type)
-    {
-      for (i = 0; i < outer_type->derived_types.length(); i++)
-       possible_polymorphic_call_targets_1 (nodes, &inserted,
-                                            &matched_vtables,
-                                            otr_type,
-                                            outer_type->derived_types[i],
-                                            otr_token, outer_type->type,
-                                            context.offset, &complete,
-                                            bases_to_consider,
-                                            context.maybe_in_construction);
-
-      if (!outer_type->all_derivations_known)
+      /* Next walk recursively all derived types.  */
+      if (context.maybe_derived_type)
        {
-         if (final_warning_records)
+         for (i = 0; i < outer_type->derived_types.length(); i++)
+           possible_polymorphic_call_targets_1 (nodes, &inserted,
+                                                &matched_vtables,
+                                                otr_type,
+                                                outer_type->derived_types[i],
+                                                otr_token, outer_type->type,
+                                                context.offset, &complete,
+                                                bases_to_consider,
+                                                context.maybe_in_construction);
+
+         if (!outer_type->all_derivations_known)
            {
-             if (complete
-                 && nodes.length () == 1
-                 && warn_suggest_final_types
-                 && !outer_type->derived_types.length ())
+             if (!speculative && final_warning_records)
                {
-                 if (outer_type->id >= (int)final_warning_records->type_warnings.length ())
-                   final_warning_records->type_warnings.safe_grow_cleared
-                     (odr_types.length ());
-                 final_warning_records->type_warnings[outer_type->id].count++;
-                 final_warning_records->type_warnings[outer_type->id].dyn_count
-                   += final_warning_records->dyn_count;
-                 final_warning_records->type_warnings[outer_type->id].type
-                   = outer_type->type;
-                 (*slot)->type_warning = outer_type->id + 1;
-               }
-             if (complete
-                 && warn_suggest_final_methods
-                 && nodes.length () == 1
-                 && types_same_for_odr (DECL_CONTEXT (nodes[0]->decl),
-                                        outer_type->type))
-               {
-                 bool existed;
-                 struct decl_warn_count &c =
-                    final_warning_records->decl_warnings.get_or_insert
-                       (nodes[0]->decl, &existed);
-
-                 if (existed)
+                 if (complete
+                     && nodes.length () == 1
+                     && warn_suggest_final_types
+                     && !outer_type->derived_types.length ())
                    {
-                     c.count++;
-                     c.dyn_count += final_warning_records->dyn_count;
+                     if (outer_type->id >= (int)final_warning_records->type_warnings.length ())
+                       final_warning_records->type_warnings.safe_grow_cleared
+                         (odr_types.length ());
+                     final_warning_records->type_warnings[outer_type->id].count++;
+                     final_warning_records->type_warnings[outer_type->id].dyn_count
+                       += final_warning_records->dyn_count;
+                     final_warning_records->type_warnings[outer_type->id].type
+                       = outer_type->type;
+                     (*slot)->type_warning = outer_type->id + 1;
                    }
-                 else
+                 if (complete
+                     && warn_suggest_final_methods
+                     && nodes.length () == 1
+                     && types_same_for_odr (DECL_CONTEXT (nodes[0]->decl),
+                                            outer_type->type))
                    {
-                     c.count = 1;
-                     c.dyn_count = final_warning_records->dyn_count;
-                     c.decl = nodes[0]->decl;
+                     bool existed;
+                     struct decl_warn_count &c =
+                        final_warning_records->decl_warnings.get_or_insert
+                           (nodes[0]->decl, &existed);
+
+                     if (existed)
+                       {
+                         c.count++;
+                         c.dyn_count += final_warning_records->dyn_count;
+                       }
+                     else
+                       {
+                         c.count = 1;
+                         c.dyn_count = final_warning_records->dyn_count;
+                         c.decl = nodes[0]->decl;
+                       }
+                     (*slot)->decl_warning = nodes[0]->decl;
                    }
-                 (*slot)->decl_warning = nodes[0]->decl;
                }
+             complete = false;
            }
-         complete = false;
        }
-    }
-
-  /* Finally walk bases, if asked to.  */
-  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
-     so look to at least two of them.  */
-  if (context.maybe_in_construction)
-    for (i =0 ; i < MIN (nodes.length (), 2); i++)
-      if (DECL_CXX_DESTRUCTOR_P (nodes[i]->decl))
-       context.maybe_in_construction = false;
-  if (context.maybe_in_construction)
-    {
-      if (type != outer_type
-         && (!skipped
-             || (context.maybe_derived_type
-                 && !type_all_derivations_known_p (outer_type->type))))
-       record_targets_from_bases (otr_type, otr_token, outer_type->type,
-                                  context.offset, nodes, &inserted,
-                                  &matched_vtables, &complete);
-      if (skipped)
-        maybe_record_node (nodes, target, &inserted, can_refer, &complete);
-      for (i = 0; i < bases_to_consider.length(); i++)
-        maybe_record_node (nodes, bases_to_consider[i], &inserted, can_refer, &complete);
+      if (!speculative)
+       {
+         /* Destructors are never called through construction virtual tables,
+            because the type is always known.  One of entries may be cxa_pure_virtual
+            so look to at least two of them.  */
+         if (context.maybe_in_construction)
+           for (i =0 ; i < MIN (nodes.length (), 2); i++)
+             if (DECL_CXX_DESTRUCTOR_P (nodes[i]->decl))
+               context.maybe_in_construction = false;
+         if (context.maybe_in_construction)
+           {
+             if (type != outer_type
+                 && (!skipped
+                     || (context.maybe_derived_type
+                         && !type_all_derivations_known_p (outer_type->type))))
+               record_targets_from_bases (otr_type, otr_token, outer_type->type,
+                                          context.offset, nodes, &inserted,
+                                          &matched_vtables, &complete);
+             if (skipped)
+               maybe_record_node (nodes, target, &inserted, can_refer, &complete);
+             for (i = 0; i < bases_to_consider.length(); i++)
+               maybe_record_node (nodes, bases_to_consider[i], &inserted, can_refer, &complete);
+           }
+       }
     }
-  bases_to_consider.release();
 
+  bases_to_consider.release();
   (*slot)->targets = nodes;
   (*slot)->complete = complete;
   if (completep)
     *completep = complete;
-  if (speculative_targetsp)
-    *speculative_targetsp = (*slot)->speculative_targets;
 
   timevar_pop (TV_IPA_VIRTUAL_CALL);
   return nodes;
@@ -4008,6 +4002,29 @@ add_decl_warning (const tree &key ATTRIBUTE_UNUSED, const decl_warn_count &value
   return true;
 }
 
+/* Dump target list TARGETS into FILE.  */
+
+static void
+dump_targets (FILE *f, vec <cgraph_node *> targets)
+{
+  unsigned int i;
+
+  for (i = 0; i < targets.length (); i++)
+    {
+      char *name = NULL;
+      if (in_lto_p)
+       name = cplus_demangle_v3 (targets[i]->asm_name (), 0);
+      fprintf (f, " %s/%i", name ? name : targets[i]->name (), targets[i]->order);
+      if (in_lto_p)
+       free (name);
+      if (!targets[i]->definition)
+       fprintf (f, " (no definition%s)",
+                DECL_DECLARED_INLINE_P (targets[i]->decl)
+                ? " inline" : "");
+    }
+  fprintf (f, "\n");
+}
+
 /* Dump all possible targets of a polymorphic call.  */
 
 void
@@ -4019,14 +4036,13 @@ dump_possible_polymorphic_call_targets (FILE *f,
   vec <cgraph_node *> targets;
   bool final;
   odr_type type = get_odr_type (TYPE_MAIN_VARIANT (otr_type), false);
-  unsigned int i;
-  int speculative;
+  unsigned int len;
 
   if (!type)
     return;
   targets = possible_polymorphic_call_targets (otr_type, otr_token,
                                               ctx,
-                                              &final, NULL, &speculative);
+                                              &final, NULL, false);
   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);
@@ -4039,23 +4055,19 @@ dump_possible_polymorphic_call_targets (FILE *f,
           ctx.maybe_in_construction ? " (base 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++)
+  len = targets.length ();
+  dump_targets (f, targets);
+
+  targets = possible_polymorphic_call_targets (otr_type, otr_token,
+                                              ctx,
+                                              &final, NULL, true);
+  gcc_assert (targets.length () <= len);
+  if (targets.length () != len)
     {
-      char *name = NULL;
-      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);
-      fprintf (f, " %s/%i", name ? name : targets[i]->name (), targets[i]->order);
-      if (in_lto_p)
-       free (name);
-      if (!targets[i]->definition)
-       fprintf (f, " (no definition%s)",
-                DECL_DECLARED_INLINE_P (targets[i]->decl)
-                ? " inline" : "");
+      fprintf (f, "  Speculative targets:");
+      dump_targets (f, targets);
     }
-  fprintf (f, "\n\n");
+  fprintf (f, "\n");
 }
 
 
@@ -4241,16 +4253,19 @@ ipa_devirt (void)
            struct cgraph_node *likely_target = NULL;
            void *cache_token;
            bool final;
-           int speculative_targets;
 
            if (final_warning_records)
              final_warning_records->dyn_count = e->count;
 
            vec <cgraph_node *>targets
               = possible_polymorphic_call_targets
-                   (e, &final, &cache_token, &speculative_targets);
+                   (e, &final, &cache_token, true);
            unsigned int i;
 
+           /* Trigger warnings by calculating non-speculative targets.  */
+           if (warn_suggest_final_methods || warn_suggest_final_types)
+             possible_polymorphic_call_targets (e);
+
            if (dump_file)
              dump_possible_polymorphic_call_targets 
                (dump_file, e);
@@ -4289,13 +4304,10 @@ ipa_devirt (void)
                {
                  if (likely_target)
                    {
-                     if (i < (unsigned) speculative_targets)
-                       {
-                         likely_target = NULL;
-                         if (dump_file)
-                           fprintf (dump_file, "More than one likely target\n\n");
-                         nmultiple++;
-                       }
+                     likely_target = NULL;
+                     if (dump_file)
+                       fprintf (dump_file, "More than one likely target\n\n");
+                     nmultiple++;
                      break;
                    }
                  likely_target = targets[i];
index 7ff29f8c147ee2f15b626adfaa603a59b52da7b4..494397b76a4743c654906e3d0c73c2a768932edd 100644 (file)
@@ -62,7 +62,7 @@ possible_polymorphic_call_targets (tree, HOST_WIDE_INT,
                                   ipa_polymorphic_call_context,
                                   bool *copletep = NULL,
                                   void **cache_token = NULL,
-                                  int *nonconstruction_targets = NULL);
+                                  bool speuclative = false);
 odr_type get_odr_type (tree, bool insert = false);
 bool possible_polymorphic_call_target_p (tree ref, gimple stmt, struct cgraph_node *n);
 void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT,
@@ -92,7 +92,7 @@ inline vec <cgraph_node *>
 possible_polymorphic_call_targets (struct cgraph_edge *e,
                                   bool *completep = NULL,
                                   void **cache_token = NULL,
-                                  int *nonconstruction_targets = NULL)
+                                  bool speculative = false)
 {
   ipa_polymorphic_call_context context(e);
 
@@ -100,7 +100,7 @@ possible_polymorphic_call_targets (struct cgraph_edge *e,
                                            e->indirect_info->otr_token,
                                            context,
                                            completep, cache_token,
-                                           nonconstruction_targets);
+                                           speculative);
 }
 
 /* Same as above but taking OBJ_TYPE_REF as an parameter.  */
index 1ac6f0e03b1bb4f916f2ea0603315433cba54120..57ae679a97ef16055997e05c7cd2ad404dd0aa42 100644 (file)
@@ -1,3 +1,7 @@
+2014-09-25  Jan Hubicka  <hubicka@ucw.cz>
+
+       * testsuite/g++.dg/ipa/devirt-34.C: Update template.
+
 2014-09-25  James Greenhalgh  <james.greenhalgh@arm.com>
 
        * gcc.target/aarch64/simd/vqshlb_1.c: New.
index 5d56e1e0c8b35203f14a049453c495cb31e927dc..6487f8ee3d901579b3f442a446541c4f0c2e35e9 100644 (file)
@@ -15,6 +15,6 @@ t(struct B *b)
 /* 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 "Speculative targets"  "devirt"  } } */
 /* { dg-final { scan-ipa-dump "1 speculatively devirtualized"  "devirt"  } } */
 /* { dg-final { cleanup-ipa-dump "devirt" } } */