]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cgraph: cgraph_indirect_call_info into a class hierachy
authorMartin Jambor <mjambor@suse.cz>
Mon, 15 Dec 2025 23:44:45 +0000 (00:44 +0100)
committerMartin Jambor <jamborm@gcc.gnu.org>
Mon, 15 Dec 2025 23:53:12 +0000 (00:53 +0100)
Currently, an instance of cgraph_indirect_call_info is allocated for
each indirect call and it contains fields which are only usable for
some kinds of calls.  The most special are polymorphic calls
representing calls of virtual methods through an OBJ_TYPE_REF and
which need the ipa_polymorphic_context structure, among other data from
the O_T_R itself for devirtualization, which are not needed for other
types of calls.

This patch splits the class into three.  A common base which is also
used for calls which we know we cannot do anything about (when the
call statement is not known or when it is a constant integer or
something like that), a (simple) type for calls of SSA_NAMEs and a
type for polymorphic calls.  This means we no longer allocate memory
for members which we do not need in a particular situation.  Part of
the motivation to write this is also that I have a patch adding fields
to the simple variant and this reorganization makes it doable in a
clean fashion.

The base class retains the param_index field even though it really only
is meaningful in the derived classes.  This made conversion of some of
the functions operating on it easier (and I expect that vast majority
of actual instances will fall into one of the two categories anyway).

We already stream information stored in indirect information at two
places, once in call graph streaming and once in ipa-prop streaming.
I am not sure what the reason is (call graph streaming cannot do trees
so we need the ipa-prop one) but this patch preserves this.

The patch also removes a part of the comment in
ipa_make_edge_direct_to_target which said the check for member_ptr was
not necessary.  We even have a test in our testsuite showing it is and
we produce wrong code without it.

gcc/ChangeLog:

2025-10-17  Martin Jambor  <mjambor@suse.cz>

* cgraph.h (cgraph_node): Adjust the comment of member function
create_indirect_edge.
(enum cgraph_indirect_info_kind): New.
(cgraph_indirect_call_info): Convert into a base class.
(cgraph_simple_indirect_info): New.
(cgraph_polymorphic_indirect_info): Likewise.
(usable_polymorphic_info_p): Likewise.
(is_a_helper <cgraph_simple_indirect_info *>::test): Likewise.
(is_a_helper <cgraph_polymorphic_indirect_info *>::test): Likewise.
(cgraph_allocate_init_indirect_info): Remove declaration.
(ipa_polymorphic_call_context::ipa_polymorphic_call_context): Use the
appropriate derived type of indirect info.
* cgraph.cc (cgraph_allocate_init_indirect_info): Removed.
(cgraph_node::create_indirect_edge): Create an appropriate type of
indirect_info.
(cgraph_node::dump): Dump indirect info using its dump function.
(cgraph_indirect_call_info::dump): New function.
(cgraph_indirect_call_info::debug): Likewise.
* cgraphclones.cc (cgraph_edge::clone): Create an appropriate type of
indirect_info.
* cgraphunit.cc (analyze_functions): Use the appropriate derived type
of indirect info.
* ipa-cp.cc (initialize_node_lattices): Adjust the check for
polymorphic indirect info.
(ipa_get_indirect_edge_target_1): Use the appropriate derived types of
indirect info.
(ipcp_discover_new_direct_edges): Likewise.
* ipa-devirt.cc (ipa_devirt): Use the polymorphis derived type of
indirect info and check that it is usable.
* ipa-inline.cc (dump_inline_stats): Adjust the check for polymorphic
indirect info.
* ipa-profile.cc (ipa_profile): Likewise and check usability.
* ipa-prop.cc (ipa_print_node_jump_functions): Dump indirect info
using its dumping member function.
(ipa_note_param_call): Removed.
(ipa_analyze_indirect_call_uses): Use the appropriate derived type of
indirect info, set all fields of indirect info separately rather than
relying on ipa_note_param_call.
(ipa_analyze_virtual_call_uses): Use the polymorphis derived type of
indirect info and check that it is usable, set all fields of indirect
info separately rather than relying on ipa_note_param_call.
(ipa_analyze_call_uses): Use the appropriate derived type of indirect
info.
(ipa_make_edge_direct_to_target): Use the appropriate derived type of
indirect info.  Remove wrong note that member_ptr check was not
needed.  Adjust check for polymorphic call when dumping.
(try_make_edge_direct_simple_call): Use the appropriate derived type
of indirect info.
(try_make_edge_direct_virtual_call): Use the polymorphis derived type
of indirect info and check that it is usable.
(update_indirect_edges_after_inlining): Use the appropriate derived
type of indirect info.  Define local variables only before their first
use.
(ipa_write_indirect_edge_info): Also stream indirect info kind.  Use
the appropriate derived type of indirect info.
(ipa_read_indirect_edge_info): Check that the streamed in indirect
info kind matches rthe structure at hand.  Use the appropriate derived
type of indirect info.
* ipa-utils.h (possible_polymorphic_call_targets): Use the
polymorphis derived type of indirect info.  Assert it is usable.
(dump_possible_polymorphic_call_targets): Use the polymorphis
derived type of indirect info and check it is usable.
(possible_polymorphic_call_target_p): Likewise.
* ipa.cc (symbol_table::remove_unreachable_nodes): Use
usable_polymorphic_info_p.
* lto-cgraph.cc (lto_output_edge): Stream indirect info kind.
(compute_ltrans_boundary): Use usable_polymorphic_info_p.
(input_edge): Move definition of ecf_flags before its first use.
Pass true as the last parameter to create_indirect_edge.  Stream
indirect info kind and create a corresponding type to hold the
information.
* trans-mem.cc (ipa_tm_insert_gettmclone_call): Use the
polymorphis derived type of indirect info.

13 files changed:
gcc/cgraph.cc
gcc/cgraph.h
gcc/cgraphclones.cc
gcc/cgraphunit.cc
gcc/ipa-cp.cc
gcc/ipa-devirt.cc
gcc/ipa-inline.cc
gcc/ipa-profile.cc
gcc/ipa-prop.cc
gcc/ipa-utils.h
gcc/ipa.cc
gcc/lto-cgraph.cc
gcc/trans-mem.cc

index 1a7d49922e0979c1be15fc5202f1fd883fe1f6ab..abea2e2d2ae9983edaeab756f54bf966fb1efb08 100644 (file)
@@ -1162,56 +1162,44 @@ cgraph_node::create_edge (cgraph_node *callee,
   return edge;
 }
 
