Hello, ping, please.
Martin On Wed, Oct 29 2025, Martin Jambor wrote: > Hi, > > 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. > > Bootsstrapped and LTO-bootstrapped and tested on x86_64-linux. OK for > master? > > thanks, > > Martin > > > gcc/ChangeLog: > > 2025-10-17 Martin Jambor <[email protected]> > > * 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. > --- > gcc/cgraph.cc | 145 +++++++++------- > gcc/cgraph.h | 191 ++++++++++++++++++--- > gcc/cgraphclones.cc | 17 +- > gcc/cgraphunit.cc | 3 +- > gcc/ipa-cp.cc | 94 +++++------ > gcc/ipa-devirt.cc | 12 +- > gcc/ipa-inline.cc | 2 +- > gcc/ipa-profile.cc | 2 +- > gcc/ipa-prop.cc | 403 +++++++++++++++++++++++--------------------- > gcc/ipa-utils.h | 23 ++- > gcc/ipa.cc | 2 +- > gcc/lto-cgraph.cc | 24 ++- > gcc/trans-mem.cc | 10 +- > 13 files changed, 573 insertions(+), 355 deletions(-) > > diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc > index d1b2e2a162c..c640dd106c9 100644 > --- a/gcc/cgraph.cc > +++ b/gcc/cgraph.cc > @@ -1161,56 +1161,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; > @@ -2668,30 +2656,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); > } > } > > @@ -2731,6 +2697,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 > diff --git a/gcc/cgraph.h b/gcc/cgraph.h > index 069e007ab71..c1329015342 100644 > --- a/gcc/cgraph.h > +++ b/gcc/cgraph.h > @@ -1152,9 +1152,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); > @@ -1685,31 +1688,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; > @@ -1723,11 +1767,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 > { > @@ -2253,6 +2355,49 @@ is_a_helper <varpool_node *>::test (symtab_node *p) > return p && p->type == SYMTAB_VARIABLE; > } > > +/* 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 *); > @@ -2676,7 +2821,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); > @@ -3575,8 +3719,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. */ > diff --git a/gcc/cgraphclones.cc b/gcc/cgraphclones.cc > index 49f0e58fa1e..3f85c15df6e 100644 > --- a/gcc/cgraphclones.cc > +++ b/gcc/cgraphclones.cc > @@ -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 > diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc > index a81f685654f..cc94a144f2a 100644 > --- a/gcc/cgraphunit.cc > +++ b/gcc/cgraphunit.cc > @@ -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); > } > diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc > index 2105c9a2ef7..74ec8a7c4b2 100644 > --- a/gcc/ipa-cp.cc > +++ b/gcc/ipa-cp.cc > @@ -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); > diff --git a/gcc/ipa-devirt.cc b/gcc/ipa-devirt.cc > index c10d67f1e67..69bd73f4240 100644 > --- a/gcc/ipa-devirt.cc > +++ b/gcc/ipa-devirt.cc > @@ -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;" > diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc > index 1f2287da896..f6c375289fe 100644 > --- a/gcc/ipa-inline.cc > +++ b/gcc/ipa-inline.cc > @@ -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 ()) > diff --git a/gcc/ipa-profile.cc b/gcc/ipa-profile.cc > index e4c0ff5fe31..8326ccba69b 100644 > --- a/gcc/ipa-profile.cc > +++ b/gcc/ipa-profile.cc > @@ -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)) > { > diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc > index c8438d67ee4..3d2a4c279b6 100644 > --- a/gcc/ipa-prop.cc > +++ b/gcc/ipa-prop.cc > @@ -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 > @@ -2789,29 +2774,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 > @@ -2885,7 +2847,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; > } > > @@ -2897,12 +2866,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; > } > > @@ -3026,14 +2999,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; > } > > @@ -3085,13 +3060,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 > @@ -3114,24 +3091,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) > @@ -3754,16 +3733,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 ()) > @@ -3856,7 +3836,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 ()); > @@ -4113,26 +4094,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) > { > @@ -4192,11 +4172,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; > @@ -4204,16 +4186,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 > @@ -4223,7 +4204,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; > @@ -4231,7 +4212,7 @@ try_make_edge_direct_virtual_call (struct cgraph_edge > *ie, > else > { > target = t; > - speculative = ie->indirect_info->vptr_changed; > + speculative = pii->vptr_changed; > } > } > } > @@ -4241,15 +4222,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; > @@ -4258,13 +4237,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; > @@ -4298,39 +4277,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) > @@ -4339,9 +4315,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); > @@ -4349,7 +4326,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, > @@ -4357,6 +4334,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 > @@ -4383,46 +4362,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; > @@ -5311,29 +5296,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 > @@ -5345,35 +5345,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. */ > diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h > index f33d21e64ce..56d12d1209f 100644 > --- a/gcc/ipa-utils.h > +++ b/gcc/ipa-utils.h > @@ -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); > } > > diff --git a/gcc/ipa.cc b/gcc/ipa.cc > index dea22ea0b49..2c8565eba25 100644 > --- a/gcc/ipa.cc > +++ b/gcc/ipa.cc > @@ -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); > } > diff --git a/gcc/lto-cgraph.cc b/gcc/lto-cgraph.cc > index 5708ba046c9..ee4a84932f8 100644 > --- a/gcc/lto-cgraph.cc > +++ b/gcc/lto-cgraph.cc > @@ -284,6 +284,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); > @@ -930,7 +932,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; > @@ -1513,7 +1515,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) > @@ -1536,7 +1537,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); > > @@ -1553,6 +1554,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)) > @@ -1565,7 +1569,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); > diff --git a/gcc/trans-mem.cc b/gcc/trans-mem.cc > index 9fc1b2d54e3..a989efb431e 100644 > --- a/gcc/trans-mem.cc > +++ b/gcc/trans-mem.cc > @@ -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; > } > > -- > 2.51.0
