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;
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);
}
}
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
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);
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;
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
{
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 *);
/* 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);
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. */
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
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);
}
}
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
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];
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)
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
(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;
}
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;
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;
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)
{
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);
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;
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;"
}
}
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 ())
"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))
{
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 ");
}
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
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
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;
}
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;
}
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;
}
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
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)
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 ())
{
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 ());
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)
{
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;
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
(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;
else
{
target = t;
- speculative = ie->indirect_info->vptr_changed;
+ speculative = pii->vptr_changed;
}
}
}
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;
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;
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)
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);
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,
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
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;
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
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. */
{
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);
{
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);
}
{
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);
}
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);
}
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);
/* 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;
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)
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);
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))
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);
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;
}