-/* Allocate cgraph_indirect_call_info and set its fields to default values. */
-
-cgraph_indirect_call_info *
-cgraph_allocate_init_indirect_info (void)
-{
-  cgraph_indirect_call_info *ii;
-
-  ii = ggc_cleared_alloc<cgraph_indirect_call_info> ();
-  ii->param_index = -1;
-  return ii;
-}
-
-/* Create an indirect edge with a yet-undetermined callee where the call
-   statement destination is a formal parameter of the caller with index
-   PARAM_INDEX. CLONING_P should be set if properties that are copied from an
-   original edge should not be calculated and indirect_info structure should
-   not be calculated.  */
+/* Create an indirect edge to a (yet-)undetermined callee.  CALL_STMT is the
+   corresponding statement, if available, ECF_FLAGS and COUNT are corresponding
+   gimple call flags and profiling count respectively.  CLONING_P should be set
+   if properties that are copied from an original edge should not be
+   calculated.  */
 
 cgraph_edge *
 cgraph_node::create_indirect_edge (gcall *call_stmt, int ecf_flags,
-                                  profile_count count,
-                                  bool cloning_p)
+                                  profile_count count, bool cloning_p)
 {
   cgraph_edge *edge = symtab->create_edge (this, NULL, call_stmt, count, true,
                                           cloning_p);
-  tree target;
 
   if (!cloning_p)
-    initialize_inline_failed (edge);
-
-  edge->indirect_info = cgraph_allocate_init_indirect_info ();
-  edge->indirect_info->ecf_flags = ecf_flags;
-  edge->indirect_info->vptr_changed = true;
-
-  /* Record polymorphic call info.  */
-  if (!cloning_p
-      && call_stmt
-      && (target = gimple_call_fn (call_stmt))
-      && virtual_method_call_p (target))
     {
-      ipa_polymorphic_call_context context (decl, target, call_stmt);
+      initialize_inline_failed (edge);
 
-      /* Only record types can have virtual calls.  */
-      edge->indirect_info->polymorphic = true;
-      edge->indirect_info->param_index = -1;
-      edge->indirect_info->otr_token
-        = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
-      edge->indirect_info->otr_type = obj_type_ref_class (target);
-      gcc_assert (TREE_CODE (edge->indirect_info->otr_type) == RECORD_TYPE);
-      edge->indirect_info->context = context;
+      tree target = NULL_TREE;
+      if (call_stmt)
+       target = gimple_call_fn (call_stmt);
+      if (target && virtual_method_call_p (target))
+       {
+         ipa_polymorphic_call_context context (decl, target, call_stmt);
+         HOST_WIDE_INT token = tree_to_shwi (OBJ_TYPE_REF_TOKEN (target));
+         tree type = obj_type_ref_class (target);
+         edge->indirect_info
+           = (new (ggc_alloc<cgraph_polymorphic_indirect_info> ())
+              cgraph_polymorphic_indirect_info (ecf_flags, context, token,
+                                                type));
+       }
+      else if (target && TREE_CODE (target) == SSA_NAME)
+       edge->indirect_info
+         = (new (ggc_alloc<cgraph_simple_indirect_info> ())
+            cgraph_simple_indirect_info (ecf_flags));
+      else
+       edge->indirect_info
+         = (new (ggc_alloc<cgraph_indirect_call_info> ())
+            cgraph_indirect_call_info(CIIK_UNSPECIFIED, ecf_flags));
     }
 
   edge->next_callee = indirect_calls;
@@ -2666,30 +2654,8 @@ cgraph_node::dump (FILE *f)
 
   for (edge = indirect_calls; edge; edge = edge->next_callee)
     {
-      if (edge->indirect_info->polymorphic)
-       {
-         fprintf (f, "   Polymorphic indirect call of type ");
-         print_generic_expr (f, edge->indirect_info->otr_type, TDF_SLIM);
-         fprintf (f, " token:%i", (int) edge->indirect_info->otr_token);
-       }
-      else
-       fprintf (f, "   Indirect call");
-      edge->dump_edge_flags (f);
-      if (edge->indirect_info->param_index != -1)
-       {
-         fprintf (f, "of param:%i ", edge->indirect_info->param_index);
-         if (edge->indirect_info->agg_contents)
-          fprintf (f, "loaded from %s %s at offset %i ",
-                   edge->indirect_info->member_ptr ? "member ptr" : "aggregate",
-                   edge->indirect_info->by_ref ? "passed by reference" : "",
-                   (int)edge->indirect_info->offset);
-         if (edge->indirect_info->vptr_changed)
-           fprintf (f, "(vptr maybe changed) ");
-       }
-      fprintf (f, "num speculative call targets: %i\n",
-              edge->indirect_info->num_speculative_call_targets);
-      if (edge->indirect_info->polymorphic)
-       edge->indirect_info->context.dump (f);
+      fprintf (f, "   ");
+      edge->indirect_info->dump (f);
     }
 }
 
@@ -2729,6 +2695,57 @@ cgraph_node::dump_cgraph (FILE *f)
     node->dump (f);
 }
 
+/* Dump human readable information about the indirect call to F.  If NEWLINE
+   is true, it will be terminated by a newline.  */
+
+void
+cgraph_indirect_call_info::dump (FILE *f, bool newline) const
+{
+  if (const cgraph_polymorphic_indirect_info *pii
+      = dyn_cast <const cgraph_polymorphic_indirect_info *> (this))
+    {
+      fprintf (f, "    indirect polymorphic callsite, %s, "
+              "calling param %i, offset " HOST_WIDE_INT_PRINT_DEC
+              "otr_token " HOST_WIDE_INT_PRINT_DEC ", otr_type ",
+              pii->vptr_changed ? "vptr_changed" : "vptr not changed",
+              pii->param_index, pii->offset, pii->otr_token);
+      print_generic_expr (f, pii->otr_type);
+      fprintf (f, ", context ");
+      pii->context.dump (f, false);
+    }
+  else if (const cgraph_simple_indirect_info *sii
+          = dyn_cast <const cgraph_simple_indirect_info *> (this))
+    {
+      if (sii->agg_contents)
+       fprintf (f, "    indirect %s callsite, calling param %i, "
+                "offset " HOST_WIDE_INT_PRINT_DEC ", %s",
+                sii->member_ptr ? "member ptr" : "aggregate",
+                sii->param_index, sii->offset,
+                sii->by_ref ? "by reference" : "by_value");
+      else if (sii->param_index >= 0)
+       fprintf (f, "    indirect simple callsite, calling param %i",
+                sii->param_index);
+      else
+       fprintf (f, "    indirect simple callsite, not calling a known "
+                "parameter");
+    }
+  else
+    fprintf (f, "    indirect callsite");
+
+  fprintf (f, ", flags %i, num speculative call targets: %i", ecf_flags,
+          num_speculative_call_targets);
+  if (newline)
+    fprintf (f, "\n");
+}
+
+/* Dump human readable information about the indirect call to stderr.  */
+
+void
+cgraph_indirect_call_info::debug () const
+{
+  dump (stderr);
+}
+
 /* Return true when the DECL can possibly be inlined.  */
 
 bool
index 6d589f59442f9c9b9c32b5dea331e6503bccd1cb..b7db8c9e5319f63ae474c68b92b3b59d06ab41be 100644 (file)
@@ -1170,9 +1170,12 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
                            gcall *call_stmt, profile_count count,
                            bool cloning_p = false);
 
-  /* Create an indirect edge with a yet-undetermined callee where the call
-     statement destination is a formal parameter of the caller with index
-     PARAM_INDEX. */
+  /* Create an indirect edge to a (yet-)undetermined callee.  CALL_STMT is the
+     corresponding statement, if available, ECF_FLAGS and COUNT are
+     corresponding gimple call flags and profiling count respectively.
+     CLONING_P should be set if properties that are copied from an original
+     edge should not be calculated.  */
+
   cgraph_edge *create_indirect_edge (gcall *call_stmt, int ecf_flags,
                                     profile_count count,
                                     bool cloning_p = false);
@@ -1703,31 +1706,72 @@ private:
   void make_speculative (tree otr_type = NULL);
 };
 
-/* Structure containing additional information about an indirect call.  */
+/* Denotes the kind of call that a particular cgraph_indirect_call_info
+   instance describes.  */
+
+enum cgraph_indirect_info_kind {
+  /* Unspecified kind.  Only to be used when no information about the call
+     statement is available or it does not fall into any of the other
+     categories.  */
+  CIIK_UNSPECIFIED,
+  /* A normal indirect call when the target is an SSA_NAME.  */
+  CIIK_SIMPLE,
+  /* Call of a virtual method when the target is an OBJ_TYPE_REF which conforms
+     to virtual_method_call_p.  */
+  CIIK_POLYMORPHIC,
+  /* Must be last */
+  CIIK_N_KINDS
+};
+
+/* The base class containing additional information about all kinds of indirect
+   calls.  It can also be used when no information about the call statement is
+   available or it does not fall into any of the other categories.  */
 
-class GTY(()) cgraph_indirect_call_info
+class GTY((desc ("%h.kind"), tag ("CIIK_UNSPECIFIED")))
+         cgraph_indirect_call_info
 {
 public:
-  /* When agg_content is set, an offset where the call pointer is located
-     within the aggregate.  */
-  HOST_WIDE_INT offset;
-  /* Context of the polymorphic call; use only when POLYMORPHIC flag is set.  */
-  ipa_polymorphic_call_context context;
-  /* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set).  */
-  HOST_WIDE_INT otr_token;
-  /* Type of the object from OBJ_TYPE_REF_OBJECT. */
-  tree otr_type;
-  /* Index of the parameter that is called.  */
-  int param_index;
+  cgraph_indirect_call_info (int flags)
+    : ecf_flags (flags), param_index (-1), kind (CIIK_UNSPECIFIED),
+    num_speculative_call_targets (0) {}
+  cgraph_indirect_call_info (enum cgraph_indirect_info_kind k, int flags)
+    : ecf_flags (flags), param_index (-1), kind (k),
+    num_speculative_call_targets (0) {}
+
+  /* Dump human readable information about the indirect call to F.  If NEWLINE
+     is true, it will be terminated by a newline.  */
+  void dump (FILE *f, bool newline = true) const;
+  void DEBUG_FUNCTION debug () const;
+
   /* ECF flags determined from the caller.  */
   int ecf_flags;
+  /* If we can relate this call target to a specific formal parameter of the
+     caller, then this is its index.  Otherwise set to -1.  */
+  int param_index;
 
-  /* Number of speculative call targets, it's less than GCOV_TOPN_VALUES.  */
+  /* Identifier of the specific type of indirect info this actually is.  */
+  enum cgraph_indirect_info_kind kind : 2;
+  /* Number of speculative call targets.  */
   unsigned num_speculative_call_targets : 16;
+};
+
+/* Structure containing additional information about non-virtual indirect calls
+   where the target is an SSA_NAME.  */
+
+class GTY((tag ("CIIK_SIMPLE")))
+         cgraph_simple_indirect_info : public cgraph_indirect_call_info
+{
+public:
+  cgraph_simple_indirect_info (int flags)
+    : cgraph_indirect_call_info (CIIK_SIMPLE, flags), offset (0),
+    agg_contents (false), member_ptr (false), by_ref (false),
+    guaranteed_unmodified (false)
+    {}
+
+  /* When agg_content is set, an offset where the call pointer is located
+     within the aggregate.  */
+  HOST_WIDE_INT offset;
 
-  /* Set when the call is a virtual call with the parameter being the
-     associated object pointer rather than a simple direct call.  */
-  unsigned polymorphic : 1;
   /* Set when the call is a call of a pointer loaded from contents of an
      aggregate at offset.  */
   unsigned agg_contents : 1;
@@ -1741,11 +1785,69 @@ public:
      never modified between the invocation of the function and the load
      point.  */
   unsigned guaranteed_unmodified : 1;
+};
+
+/* Structure containing additional information about non-virtual indirect calls
+   when the target is an OBJ_TYPE_REF which conforms to
+   virtual_method_call_p.  */
+
+class GTY((tag ("CIIK_POLYMORPHIC")))
+         cgraph_polymorphic_indirect_info : public cgraph_indirect_call_info
+{
+public:
+  cgraph_polymorphic_indirect_info (int flags)
+    : cgraph_indirect_call_info (CIIK_POLYMORPHIC, flags), context (),
+    otr_token (0), otr_type (nullptr), offset (0), vptr_changed (true)
+    {}
+  cgraph_polymorphic_indirect_info (int flags,
+                                   const ipa_polymorphic_call_context &ctx,
+                                   HOST_WIDE_INT token, tree type)
+    : cgraph_indirect_call_info (CIIK_POLYMORPHIC, flags), context (ctx),
+    otr_token (token), otr_type (type), offset (0), vptr_changed (true)
+    {}
+
+  /* Return true if the information is usable for devirtualization.  This can
+     happen if part of the required information is not streamed in yet and for
+     some cases we determine it is no longer useful to attempt to use the
+     information too.  */
+  bool usable_p () const
+  {
+    return !!otr_type;
+  }
+  /* Mark this information as not useful for devirtualization.  Return true if
+     it was considered useful until now.  */
+  bool mark_unusable ()
+  {
+    bool r = !!otr_type;
+    otr_type = NULL_TREE;
+    return r;
+  }
+
+  /* Context of the polymorphic call; use only when POLYMORPHIC flag is set.  */
+  ipa_polymorphic_call_context context;
+  /* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set).  */
+  HOST_WIDE_INT otr_token;
+  /* Type of the object from OBJ_TYPE_REF_OBJECT. */
+  tree otr_type;
+  /* The offset from the point where the parameter identified by param_index to
+     the point where the corresponding object appears.  */
+  HOST_WIDE_INT offset;
+
   /* For polymorphic calls this specify whether the virtual table pointer
      may have changed in between function entry and the call.  */
   unsigned vptr_changed : 1;
 };
 
+/* Return true if ii is a cgraph_polymorphic_indirect_info that is usable_p.  */
+
+inline bool
+usable_polymorphic_info_p (cgraph_indirect_call_info *ii)
+{
+  cgraph_polymorphic_indirect_info *pii
+    = dyn_cast <cgraph_polymorphic_indirect_info *> (ii);
+  return pii && pii->usable_p ();
+}
+
 class GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
           for_user)) cgraph_edge
 {
@@ -2311,6 +2413,49 @@ is_a_helper <asm_node *>::test (toplevel_node *p)
   return p && p->type == TOPLEVEL_ASM;
 }
 
+/* Report whether or not THIS indirect info is a known simple one.  */
+
+template <>
+template <>
+inline bool
+is_a_helper <cgraph_simple_indirect_info *>::test (cgraph_indirect_call_info *p)
+{
+  return p && p->kind == CIIK_SIMPLE;
+}
+
+/* Likewise, but const qualified.  */
+
+template <>
+template <>
+inline bool
+is_a_helper <const cgraph_simple_indirect_info *>
+::test (const cgraph_indirect_call_info *p)
+{
+  return p && p->kind == CIIK_SIMPLE;
+}
+
+/* Report whether or not THIS indirect info is a known polymorphic one.  */
+
+template <>
+template <>
+inline bool
+is_a_helper <cgraph_polymorphic_indirect_info *>
+::test (cgraph_indirect_call_info *p)
+{
+  return p && p->kind == CIIK_POLYMORPHIC;
+}
+
+/* Likewise, but const qualified.  */
+
+template <>
+template <>
+inline bool
+is_a_helper <const cgraph_polymorphic_indirect_info *>
+::test (const cgraph_indirect_call_info *p)
+{
+  return p && p->kind == CIIK_POLYMORPHIC;
+}
+
 typedef void (*cgraph_edge_hook)(cgraph_edge *, void *);
 typedef void (*cgraph_node_hook)(cgraph_node *, void *);
 typedef void (*varpool_node_hook)(varpool_node *, void *);
@@ -2734,7 +2879,6 @@ asmname_hasher::equal (symtab_node *n, const_tree t)
 /* In cgraph.cc  */
 void cgraph_cc_finalize (void);
 void release_function_body (tree);
-cgraph_indirect_call_info *cgraph_allocate_init_indirect_info (void);
 
 void cgraph_update_edges_for_call_stmt (gimple *, tree, gimple *);
 bool cgraph_function_possibly_inlined_p (tree);
@@ -3633,8 +3777,9 @@ ipa_ref::address_matters_p ()
 inline
 ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e)
 {
-  gcc_checking_assert (e->indirect_info->polymorphic);
-  *this = e->indirect_info->context;
+  cgraph_polymorphic_indirect_info *pii
+    = as_a <cgraph_polymorphic_indirect_info *> (e->indirect_info);
+  *this = pii->context;
 }
 
 /* Build empty "I know nothing" context.  */
index 816fc53c28a10f5ba481a7473be66f0348c2b302..96ea178ab23a880c035d9406760e58dd50a0d131 100644 (file)
@@ -121,7 +121,22 @@ cgraph_edge::clone (cgraph_node *n, gcall *call_stmt, unsigned stmt_uid,
          new_edge = n->create_indirect_edge (call_stmt,
                                              indirect_info->ecf_flags,
                                              prof_count, true);
-         *new_edge->indirect_info = *indirect_info;
+
+         if (indirect_info->kind == CIIK_POLYMORPHIC)
+           new_edge->indirect_info
+             = (new (ggc_alloc<cgraph_polymorphic_indirect_info> ())
+                cgraph_polymorphic_indirect_info (
+                    *(const cgraph_polymorphic_indirect_info *) indirect_info));
+         else if (indirect_info->kind == CIIK_SIMPLE)
+           new_edge->indirect_info
+             = (new (ggc_alloc<cgraph_simple_indirect_info> ())
+                cgraph_simple_indirect_info (
+                    *(const cgraph_simple_indirect_info *) indirect_info));
+         else
+           new_edge->indirect_info
+             = (new (ggc_alloc<cgraph_indirect_call_info> ())
+                cgraph_indirect_call_info(
+                    *(const cgraph_indirect_call_info *) indirect_info));
        }
     }
   else
index 017c05750bb58c2dc40f17e7cd49e34834076741..8b0a574389f572aec301e5f1252c1f0dca110f16 100644 (file)
@@ -1297,7 +1297,8 @@ analyze_functions (bool first_time)
                  for (edge = cnode->indirect_calls; edge; edge = next)
                    {
                      next = edge->next_callee;
-                     if (edge->indirect_info->polymorphic)
+                     if (is_a <cgraph_polymorphic_indirect_info *>
+                         (edge->indirect_info))
                        walk_polymorphic_call_targets (&reachable_call_targets,
                                                       edge);
                    }
index 2105c9a2ef7f57e4e70bca542b7e942b9aea3bf3..74ec8a7c4b2ee3ae508c6757d81d7f5e6d690ed5 100644 (file)
@@ -1482,13 +1482,10 @@ initialize_node_lattices (struct cgraph_node *node)
     }
 
   for (ie = node->indirect_calls; ie; ie = ie->next_callee)
-    if (ie->indirect_info->polymorphic
-       && ie->indirect_info->param_index >= 0)
-      {
-       gcc_checking_assert (ie->indirect_info->param_index >= 0);
-       ipa_get_parm_lattices (info,
-                              ie->indirect_info->param_index)->virt_call = 1;
-      }
+    if (ie->indirect_info->param_index >= 0
+       && is_a <cgraph_polymorphic_indirect_info *> (ie->indirect_info))
+      ipa_get_parm_lattices (info,
+                            ie->indirect_info->param_index)->virt_call = 1;
 }
 
 /* Return VALUE if it is NULL_TREE or if it can be directly safely IPA-CP
@@ -3106,32 +3103,28 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
                                bool *speculative)
 {
   int param_index = ie->indirect_info->param_index;
-  HOST_WIDE_INT anc_offset;
-  tree t = NULL;
-  tree target = NULL;
-
   *speculative = false;
 
   if (param_index == -1)
     return NULL_TREE;
 
-  if (!ie->indirect_info->polymorphic)
+  if (cgraph_simple_indirect_info *sii
+      = dyn_cast <cgraph_simple_indirect_info *> (ie->indirect_info))
     {
       tree t = NULL;
 
-      if (ie->indirect_info->agg_contents)
+      if (sii->agg_contents)
        {
          t = NULL;
          if ((unsigned) param_index < known_csts.length ()
              && known_csts[param_index])
            t = ipa_find_agg_cst_from_init (known_csts[param_index],
-                                           ie->indirect_info->offset,
-                                           ie->indirect_info->by_ref);
+                                           sii->offset,
+                                           sii->by_ref);
 
-         if (!t && ie->indirect_info->guaranteed_unmodified)
-           t = avs.get_value (param_index,
-                              ie->indirect_info->offset / BITS_PER_UNIT,
-                              ie->indirect_info->by_ref);
+         if (!t && sii->guaranteed_unmodified)
+           t = avs.get_value (param_index, sii->offset / BITS_PER_UNIT,
+                              sii->by_ref);
        }
       else if ((unsigned) param_index < known_csts.length ())
        t = known_csts[param_index];
@@ -3147,23 +3140,22 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
   if (!opt_for_fn (ie->caller->decl, flag_devirtualize))
     return NULL_TREE;
 
-  gcc_assert (!ie->indirect_info->agg_contents);
-  gcc_assert (!ie->indirect_info->by_ref);
-  anc_offset = ie->indirect_info->offset;
-
-  t = NULL;
+  cgraph_polymorphic_indirect_info *pii
+    = as_a <cgraph_polymorphic_indirect_info *> (ie->indirect_info);
+  if (!pii->usable_p ())
+    return NULL_TREE;
 
+  HOST_WIDE_INT anc_offset = pii->offset;
+  tree t = NULL;
+  tree target = NULL;
   if ((unsigned) param_index < known_csts.length ()
       && known_csts[param_index])
-    t = ipa_find_agg_cst_from_init (known_csts[param_index],
-                                   ie->indirect_info->offset, true);
+    t = ipa_find_agg_cst_from_init (known_csts[param_index], anc_offset, true);
 
   /* Try to work out value of virtual table pointer value in replacements.  */
   /* or known aggregate values.  */
   if (!t)
-    t = avs.get_value (param_index,
-                      ie->indirect_info->offset / BITS_PER_UNIT,
-                      true);
+    t = avs.get_value (param_index, anc_offset / BITS_PER_UNIT, true);
 
   /* If we found the virtual table pointer, lookup the target.  */
   if (t)
@@ -3173,8 +3165,8 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
       if (vtable_pointer_value_to_vtable (t, &vtable, &offset))
        {
          bool can_refer;
-         target = gimple_get_virt_method_for_vtable (ie->indirect_info->otr_token,
-                                                     vtable, offset, &can_refer);
+         target = gimple_get_virt_method_for_vtable (pii->otr_token, vtable,
+                                                     offset, &can_refer);
          if (can_refer)
            {
              if (!target
@@ -3183,11 +3175,11 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
                       (ie, cgraph_node::get (target)))
                {
                  /* Do not speculate builtin_unreachable, it is stupid!  */
-                 if (ie->indirect_info->vptr_changed)
+                 if (pii->vptr_changed)
                    return NULL;
                  target = ipa_impossible_devirt_target (ie, target);
                }
-             *speculative = ie->indirect_info->vptr_changed;
+             *speculative = pii->vptr_changed;
              if (!*speculative)
                return target;
            }
@@ -3198,31 +3190,28 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
   if (!t && (unsigned) param_index < known_csts.length ())
     t = known_csts[param_index];
 
-  gcc_checking_assert (!t || TREE_CODE (t) != TREE_BINFO);
-
   ipa_polymorphic_call_context context;
   if (known_contexts.length () > (unsigned int) param_index)
     {
       context = known_contexts[param_index];
       context.offset_by (anc_offset);
-      if (ie->indirect_info->vptr_changed)
+      if (pii->vptr_changed)
        context.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
-                                             ie->indirect_info->otr_type);
+                                             pii->otr_type);
       if (t)
        {
-         ipa_polymorphic_call_context ctx2 = ipa_polymorphic_call_context
-           (t, ie->indirect_info->otr_type, anc_offset);
+         ipa_polymorphic_call_context ctx2
+           = ipa_polymorphic_call_context (t, pii->otr_type, anc_offset);
          if (!ctx2.useless_p ())
-           context.combine_with (ctx2, ie->indirect_info->otr_type);
+           context.combine_with (ctx2, pii->otr_type);
        }
     }
   else if (t)
     {
-      context = ipa_polymorphic_call_context (t, ie->indirect_info->otr_type,
-                                             anc_offset);
-      if (ie->indirect_info->vptr_changed)
+      context = ipa_polymorphic_call_context (t, pii->otr_type, anc_offset);
+      if (pii->vptr_changed)
        context.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
-                                             ie->indirect_info->otr_type);
+                                             pii->otr_type);
     }
   else
     return NULL_TREE;
@@ -3230,10 +3219,8 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
   vec <cgraph_node *>targets;
   bool final;
 
-  targets = possible_polymorphic_call_targets
-    (ie->indirect_info->otr_type,
-     ie->indirect_info->otr_token,
-     context, &final);
+  targets = possible_polymorphic_call_targets (pii->otr_type, pii->otr_token,
+                                              context, &final);
   if (!final || targets.length () > 1)
     {
       struct cgraph_node *node;
@@ -3242,8 +3229,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie,
       if (!opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively)
          || ie->speculative || !ie->maybe_hot_p ())
        return NULL;
-      node = try_speculative_devirtualization (ie->indirect_info->otr_type,
-                                              ie->indirect_info->otr_token,
+      node = try_speculative_devirtualization (pii->otr_type, pii->otr_token,
                                               context);
       if (node)
        {
@@ -4142,8 +4128,12 @@ ipcp_discover_new_direct_edges (struct cgraph_node *node,
                                               avs, &speculative);
       if (target)
        {
-         bool agg_contents = ie->indirect_info->agg_contents;
-         bool polymorphic = ie->indirect_info->polymorphic;
+         cgraph_polymorphic_indirect_info *pii
+           = dyn_cast <cgraph_polymorphic_indirect_info *> (ie->indirect_info);
+         cgraph_simple_indirect_info *sii
+           = dyn_cast <cgraph_simple_indirect_info *> (ie->indirect_info);
+         bool agg_contents = sii && sii->agg_contents;
+         bool polymorphic = !!pii;
          int param_index = ie->indirect_info->param_index;
          struct cgraph_edge *cs = ipa_make_edge_direct_to_target (ie, target,
                                                                   speculative);
index c10d67f1e67405846d21ae10ac31dc69b4c1c59d..69bd73f4240ac85a6680b936e8ae817b621de02b 100644 (file)
@@ -3692,8 +3692,12 @@ ipa_devirt (void)
        fprintf (dump_file, "\n\nProcesing function %s\n",
                 n->dump_name ());
       for (e = n->indirect_calls; e; e = e->next_callee)
-       if (e->indirect_info->polymorphic)
+       if (cgraph_polymorphic_indirect_info *pii
+           = dyn_cast <cgraph_polymorphic_indirect_info *> (e->indirect_info))
          {
+           if (!pii->usable_p ())
+             continue;
+
            void *cache_token;
            bool final;
 
@@ -3725,12 +3729,12 @@ ipa_devirt (void)
               This may need to be revisited once we add further ways to use
               the may edges, but it is a reasonable thing to do right now.  */
 
-           if ((e->indirect_info->param_index == -1
+           if ((pii->param_index == -1
                || (!opt_for_fn (n->decl, flag_devirtualize_speculatively)
-                   && e->indirect_info->vptr_changed))
+                   && pii->vptr_changed))
                && !flag_ltrans_devirtualize)
              {
-               e->indirect_info->polymorphic = false;
+               pii->mark_unusable ();
                ndropped++;
                if (dump_file)
                  fprintf (dump_file, "Dropping polymorphic call info;"
index a9da0b571dbbc3cbdc3a2940501f0f9f5f2f3ded..6eb266851757dce22700b7d4e894370bd55f1fce 100644 (file)
@@ -2758,7 +2758,7 @@ dump_inline_stats (void)
          }
       }
     for (e = node->indirect_calls; e; e = e->next_callee)
-      if (e->indirect_info->polymorphic
+      if (is_a <cgraph_polymorphic_indirect_info *> (e->indirect_info)
          & e->count.ipa ().initialized_p ())
        indirect_poly_cnt += e->count.ipa ().to_gcov_type ();
       else if (e->count.ipa ().initialized_p ())
index e4c0ff5fe3103d905681d8aad1808fcc16ba6df4..8326ccba69b60787788315aaca1259d36f513b1a 100644 (file)
@@ -921,7 +921,7 @@ ipa_profile (void)
                                     "Not speculating: "
                                     "parameter count mismatch\n");
                        }
-                     else if (e->indirect_info->polymorphic
+                     else if (usable_polymorphic_info_p (e->indirect_info)
                               && !opt_for_fn (n->decl, flag_devirtualize)
                               && !possible_polymorphic_call_target_p (e, n2))
                        {
index 2debbe10de38509dc508913f748766cfad69344f..f3d6c19028062beb73328bd6a59c846b6b0153e1 100644 (file)
@@ -599,21 +599,8 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
 
   for (cs = node->indirect_calls; cs; cs = cs->next_callee)
     {
-      class cgraph_indirect_call_info *ii;
-
-      ii = cs->indirect_info;
-      if (ii->agg_contents)
-       fprintf (f, "    indirect %s callsite, calling param %i, "
-                "offset " HOST_WIDE_INT_PRINT_DEC ", %s",
-                ii->member_ptr ? "member ptr" : "aggregate",
-                ii->param_index, ii->offset,
-                ii->by_ref ? "by reference" : "by_value");
-      else
-       fprintf (f, "    indirect %s callsite, calling param %i, "
-                "offset " HOST_WIDE_INT_PRINT_DEC,
-                ii->polymorphic ? "polymorphic" : "simple", ii->param_index,
-                ii->offset);
-
+      fprintf (f, "    ");
+      cs->indirect_info->dump (f, false);
       if (cs->call_stmt)
        {
          fprintf (f, ", for stmt ");
@@ -621,8 +608,6 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
        }
       else
        fprintf (f, "\n");
-      if (ii->polymorphic)
-       ii->context.dump (f);
       if (!ipa_edge_args_info_available_for_edge_p (cs))
        fprintf (f, "       no arg info\n");
       else
@@ -2790,29 +2775,6 @@ ipa_is_ssa_with_stmt_def (tree t)
     return false;
 }
 
-/* Find the indirect call graph edge corresponding to STMT and mark it as a
-   call to a parameter number PARAM_INDEX.  NODE is the caller.  Return the
-   indirect call graph edge.
-   If POLYMORPHIC is true record is as a destination of polymorphic call.  */
-
-static struct cgraph_edge *
-ipa_note_param_call (struct cgraph_node *node, int param_index,
-                    gcall *stmt, bool polymorphic)
-{
-  struct cgraph_edge *cs;
-
-  cs = node->get_edge (stmt);
-  cs->indirect_info->param_index = param_index;
-  cs->indirect_info->agg_contents = 0;
-  cs->indirect_info->member_ptr = 0;
-  cs->indirect_info->guaranteed_unmodified = 0;
-  ipa_node_params *info = ipa_node_params_sum->get (node);
-  ipa_set_param_used_by_indirect_call (info, param_index, true);
-  if (cs->indirect_info->polymorphic || polymorphic)
-    ipa_set_param_used_by_polymorphic_call (info, param_index, true);
-  return cs;
-}
-
 /* Analyze the CALL and examine uses of formal parameters of the caller NODE
    (described by INFO).  PARMS_AINFO is a pointer to a vector containing
    intermediate information about each formal parameter.  Currently it checks
@@ -2886,7 +2848,14 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
       tree var = SSA_NAME_VAR (target);
       int index = ipa_get_param_decl_index (info, var);
       if (index >= 0)
-       ipa_note_param_call (fbi->node, index, call, false);
+       {
+         cgraph_edge *cs = fbi->node->get_edge (call);
+         cgraph_simple_indirect_info *sii =
+           as_a <cgraph_simple_indirect_info *> (cs->indirect_info);
+         sii->param_index = index;
+         gcc_assert (!sii->agg_contents && !sii->member_ptr);
+         ipa_set_param_used_by_indirect_call (info, index, true);
+       }
       return;
     }
 
@@ -2898,12 +2867,16 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
                                 gimple_assign_rhs1 (def), &index, &offset,
                                 NULL, &by_ref, &guaranteed_unmodified))
     {
-      struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
-                                                   call, false);
-      cs->indirect_info->offset = offset;
-      cs->indirect_info->agg_contents = 1;
-      cs->indirect_info->by_ref = by_ref;
-      cs->indirect_info->guaranteed_unmodified = guaranteed_unmodified;
+      cgraph_edge *cs = fbi->node->get_edge (call);
+      cgraph_simple_indirect_info *sii =
+       as_a <cgraph_simple_indirect_info *> (cs->indirect_info);
+      sii->param_index = index;
+      sii->offset = offset;
+      sii->agg_contents = 1;
+      sii->by_ref = by_ref;
+      sii->guaranteed_unmodified = guaranteed_unmodified;
+      gcc_assert (!sii->member_ptr);
+      ipa_set_param_used_by_indirect_call (info, index, true);
       return;
     }
 
@@ -3027,14 +3000,16 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
       by_ref = false;
     }
 
-  struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
-                                               call, false);
-  cs->indirect_info->offset = offset;
-  cs->indirect_info->agg_contents = 1;
-  cs->indirect_info->member_ptr = 1;
-  cs->indirect_info->by_ref = by_ref;
-  cs->indirect_info->guaranteed_unmodified = 1;
-
+  cgraph_edge *cs = fbi->node->get_edge (call);
+  cgraph_simple_indirect_info *sii =
+    as_a <cgraph_simple_indirect_info *> (cs->indirect_info);
+  sii->param_index = index;
+  sii->offset = offset;
+  sii->agg_contents = 1;
+  sii->member_ptr = 1;
+  sii->by_ref = by_ref;
+  sii->guaranteed_unmodified = 1;
+  ipa_set_param_used_by_indirect_call (info, index, true);
   return;
 }
 
@@ -3086,13 +3061,15 @@ ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi,
        return;
     }
 
-  struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
-                                               call, true);
-  class cgraph_indirect_call_info *ii = cs->indirect_info;
-  ii->offset = anc_offset;
-  ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
-  ii->otr_type = obj_type_ref_class (target);
-  ii->polymorphic = 1;
+  cgraph_edge *cs = fbi->node->get_edge (call);
+  cgraph_polymorphic_indirect_info *pii =
+    as_a <cgraph_polymorphic_indirect_info *> (cs->indirect_info);
+  pii->param_index = index;
+  pii->offset = anc_offset;
+  gcc_assert (pii->otr_token == tree_to_shwi (OBJ_TYPE_REF_TOKEN (target)));
+  gcc_assert (pii->otr_type = obj_type_ref_class (target));
+  ipa_set_param_used_by_indirect_call (info, index, true);
+  ipa_set_param_used_by_polymorphic_call (info, index, true);
 }
 
 /* Analyze a call statement CALL whether and how it utilizes formal parameters
@@ -3115,24 +3092,26 @@ ipa_analyze_call_uses (struct ipa_func_body_info *fbi, gcall *call)
   if (cs && !cs->indirect_unknown_callee)
     return;
 
-  if (cs->indirect_info->polymorphic && flag_devirtualize)
+  cgraph_polymorphic_indirect_info *pii;
+  if (flag_devirtualize
+      && (pii
+         = dyn_cast <cgraph_polymorphic_indirect_info *> (cs->indirect_info)))
     {
       tree instance;
       tree target = gimple_call_fn (call);
       ipa_polymorphic_call_context context (current_function_decl,
                                            target, call, &instance);
 
-      gcc_checking_assert (cs->indirect_info->otr_type
-                          == obj_type_ref_class (target));
-      gcc_checking_assert (cs->indirect_info->otr_token
+      gcc_checking_assert (pii->otr_type == obj_type_ref_class (target));
+      gcc_checking_assert (pii->otr_token
                           == tree_to_shwi (OBJ_TYPE_REF_TOKEN (target)));
 
-      cs->indirect_info->vptr_changed
+      pii->vptr_changed
        = !context.get_dynamic_type (instance,
                                     OBJ_TYPE_REF_OBJECT (target),
                                     obj_type_ref_class (target), call,
                                     &fbi->aa_walk_budget);
-      cs->indirect_info->context = context;
+      pii->context = context;
     }
 
   if (TREE_CODE (target) == SSA_NAME)
@@ -3755,16 +3734,17 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
       target = canonicalize_constructor_val (target, NULL);
       if (!target || TREE_CODE (target) != FUNCTION_DECL)
        {
+         cgraph_simple_indirect_info *sii
+           = dyn_cast <cgraph_simple_indirect_info *> (ie->indirect_info);
          /* Member pointer call that goes through a VMT lookup.  */
-         if (ie->indirect_info->member_ptr
+         if ((sii && sii->member_ptr)
              /* Or if target is not an invariant expression and we do not
                 know if it will evaulate to function at runtime.
                 This can happen when folding through &VAR, where &VAR
                 is IP invariant, but VAR itself is not.
 
-                TODO: Revisit this when GCC 5 is branched.  It seems that
-                member_ptr check is not needed and that we may try to fold
-                the expression and see if VAR is readonly.  */
+                TODO: It seems that we may try to fold the expression and see
+                if VAR is readonly.  */
              || !is_gimple_ip_invariant (target))
            {
              if (dump_enabled_p ())
@@ -3857,7 +3837,8 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
     {
       fprintf (dump_file, "ipa-prop: Discovered %s call to a %s target "
               "(%s -> %s), for stmt ",
-              ie->indirect_info->polymorphic ? "a virtual" : "an indirect",
+              is_a <cgraph_polymorphic_indirect_info *> (ie->indirect_info)
+              ? "a virtual" : "an indirect",
               speculative ? "speculative" : "known",
               ie->caller->dump_name (),
               callee->dump_name ());
@@ -4114,26 +4095,25 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie,
                                  struct cgraph_node *new_root,
                                  class ipa_node_params *new_root_info)
 {
-  struct cgraph_edge *cs;
   tree target = NULL_TREE;
-  bool agg_contents = ie->indirect_info->agg_contents;
+  cgraph_simple_indirect_info *sii
+    = as_a <cgraph_simple_indirect_info *> (ie->indirect_info);
+  bool agg_contents = sii->agg_contents;
   tree scalar = ipa_value_from_jfunc (new_root_info, jfunc, target_type);
   if (agg_contents)
     {
       if (scalar)
-       target = ipa_find_agg_cst_from_init (scalar, ie->indirect_info->offset,
-                                            ie->indirect_info->by_ref);
-      if (!target && ie->indirect_info->guaranteed_unmodified)
+       target = ipa_find_agg_cst_from_init (scalar, sii->offset, sii->by_ref);
+      if (!target && sii->guaranteed_unmodified)
        target = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info,
-                                                   new_root,
-                                                   ie->indirect_info->offset,
-                                                   ie->indirect_info->by_ref);
+                                                   new_root, sii->offset,
+                                                   sii->by_ref);
     }
   else
     target = scalar;
   if (!target)
     return NULL;
-  cs = ipa_make_edge_direct_to_target (ie, target);
+  cgraph_edge *cs = ipa_make_edge_direct_to_target (ie, target);
 
   if (cs && !agg_contents)
     {
@@ -4193,11 +4173,13 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
 
   if (!opt_for_fn (ie->caller->decl, flag_devirtualize))
     return NULL;
-
-  gcc_assert (!ie->indirect_info->by_ref);
+  cgraph_polymorphic_indirect_info *pii
+    = as_a <cgraph_polymorphic_indirect_info *> (ie->indirect_info);
+  if (!pii->usable_p ())
+    return nullptr;
 
   /* Try to do lookup via known virtual table pointer value.  */
-  if (!ie->indirect_info->vptr_changed
+  if (!pii->vptr_changed
       || opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively))
     {
       tree vtable;
@@ -4205,16 +4187,15 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
       tree t = NULL_TREE;
       if (jfunc->type == IPA_JF_CONST)
        t = ipa_find_agg_cst_from_init (ipa_get_jf_constant (jfunc),
-                                       ie->indirect_info->offset, true);
+                                       pii->offset, true);
       if (!t)
        t = ipa_find_agg_cst_from_jfunc_items (&jfunc->agg, new_root_info,
-                                              new_root,
-                                              ie->indirect_info->offset, true);
+                                              new_root, pii->offset, true);
       if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset))
        {
          bool can_refer;
-         t = gimple_get_virt_method_for_vtable (ie->indirect_info->otr_token,
-                                                vtable, offset, &can_refer);
+         t = gimple_get_virt_method_for_vtable (pii->otr_token, vtable, offset,
+                                                &can_refer);
          if (can_refer)
            {
              if (!t
@@ -4224,7 +4205,7 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
                       (ie, cgraph_node::get (t)))
                {
                  /* Do not speculate builtin_unreachable, it is stupid!  */
-                 if (!ie->indirect_info->vptr_changed)
+                 if (!pii->vptr_changed)
                    target = ipa_impossible_devirt_target (ie, target);
                  else
                    target = NULL;
@@ -4232,7 +4213,7 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
              else
                {
                  target = t;
-                 speculative = ie->indirect_info->vptr_changed;
+                 speculative = pii->vptr_changed;
                }
            }
        }
@@ -4242,15 +4223,13 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
   vec <cgraph_node *>targets;
   bool final;
 
-  ctx.offset_by (ie->indirect_info->offset);
-  if (ie->indirect_info->vptr_changed)
+  ctx.offset_by (pii->offset);
+  if (pii->vptr_changed)
     ctx.possible_dynamic_type_change (ie->in_polymorphic_cdtor,
-                                     ie->indirect_info->otr_type);
-  ctx.combine_with (ie_context, ie->indirect_info->otr_type);
-  targets = possible_polymorphic_call_targets
-    (ie->indirect_info->otr_type,
-     ie->indirect_info->otr_token,
-     ctx, &final);
+                                     pii->otr_type);
+  ctx.combine_with (ie_context, pii->otr_type);
+  targets = possible_polymorphic_call_targets (pii->otr_type, pii->otr_token,
+                                              ctx, &final);
   if (final && targets.length () <= 1)
     {
       speculative = false;
@@ -4259,13 +4238,13 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
       else
        target = ipa_impossible_devirt_target (ie, NULL_TREE);
     }
-  else if (!target && opt_for_fn (ie->caller->decl, flag_devirtualize_speculatively)
+  else if (!target && opt_for_fn (ie->caller->decl,
+                                 flag_devirtualize_speculatively)
           && !ie->speculative && ie->maybe_hot_p ())
     {
       cgraph_node *n;
-      n = try_speculative_devirtualization (ie->indirect_info->otr_type,
-                                           ie->indirect_info->otr_token,
-                                           ie->indirect_info->context);
+      n = try_speculative_devirtualization (pii->otr_type, pii->otr_token,
+                                           pii->context);
       if (n)
        {
          target = n->decl;
@@ -4299,39 +4278,36 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
                                      struct cgraph_node *node,
                                      vec<cgraph_edge *> *new_edges)
 {
-  class ipa_edge_args *top;
-  struct cgraph_edge *ie, *next_ie, *new_direct_edge;
-  struct cgraph_node *new_root;
-  class ipa_node_params *new_root_info, *inlined_node_info;
   bool res = false;
 
   ipa_check_create_edge_args ();
-  top = ipa_edge_args_sum->get (cs);
-  new_root = cs->caller->inlined_to
-               ? cs->caller->inlined_to : cs->caller;
-  new_root_info = ipa_node_params_sum->get (new_root);
-  inlined_node_info = ipa_node_params_sum->get (cs->callee->function_symbol ());
+  class ipa_edge_args *top = ipa_edge_args_sum->get (cs);
+  if (!top)
+    return res;
+  cgraph_node *new_root
+    = cs->caller->inlined_to ? cs->caller->inlined_to : cs->caller;
+  ipa_node_params *new_root_info = ipa_node_params_sum->get (new_root);
+  ipa_node_params *inlined_node_info
+    = ipa_node_params_sum->get (cs->callee->function_symbol ());
 
-  for (ie = node->indirect_calls; ie; ie = next_ie)
+  cgraph_edge *next_ie;
+  for (cgraph_edge *ie = node->indirect_calls; ie; ie = next_ie)
     {
-      class cgraph_indirect_call_info *ici = ie->indirect_info;
-      struct ipa_jump_func *jfunc;
-      int param_index;
-
       next_ie = ie->next_callee;
 
-      if (ici->param_index == -1)
-       continue;
-
-      /* We must check range due to calls with variable number of arguments:  */
-      if (!top || ici->param_index >= ipa_get_cs_argument_count (top))
+      if (ie->indirect_info->param_index < 0
+         || ie->indirect_info->param_index >= ipa_get_cs_argument_count (top))
        {
-         ici->param_index = -1;
+         ie->indirect_info->param_index = -1;
          continue;
        }
 
-      param_index = ici->param_index;
-      jfunc = ipa_get_ith_jump_func (top, param_index);
+      int param_index = ie->indirect_info->param_index;
+      cgraph_polymorphic_indirect_info *pii
+       = dyn_cast <cgraph_polymorphic_indirect_info *> (ie->indirect_info);
+      cgraph_simple_indirect_info *sii
+       = dyn_cast <cgraph_simple_indirect_info *> (ie->indirect_info);
+      struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (top, param_index);
 
       auto_vec<cgraph_node *, 4> spec_targets;
       if (ie->speculative)
@@ -4340,9 +4316,10 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
             direct = direct->next_speculative_call_target ())
          spec_targets.safe_push (direct->callee);
 
+      cgraph_edge *new_direct_edge;
       if (!opt_for_fn (node->decl, flag_indirect_inlining))
        new_direct_edge = NULL;
-      else if (ici->polymorphic)
+      else if (pii)
        {
           ipa_polymorphic_call_context ctx;
          ctx = ipa_context_from_jfunc (new_root_info, cs, param_index, jfunc);
@@ -4350,7 +4327,7 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
                                                               new_root,
                                                               new_root_info);
        }
-      else
+      else if (sii)
        {
          tree target_type =  ipa_get_type (inlined_node_info, param_index);
          new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc,
@@ -4358,6 +4335,8 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
                                                              new_root,
                                                              new_root_info);
        }
+      else
+       gcc_unreachable ();
 
       /* If speculation was removed, then we need to do nothing.  */
       if (new_direct_edge && new_direct_edge != ie
@@ -4384,46 +4363,52 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
       if (jfunc->type == IPA_JF_PASS_THROUGH
           && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
        {
-         if (ici->agg_contents
-             && !ipa_get_jf_pass_through_agg_preserved (jfunc)
-             && !ici->polymorphic)
-           ici->param_index = -1;
+         if (!pii
+             && sii->agg_contents
+             && !ipa_get_jf_pass_through_agg_preserved (jfunc))
+           ie->indirect_info->param_index = -1;
          else
            {
-             ici->param_index = ipa_get_jf_pass_through_formal_id (jfunc);
-             if (ici->polymorphic
-                 && !ipa_get_jf_pass_through_type_preserved (jfunc))
-               ici->vptr_changed = true;
-             ipa_set_param_used_by_indirect_call (new_root_info,
-                                                  ici->param_index, true);
-             if (ici->polymorphic)
-               ipa_set_param_used_by_polymorphic_call (new_root_info,
-                                                       ici->param_index, true);
+             param_index = ipa_get_jf_pass_through_formal_id (jfunc);
+             ie->indirect_info->param_index = param_index;
+             ipa_set_param_used_by_indirect_call (new_root_info, param_index,
+                                                  true);
+             if (pii)
+               {
+                 if (!ipa_get_jf_pass_through_type_preserved (jfunc))
+                   pii->vptr_changed = true;
+                 ipa_set_param_used_by_polymorphic_call (new_root_info,
+                                                         param_index, true);
+               }
            }
        }
       else if (jfunc->type == IPA_JF_ANCESTOR)
        {
-         if (ici->agg_contents
-             && !ipa_get_jf_ancestor_agg_preserved (jfunc)
-             && !ici->polymorphic)
-           ici->param_index = -1;
+         if (!pii
+             && sii->agg_contents
+             && !ipa_get_jf_ancestor_agg_preserved (jfunc))
+           ie->indirect_info->param_index = -1;
          else
            {
-             ici->param_index = ipa_get_jf_ancestor_formal_id (jfunc);
-             ici->offset += ipa_get_jf_ancestor_offset (jfunc);
-             if (ici->polymorphic
-                 && !ipa_get_jf_ancestor_type_preserved (jfunc))
-               ici->vptr_changed = true;
-             ipa_set_param_used_by_indirect_call (new_root_info,
-                                                  ici->param_index, true);
-             if (ici->polymorphic)
-               ipa_set_param_used_by_polymorphic_call (new_root_info,
-                                                       ici->param_index, true);
+             param_index = ipa_get_jf_ancestor_formal_id (jfunc);
+             ie->indirect_info->param_index = param_index;
+             ipa_set_param_used_by_indirect_call (new_root_info, param_index,
+                                                  true);
+             if (pii)
+               {
+                 pii->offset += ipa_get_jf_ancestor_offset (jfunc);
+                 if (!ipa_get_jf_ancestor_type_preserved (jfunc))
+                   pii->vptr_changed = true;
+                 ipa_set_param_used_by_polymorphic_call (new_root_info,
+                                                         param_index, true);
+               }
+             else
+               sii->offset += ipa_get_jf_ancestor_offset (jfunc);
            }
        }
       else
        /* Either we can find a destination for this edge now or never. */
-       ici->param_index = -1;
+       ie->indirect_info->param_index = -1;
     }
 
   return res;
@@ -5312,29 +5297,44 @@ static void
 ipa_write_indirect_edge_info (struct output_block *ob,
                              struct cgraph_edge *cs)
 {
-  class cgraph_indirect_call_info *ii = cs->indirect_info;
   struct bitpack_d bp;
 
-  streamer_write_hwi (ob, ii->param_index);
   bp = bitpack_create (ob->main_stream);
-  bp_pack_value (&bp, ii->polymorphic, 1);
-  bp_pack_value (&bp, ii->agg_contents, 1);
-  bp_pack_value (&bp, ii->member_ptr, 1);
-  bp_pack_value (&bp, ii->by_ref, 1);
-  bp_pack_value (&bp, ii->guaranteed_unmodified, 1);
-  bp_pack_value (&bp, ii->vptr_changed, 1);
+  bp_pack_enum (&bp, cgraph_indirect_info_kind, CIIK_N_KINDS,
+               cs->indirect_info->kind);
   streamer_write_bitpack (&bp);
-  if (ii->agg_contents || ii->polymorphic)
-    streamer_write_hwi (ob, ii->offset);
-  else
-    gcc_assert (ii->offset == 0);
 
-  if (ii->polymorphic)
+  if (cgraph_polymorphic_indirect_info *pii
+      = dyn_cast <cgraph_polymorphic_indirect_info *> (cs->indirect_info))
+    {
+      bp = bitpack_create (ob->main_stream);
+      bp_pack_value (&bp, pii->vptr_changed, 1);
+      streamer_write_bitpack (&bp);
+
+      streamer_write_hwi (ob, pii->param_index);
+      pii->context.stream_out (ob);
+      streamer_write_hwi (ob, pii->otr_token);
+      stream_write_tree (ob, pii->otr_type, true);
+      streamer_write_hwi (ob, pii->offset);
+    }
+  else if (cgraph_simple_indirect_info *sii
+          = dyn_cast <cgraph_simple_indirect_info *> (cs->indirect_info))
     {
-      streamer_write_hwi (ob, ii->otr_token);
-      stream_write_tree (ob, ii->otr_type, true);
-      ii->context.stream_out (ob);
+      bp = bitpack_create (ob->main_stream);
+      bp_pack_value (&bp, sii->agg_contents, 1);
+      bp_pack_value (&bp, sii->member_ptr, 1);
+      bp_pack_value (&bp, sii->by_ref, 1);
+      bp_pack_value (&bp, sii->guaranteed_unmodified, 1);
+      streamer_write_bitpack (&bp);
+
+      streamer_write_hwi (ob, sii->param_index);
+      if (sii->agg_contents)
+       streamer_write_hwi (ob, sii->offset);
+      else
+       gcc_assert (sii->offset == 0);
     }
+  else
+    gcc_assert (cs->indirect_info->param_index == -1);
 }
 
 /* Read in parts of cgraph_indirect_call_info corresponding to CS that are
@@ -5346,35 +5346,50 @@ ipa_read_indirect_edge_info (class lto_input_block *ib,
                             struct cgraph_edge *cs,
                             class ipa_node_params *info)
 {
-  class cgraph_indirect_call_info *ii = cs->indirect_info;
   struct bitpack_d bp;
 
-  ii->param_index = (int) streamer_read_hwi (ib);
   bp = streamer_read_bitpack (ib);
-  ii->polymorphic = bp_unpack_value (&bp, 1);
-  ii->agg_contents = bp_unpack_value (&bp, 1);
-  ii->member_ptr = bp_unpack_value (&bp, 1);
-  ii->by_ref = bp_unpack_value (&bp, 1);
-  ii->guaranteed_unmodified = bp_unpack_value (&bp, 1);
-  ii->vptr_changed = bp_unpack_value (&bp, 1);
-  if (ii->agg_contents || ii->polymorphic)
-    ii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
-  else
-    ii->offset = 0;
-  if (ii->polymorphic)
+  enum cgraph_indirect_info_kind ii_kind
+    = bp_unpack_enum (&bp, cgraph_indirect_info_kind, CIIK_N_KINDS);
+  gcc_assert (ii_kind == cs->indirect_info->kind);
+
+  if (cgraph_polymorphic_indirect_info *pii
+      = dyn_cast <cgraph_polymorphic_indirect_info *> (cs->indirect_info))
     {
-      ii->otr_token = (HOST_WIDE_INT) streamer_read_hwi (ib);
-      ii->otr_type = stream_read_tree (ib, data_in);
-      ii->context.stream_in (ib, data_in);
+      bp = streamer_read_bitpack (ib);
+      pii->vptr_changed = bp_unpack_value (&bp, 1);
+
+      pii->param_index = (int) streamer_read_hwi (ib);
+      pii->context.stream_in (ib, data_in);
+      pii->otr_token = (HOST_WIDE_INT) streamer_read_hwi (ib);
+      pii->otr_type = stream_read_tree (ib, data_in);
+      pii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
+
+      if (info && pii->param_index >= 0)
+       {
+         ipa_set_param_used_by_polymorphic_call (info, pii->param_index, true);
+         ipa_set_param_used_by_indirect_call (info, pii->param_index, true);
+       }
     }
-  if (info && ii->param_index >= 0)
+  else if (cgraph_simple_indirect_info *sii
+          = dyn_cast <cgraph_simple_indirect_info *> (cs->indirect_info))
     {
-      if (ii->polymorphic)
-       ipa_set_param_used_by_polymorphic_call (info,
-                                               ii->param_index , true);
-      ipa_set_param_used_by_indirect_call (info,
-                                          ii->param_index, true);
+      bp = streamer_read_bitpack (ib);
+      sii->agg_contents = bp_unpack_value (&bp, 1);
+      sii->member_ptr = bp_unpack_value (&bp, 1);
+      sii->by_ref = bp_unpack_value (&bp, 1);
+      sii->guaranteed_unmodified = bp_unpack_value (&bp, 1);
+
+      sii->param_index = (int) streamer_read_hwi (ib);
+      if (sii->agg_contents)
+       sii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
+      else
+       sii->offset = 0;
+      if (info && sii->param_index >= 0)
+       ipa_set_param_used_by_indirect_call (info, sii->param_index, true);
     }
+  else
+    cs->indirect_info->param_index = -1;
 }
 
 /* Stream out NODE info to OB.  */
index f33d21e64ce2d564757f826271660b026cb573cb..56d12d1209fd47f0d8aae688882f92e95e003085 100644 (file)
@@ -134,8 +134,11 @@ possible_polymorphic_call_targets (struct cgraph_edge *e,
 {
   ipa_polymorphic_call_context context(e);
 
-  return possible_polymorphic_call_targets (e->indirect_info->otr_type,
-                                           e->indirect_info->otr_token,
+  cgraph_polymorphic_indirect_info *pii
+    = as_a <cgraph_polymorphic_indirect_info *> (e->indirect_info);
+  gcc_checking_assert (pii->usable_p ());
+  return possible_polymorphic_call_targets (pii->otr_type,
+                                           pii->otr_token,
                                            context,
                                            completep, cache_token,
                                            speculative);
@@ -166,8 +169,12 @@ dump_possible_polymorphic_call_targets (FILE *f, struct cgraph_edge *e,
 {
   ipa_polymorphic_call_context context(e);
 
-  dump_possible_polymorphic_call_targets (f, e->indirect_info->otr_type,
-                                         e->indirect_info->otr_token,
+  cgraph_polymorphic_indirect_info *pii
+    = as_a <cgraph_polymorphic_indirect_info *> (e->indirect_info);
+  if (!pii->usable_p ())
+    return;
+  dump_possible_polymorphic_call_targets (f, pii->otr_type,
+                                         pii->otr_token,
                                          context, verbose);
 }
 
@@ -180,8 +187,12 @@ possible_polymorphic_call_target_p (struct cgraph_edge *e,
 {
   ipa_polymorphic_call_context context(e);
 
-  return possible_polymorphic_call_target_p (e->indirect_info->otr_type,
-                                            e->indirect_info->otr_token,
+  cgraph_polymorphic_indirect_info *pii
+    = as_a <cgraph_polymorphic_indirect_info *> (e->indirect_info);
+  if (!pii->usable_p ())
+    return true;
+  return possible_polymorphic_call_target_p (pii->otr_type,
+                                            pii->otr_token,
                                             context, n);
 }
 
index dea22ea0b49178a14c9c41fd32a6b49d9a9c8f42..2c8565eba25b6ae1fcb9c811591697831f6384cc 100644 (file)
@@ -428,7 +428,7 @@ symbol_table::remove_unreachable_nodes (FILE *file)
                  for (e = cnode->indirect_calls; e; e = next)
                    {
                      next = e->next_callee;
-                     if (e->indirect_info->polymorphic)
+                     if (usable_polymorphic_info_p (e->indirect_info))
                        walk_polymorphic_call_targets (&reachable_call_targets,
                                                       e, &first, &reachable);
                    }
index 4c60bf0dd74a74070d7116111879152c34e9ec53..fa38a385e0aa2cf5412539ba6d7154a6f7b428e8 100644 (file)
@@ -286,6 +286,8 @@ lto_output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge,
   bp_pack_value (&bp, edge->in_polymorphic_cdtor, 1);
   if (edge->indirect_unknown_callee)
     {
+      bp_pack_enum (&bp, cgraph_indirect_info_kind, CIIK_N_KINDS,
+                   edge->indirect_info->kind);
       int flags = edge->indirect_info->ecf_flags;
       bp_pack_value (&bp, (flags & ECF_CONST) != 0, 1);
       bp_pack_value (&bp, (flags & ECF_PURE) != 0, 1);
@@ -935,7 +937,7 @@ compute_ltrans_boundary (lto_symtab_encoder_t in_encoder)
       /* Add all possible targets for late devirtualization.  */
       if (flag_ltrans_devirtualize || !flag_wpa)
        for (edge = node->indirect_calls; edge; edge = edge->next_callee)
-         if (edge->indirect_info->polymorphic)
+         if (usable_polymorphic_info_p (edge->indirect_info))
            {
              unsigned int i;
              void *cache_token;
@@ -1523,7 +1525,6 @@ input_edge (class lto_input_block *ib, vec<symtab_node *> nodes,
   profile_count count;
   cgraph_inline_failed_t inline_failed;
   struct bitpack_d bp;
-  int ecf_flags = 0;
 
   caller = dyn_cast<cgraph_node *> (nodes[streamer_read_hwi (ib)]);
   if (caller == NULL || caller->decl == NULL_TREE)
@@ -1546,7 +1547,7 @@ input_edge (class lto_input_block *ib, vec<symtab_node *> nodes,
   speculative_id = bp_unpack_value (&bp, 16);
 
   if (indirect)
-    edge = caller->create_indirect_edge (NULL, 0, count);
+    edge = caller->create_indirect_edge (NULL, 0, count, true);
   else
     edge = caller->create_edge (callee, NULL, count);
 
@@ -1563,6 +1564,9 @@ input_edge (class lto_input_block *ib, vec<symtab_node *> nodes,
   edge->in_polymorphic_cdtor = bp_unpack_value (&bp, 1);
   if (indirect)
     {
+      enum cgraph_indirect_info_kind ii_kind
+       = bp_unpack_enum (&bp, cgraph_indirect_info_kind, CIIK_N_KINDS);
+      int ecf_flags = 0;
       if (bp_unpack_value (&bp, 1))
        ecf_flags |= ECF_CONST;
       if (bp_unpack_value (&bp, 1))
@@ -1575,7 +1579,19 @@ input_edge (class lto_input_block *ib, vec<symtab_node *> nodes,
        ecf_flags |= ECF_NOTHROW;
       if (bp_unpack_value (&bp, 1))
        ecf_flags |= ECF_RETURNS_TWICE;
-      edge->indirect_info->ecf_flags = ecf_flags;
+
+      if (ii_kind == CIIK_POLYMORPHIC)
+       edge->indirect_info
+         = (new (ggc_alloc<cgraph_polymorphic_indirect_info> ())
+            cgraph_polymorphic_indirect_info (ecf_flags));
+      else if (ii_kind == CIIK_SIMPLE)
+       edge->indirect_info
+         = (new (ggc_alloc<cgraph_simple_indirect_info> ())
+            cgraph_simple_indirect_info (ecf_flags));
+      else
+       edge->indirect_info
+         = (new (ggc_alloc<cgraph_indirect_call_info> ())
+            cgraph_indirect_call_info(CIIK_UNSPECIFIED, ecf_flags));
 
       edge->indirect_info->num_speculative_call_targets
        = bp_unpack_value (&bp, 16);
index 9fc1b2d54e34b8eb9833eab86b45a6f9aae03ba9..a989efb431e668dbebb3bd3a42033760b9a5849a 100644 (file)
@@ -5163,9 +5163,13 @@ ipa_tm_insert_gettmclone_call (struct cgraph_node *node,
 
   update_stmt (stmt);
   cgraph_edge *e = cgraph_node::get (current_function_decl)->get_edge (stmt);
-  if (e && e->indirect_info)
-    e->indirect_info->polymorphic = false;
-
+  if (e)
+    {
+      cgraph_polymorphic_indirect_info *pii
+       = dyn_cast <cgraph_polymorphic_indirect_info *> (e->indirect_info);
+      if (pii)
+       pii->mark_unusable ();
+    }
   return true;
 }