Commit ba392339 by Jan Hubicka Committed by Jan Hubicka

cgraph.h (class ipa_polymorphic_call_context): Move here from ipa-utils.h; add…

cgraph.h (class ipa_polymorphic_call_context): Move here from ipa-utils.h; add stream_int and stream_out methods.


	* cgraph.h (class ipa_polymorphic_call_context): Move here from
	ipa-utils.h; add stream_int and stream_out methods.
	(cgraph_indirect_call_info): Remove SPECILATIVE_OFFSET,
	OUTER_TYPE, SPECULATIVE_OUTER_TYPE, MAYBE_IN_CONSTRUCTION
	MAYBE_DERIVED_TYPE and SPECULATIEVE_MAYBE_DERIVED_TYPE;
	add CONTEXT.
	(ipa_polymorphic_call_context::ipa_polymorphic_call_context,
	ipa_polymorphic_call_context::ipa_polymorphic_call_context,
	ipa_polymorphic_call_context::clear_speculation,
	ipa_polymorphic_call_context::clear_outer_type): Move here from
	ipa-utils.h
	* ipa-utils.h (class ipa_polymorphic_call_context): Move to cgraph.h
	(ipa_polymorphic_call_context::ipa_polymorphic_call_context,
	ipa_polymorphic_call_context::ipa_polymorphic_call_context,
	ipa_polymorphic_call_context::clear_speculation,
	ipa_polymorphic_call_context::clear_outer_type): Likewise.
	* ipa-devirt.c: Include data-streamer.h, lto-streamer.h and
	streamer-hooks.h
	(ipa_polymorphic_call_context::stream_out): New method.
	(ipa_polymorphic_call_context::stream_in): New method.
	(noncall_stmt_may_be_vtbl_ptr_store): Add forgotten static.
	* ipa-prop.c (ipa_analyze_indirect_call_uses): Do not care about
	OUTER_TYPE.
	(ipa_analyze_call_uses): Simplify.
	(update_indirect_edges_after_inlining): Do not care about outer_type.
	(ipa_write_indirect_edge_info): Update.
	(ipa_write_indirect_edge_info): Likewise.
	* cgraph.c (cgraph_node::create_indirect_edge): Simplify.
	(dump_edge_flags): Break out from ...
	(cgraph_node::dump): ... here; dump indirect edges.

From-SVN: r215575
parent 20149bd2
2014-09-24 Jan Hubicka <hubicka@ucw.cz> 2014-09-24 Jan Hubicka <hubicka@ucw.cz>
* cgraph.h (class ipa_polymorphic_call_context): Move here from
ipa-utils.h; add stream_int and stream_out methods.
(cgraph_indirect_call_info): Remove SPECILATIVE_OFFSET,
OUTER_TYPE, SPECULATIVE_OUTER_TYPE, MAYBE_IN_CONSTRUCTION
MAYBE_DERIVED_TYPE and SPECULATIEVE_MAYBE_DERIVED_TYPE;
add CONTEXT.
(ipa_polymorphic_call_context::ipa_polymorphic_call_context,
ipa_polymorphic_call_context::ipa_polymorphic_call_context,
ipa_polymorphic_call_context::clear_speculation,
ipa_polymorphic_call_context::clear_outer_type): Move here from
ipa-utils.h
* ipa-utils.h (class ipa_polymorphic_call_context): Move to cgraph.h
(ipa_polymorphic_call_context::ipa_polymorphic_call_context,
ipa_polymorphic_call_context::ipa_polymorphic_call_context,
ipa_polymorphic_call_context::clear_speculation,
ipa_polymorphic_call_context::clear_outer_type): Likewise.
* ipa-devirt.c: Include data-streamer.h, lto-streamer.h and
streamer-hooks.h
(ipa_polymorphic_call_context::stream_out): New method.
(ipa_polymorphic_call_context::stream_in): New method.
(noncall_stmt_may_be_vtbl_ptr_store): Add forgotten static.
* ipa-prop.c (ipa_analyze_indirect_call_uses): Do not care about
OUTER_TYPE.
(ipa_analyze_call_uses): Simplify.
(update_indirect_edges_after_inlining): Do not care about outer_type.
(ipa_write_indirect_edge_info): Update.
(ipa_write_indirect_edge_info): Likewise.
* cgraph.c (cgraph_node::create_indirect_edge): Simplify.
(dump_edge_flags): Break out from ...
(cgraph_node::dump): ... here; dump indirect edges.
2014-09-24 Jan Hubicka <hubicka@ucw.cz>
* ipa-utils.h (polymorphic_call_context): Add * ipa-utils.h (polymorphic_call_context): Add
metdhos dump, debug and clear_outer_type. metdhos dump, debug and clear_outer_type.
(ipa_polymorphic_call_context::ipa_polymorphic_call_context): Simplify. (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Simplify.
...@@ -893,16 +893,7 @@ cgraph_node::create_indirect_edge (gimple call_stmt, int ecf_flags, ...@@ -893,16 +893,7 @@ cgraph_node::create_indirect_edge (gimple call_stmt, int ecf_flags,
= tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target)); = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
edge->indirect_info->otr_type = obj_type_ref_class (target); edge->indirect_info->otr_type = obj_type_ref_class (target);
gcc_assert (TREE_CODE (edge->indirect_info->otr_type) == RECORD_TYPE); gcc_assert (TREE_CODE (edge->indirect_info->otr_type) == RECORD_TYPE);
edge->indirect_info->outer_type = context.outer_type; edge->indirect_info->context = context;
edge->indirect_info->speculative_outer_type
= context.speculative_outer_type;
edge->indirect_info->offset = context.offset;
edge->indirect_info->speculative_offset = context.speculative_offset;
edge->indirect_info->maybe_in_construction
= context.maybe_in_construction;
edge->indirect_info->maybe_derived_type = context.maybe_derived_type;
edge->indirect_info->speculative_maybe_derived_type
= context.speculative_maybe_derived_type;
} }
edge->next_callee = indirect_calls; edge->next_callee = indirect_calls;
...@@ -1851,6 +1842,26 @@ cgraph_inline_failed_type (cgraph_inline_failed_t reason) ...@@ -1851,6 +1842,26 @@ cgraph_inline_failed_type (cgraph_inline_failed_t reason)
const char * const cgraph_availability_names[] = const char * const cgraph_availability_names[] =
{"unset", "not_available", "overwritable", "available", "local"}; {"unset", "not_available", "overwritable", "available", "local"};
/* Output flags of edge E. */
static void
dump_edge_flags (FILE *f, struct cgraph_edge *edge)
{
if (edge->speculative)
fprintf (f, "(speculative) ");
if (!edge->inline_failed)
fprintf (f, "(inlined) ");
if (edge->indirect_inlining_edge)
fprintf (f, "(indirect_inlining) ");
if (edge->count)
fprintf (f, "(%"PRId64"x) ",
(int64_t)edge->count);
if (edge->frequency)
fprintf (f, "(%.2f per call) ",
edge->frequency / (double)CGRAPH_FREQ_BASE);
if (edge->can_throw_external)
fprintf (f, "(can throw external) ");
}
/* Dump call graph node to file F. */ /* Dump call graph node to file F. */
...@@ -1858,7 +1869,6 @@ void ...@@ -1858,7 +1869,6 @@ void
cgraph_node::dump (FILE *f) cgraph_node::dump (FILE *f)
{ {
cgraph_edge *edge; cgraph_edge *edge;
int indirect_calls_count = 0;
dump_base (f); dump_base (f);
...@@ -1937,20 +1947,7 @@ cgraph_node::dump (FILE *f) ...@@ -1937,20 +1947,7 @@ cgraph_node::dump (FILE *f)
{ {
fprintf (f, "%s/%i ", edge->caller->asm_name (), fprintf (f, "%s/%i ", edge->caller->asm_name (),
edge->caller->order); edge->caller->order);
if (count) dump_edge_flags (f, edge);
fprintf (f, "(%"PRId64"x) ",
(int64_t)count);
if (frequency)
fprintf (f, "(%.2f per call) ",
frequency / (double)CGRAPH_FREQ_BASE);
if (edge->speculative)
fprintf (f, "(speculative) ");
if (!edge->inline_failed)
fprintf (f, "(inlined) ");
if (edge->indirect_inlining_edge)
fprintf (f, "(indirect_inlining) ");
if (edge->can_throw_external)
fprintf (f, "(can throw external) ");
} }
fprintf (f, "\n Calls: "); fprintf (f, "\n Calls: ");
...@@ -1958,28 +1955,34 @@ cgraph_node::dump (FILE *f) ...@@ -1958,28 +1955,34 @@ cgraph_node::dump (FILE *f)
{ {
fprintf (f, "%s/%i ", edge->callee->asm_name (), fprintf (f, "%s/%i ", edge->callee->asm_name (),
edge->callee->order); edge->callee->order);
if (edge->speculative) dump_edge_flags (f, edge);
fprintf (f, "(speculative) ");
if (!edge->inline_failed)
fprintf (f, "(inlined) ");
if (edge->indirect_inlining_edge)
fprintf (f, "(indirect_inlining) ");
if (edge->count)
fprintf (f, "(%"PRId64"x) ",
(int64_t)count);
if (edge->frequency)
fprintf (f, "(%.2f per call) ",
frequency / (double)CGRAPH_FREQ_BASE);
if (edge->can_throw_external)
fprintf (f, "(can throw external) ");
} }
fprintf (f, "\n"); fprintf (f, "\n");
for (edge = indirect_calls; edge; edge = edge->next_callee) for (edge = indirect_calls; edge; edge = edge->next_callee)
indirect_calls_count++; {
if (indirect_calls_count) if (edge->indirect_info->polymorphic)
fprintf (f, " Has %i outgoing edges for indirect calls.\n", {
indirect_calls_count); 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");
dump_edge_flags (f, edge);
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);
}
fprintf (f, "\n");
if (edge->indirect_info->polymorphic)
edge->indirect_info->context.dump (f);
}
} }
/* Dump call graph node NODE to stderr. */ /* Dump call graph node NODE to stderr. */
......
...@@ -1267,19 +1267,83 @@ struct varpool_node_set_iterator ...@@ -1267,19 +1267,83 @@ struct varpool_node_set_iterator
unsigned index; unsigned index;
}; };
/* Context of polymorphic call. It represent information about the type of
instance that may reach the call. This is used by ipa-devirt walkers of the
type inheritance graph. */
class GTY(()) ipa_polymorphic_call_context {
public:
/* The called object appears in an object of type OUTER_TYPE
at offset OFFSET. When information is not 100% reliable, we
use SPECULATIVE_OUTER_TYPE and SPECULATIVE_OFFSET. */
HOST_WIDE_INT offset;
HOST_WIDE_INT speculative_offset;
tree outer_type;
tree speculative_outer_type;
/* True if outer object may be in construction or destruction. */
bool maybe_in_construction;
/* True if outer object may be of derived type. */
bool maybe_derived_type;
/* True if speculative outer object may be of derived type. We always
speculate that construction does not happen. */
bool speculative_maybe_derived_type;
/* True if the context is invalid and all calls should be redirected
to BUILTIN_UNREACHABLE. */
bool invalid;
/* Build empty "I know nothing" context. */
ipa_polymorphic_call_context ();
/* Build polymorphic call context for indirect call E. */
ipa_polymorphic_call_context (cgraph_edge *e);
/* Build polymorphic call context for IP invariant CST.
If specified, OTR_TYPE specify the type of polymorphic call
that takes CST+OFFSET as a prameter. */
ipa_polymorphic_call_context (tree cst, tree otr_type = NULL,
HOST_WIDE_INT offset = 0);
/* Build context for pointer REF contained in FNDECL at statement STMT.
if INSTANCE is non-NULL, return pointer to the object described by
the context. */
ipa_polymorphic_call_context (tree fndecl, tree ref, gimple stmt,
tree *instance = NULL);
/* Look for vtable stores or constructor calls to work out dynamic type
of memory location. */
bool get_dynamic_type (tree, tree, tree, gimple);
/* Make context non-speculative. */
void clear_speculation ();
/* Walk container types and modify context to point to actual class
containing EXPECTED_TYPE as base class. */
bool restrict_to_inner_class (tree expected_type);
/* Dump human readable context to F. */
void dump (FILE *f) const;
void DEBUG_FUNCTION debug () const;
/* LTO streaming. */
void stream_out (struct output_block *) const;
void stream_in (struct lto_input_block *, struct data_in *data_in);
private:
void set_by_decl (tree, HOST_WIDE_INT);
bool set_by_invariant (tree, tree, HOST_WIDE_INT);
void clear_outer_type (tree otr_type = NULL);
};
/* Structure containing additional information about an indirect call. */ /* Structure containing additional information about an indirect call. */
struct GTY(()) cgraph_indirect_call_info struct GTY(()) cgraph_indirect_call_info
{ {
/* When polymorphic is set, this field contains offset where the object which /* When agg_content is set, an offset where the call pointer is located
was actually used in the polymorphic resides within a larger structure. within the aggregate. */
If agg_contents is set, the field contains the offset within the aggregate HOST_WIDE_INT offset;
from which the address to call was loaded. */ /* Context of the polymorphic call; use only when POLYMORPHIC flag is set. */
HOST_WIDE_INT offset, speculative_offset; ipa_polymorphic_call_context context;
/* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set). */ /* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set). */
HOST_WIDE_INT otr_token; HOST_WIDE_INT otr_token;
/* Type of the object from OBJ_TYPE_REF_OBJECT. */ /* Type of the object from OBJ_TYPE_REF_OBJECT. */
tree otr_type, outer_type, speculative_outer_type; tree otr_type;
/* Index of the parameter that is called. */ /* Index of the parameter that is called. */
int param_index; int param_index;
/* ECF flags determined from the caller. */ /* ECF flags determined from the caller. */
...@@ -1300,9 +1364,6 @@ struct GTY(()) cgraph_indirect_call_info ...@@ -1300,9 +1364,6 @@ struct GTY(()) cgraph_indirect_call_info
/* When the previous bit is set, this one determines whether the destination /* When the previous bit is set, this one determines whether the destination
is loaded from a parameter passed by reference. */ is loaded from a parameter passed by reference. */
unsigned by_ref : 1; unsigned by_ref : 1;
unsigned int maybe_in_construction : 1;
unsigned int maybe_derived_type : 1;
unsigned int speculative_maybe_derived_type : 1;
}; };
struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgraph_edge { struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgraph_edge {
...@@ -2532,4 +2593,45 @@ inline symtab_node * symtab_node::get_create (tree node) ...@@ -2532,4 +2593,45 @@ inline symtab_node * symtab_node::get_create (tree node)
return cgraph_node::get_create (node); return cgraph_node::get_create (node);
} }
/* Build polymorphic call context for indirect call E. */
inline
ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e)
{
gcc_checking_assert (e->indirect_info->polymorphic);
*this = e->indirect_info->context;
}
/* Build empty "I know nothing" context. */
inline
ipa_polymorphic_call_context::ipa_polymorphic_call_context ()
{
clear_speculation ();
clear_outer_type ();
invalid = false;
}
/* Make context non-speculative. */
inline void
ipa_polymorphic_call_context::clear_speculation ()
{
speculative_outer_type = NULL;
speculative_offset = 0;
speculative_maybe_derived_type = false;
}
/* Produce context specifying all derrived types of OTR_TYPE.
If OTR_TYPE is NULL or type of the OBJ_TYPE_REF, the context is set
to dummy "I know nothing" setting. */
inline void
ipa_polymorphic_call_context::clear_outer_type (tree otr_type)
{
outer_type = otr_type ? TYPE_MAIN_VARIANT (otr_type) : NULL;
offset = 0;
maybe_derived_type = true;
maybe_in_construction = true;
}
#endif /* GCC_CGRAPH_H */ #endif /* GCC_CGRAPH_H */
...@@ -135,6 +135,9 @@ along with GCC; see the file COPYING3. If not see ...@@ -135,6 +135,9 @@ along with GCC; see the file COPYING3. If not see
#include "stor-layout.h" #include "stor-layout.h"
#include "intl.h" #include "intl.h"
#include "hash-map.h" #include "hash-map.h"
#include "data-streamer.h"
#include "lto-streamer.h"
#include "streamer-hooks.h"
/* Hash based set of pairs of types. */ /* Hash based set of pairs of types. */
typedef struct typedef struct
...@@ -2570,6 +2573,71 @@ ipa_polymorphic_call_context::debug () const ...@@ -2570,6 +2573,71 @@ ipa_polymorphic_call_context::debug () const
dump (stderr); dump (stderr);
} }
/* Stream out the context to OB. */
void
ipa_polymorphic_call_context::stream_out (struct output_block *ob) const
{
struct bitpack_d bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, invalid, 1);
bp_pack_value (&bp, maybe_in_construction, 1);
bp_pack_value (&bp, maybe_derived_type, 1);
bp_pack_value (&bp, speculative_maybe_derived_type, 1);
bp_pack_value (&bp, outer_type != NULL, 1);
bp_pack_value (&bp, offset != 0, 1);
bp_pack_value (&bp, speculative_outer_type != NULL, 1);
streamer_write_bitpack (&bp);
if (outer_type != NULL)
stream_write_tree (ob, outer_type, true);
if (offset)
streamer_write_hwi (ob, offset);
if (speculative_outer_type != NULL)
{
stream_write_tree (ob, speculative_outer_type, true);
streamer_write_hwi (ob, speculative_offset);
}
else
gcc_assert (!speculative_offset);
}
/* Stream in the context from IB and DATA_IN. */
void
ipa_polymorphic_call_context::stream_in (struct lto_input_block *ib,
struct data_in *data_in)
{
struct bitpack_d bp = streamer_read_bitpack (ib);
invalid = bp_unpack_value (&bp, 1);
maybe_in_construction = bp_unpack_value (&bp, 1);
maybe_derived_type = bp_unpack_value (&bp, 1);
speculative_maybe_derived_type = bp_unpack_value (&bp, 1);
bool outer_type_p = bp_unpack_value (&bp, 1);
bool offset_p = bp_unpack_value (&bp, 1);
bool speculative_outer_type_p = bp_unpack_value (&bp, 1);
if (outer_type_p)
outer_type = stream_read_tree (ib, data_in);
else
outer_type = NULL;
if (offset_p)
offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
else
offset = 0;
if (speculative_outer_type_p)
{
speculative_outer_type = stream_read_tree (ib, data_in);
speculative_offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
}
else
{
speculative_outer_type = NULL;
speculative_offset = 0;
}
}
/* Proudce polymorphic call context for call method of instance /* Proudce polymorphic call context for call method of instance
that is located within BASE (that is assumed to be a decl) at offset OFF. */ that is located within BASE (that is assumed to be a decl) at offset OFF. */
...@@ -2894,7 +2962,7 @@ struct type_change_info ...@@ -2894,7 +2962,7 @@ struct type_change_info
We take advantage of fact that vtable stores must appear within constructor We take advantage of fact that vtable stores must appear within constructor
and destructor functions. */ and destructor functions. */
bool static bool
noncall_stmt_may_be_vtbl_ptr_store (gimple stmt) noncall_stmt_may_be_vtbl_ptr_store (gimple stmt)
{ {
if (is_gimple_assign (stmt)) if (is_gimple_assign (stmt))
......
...@@ -416,6 +416,8 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node) ...@@ -416,6 +416,8 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
} }
else else
fprintf (f, "\n"); fprintf (f, "\n");
if (ii->polymorphic)
ii->context.dump (f);
ipa_print_node_jump_functions_for_edge (f, cs); ipa_print_node_jump_functions_for_edge (f, cs);
} }
} }
...@@ -2153,8 +2155,6 @@ ipa_analyze_indirect_call_uses (struct func_body_info *fbi, gimple call, ...@@ -2153,8 +2155,6 @@ ipa_analyze_indirect_call_uses (struct func_body_info *fbi, gimple call,
NULL, &by_ref)) NULL, &by_ref))
{ {
struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call); struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
if (cs->indirect_info->offset != offset)
cs->indirect_info->outer_type = NULL;
cs->indirect_info->offset = offset; cs->indirect_info->offset = offset;
cs->indirect_info->agg_contents = 1; cs->indirect_info->agg_contents = 1;
cs->indirect_info->by_ref = by_ref; cs->indirect_info->by_ref = by_ref;
...@@ -2255,8 +2255,6 @@ ipa_analyze_indirect_call_uses (struct func_body_info *fbi, gimple call, ...@@ -2255,8 +2255,6 @@ ipa_analyze_indirect_call_uses (struct func_body_info *fbi, gimple call,
&& parm_preserved_before_stmt_p (fbi, index, call, rec)) && parm_preserved_before_stmt_p (fbi, index, call, rec))
{ {
struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call); struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
if (cs->indirect_info->offset != offset)
cs->indirect_info->outer_type = NULL;
cs->indirect_info->offset = offset; cs->indirect_info->offset = offset;
cs->indirect_info->agg_contents = 1; cs->indirect_info->agg_contents = 1;
cs->indirect_info->member_ptr = 1; cs->indirect_info->member_ptr = 1;
...@@ -2345,36 +2343,20 @@ ipa_analyze_call_uses (struct func_body_info *fbi, gimple call) ...@@ -2345,36 +2343,20 @@ ipa_analyze_call_uses (struct func_body_info *fbi, gimple call)
if (cs->indirect_info->polymorphic) if (cs->indirect_info->polymorphic)
{ {
tree otr_type;
HOST_WIDE_INT otr_token;
tree instance; tree instance;
tree target = gimple_call_fn (call); tree target = gimple_call_fn (call);
ipa_polymorphic_call_context context (current_function_decl, ipa_polymorphic_call_context context (current_function_decl,
target, call, &instance); target, call, &instance);
otr_type = obj_type_ref_class (target); gcc_checking_assert (cs->indirect_info->otr_type
otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target)); == obj_type_ref_class (target));
gcc_checking_assert (cs->indirect_info->otr_token
== tree_to_shwi (OBJ_TYPE_REF_TOKEN (target)));
if (context.get_dynamic_type (instance, if (context.get_dynamic_type (instance,
OBJ_TYPE_REF_OBJECT (target), OBJ_TYPE_REF_OBJECT (target),
otr_type, call) obj_type_ref_class (target), call))
&& context.offset == cs->indirect_info->offset) cs->indirect_info->context = context;
{
gcc_assert (TREE_CODE (otr_type) == RECORD_TYPE);
cs->indirect_info->polymorphic = true;
cs->indirect_info->param_index = -1;
cs->indirect_info->otr_token = otr_token;
cs->indirect_info->otr_type = otr_type;
cs->indirect_info->outer_type = context.outer_type;
cs->indirect_info->speculative_outer_type = context.speculative_outer_type;
cs->indirect_info->offset = context.offset;
cs->indirect_info->speculative_offset = context.speculative_offset;
cs->indirect_info->maybe_in_construction
= context.maybe_in_construction;
cs->indirect_info->maybe_derived_type = context.maybe_derived_type;
cs->indirect_info->speculative_maybe_derived_type
= context.speculative_maybe_derived_type;
}
} }
if (TREE_CODE (target) == SSA_NAME) if (TREE_CODE (target) == SSA_NAME)
...@@ -3253,8 +3235,6 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs, ...@@ -3253,8 +3235,6 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
else else
{ {
ici->param_index = ipa_get_jf_ancestor_formal_id (jfunc); ici->param_index = ipa_get_jf_ancestor_formal_id (jfunc);
if (ipa_get_jf_ancestor_offset (jfunc))
ici->outer_type = NULL;
ici->offset += ipa_get_jf_ancestor_offset (jfunc); ici->offset += ipa_get_jf_ancestor_offset (jfunc);
} }
} }
...@@ -4735,25 +4715,22 @@ ipa_write_indirect_edge_info (struct output_block *ob, ...@@ -4735,25 +4715,22 @@ ipa_write_indirect_edge_info (struct output_block *ob,
struct bitpack_d bp; struct bitpack_d bp;
streamer_write_hwi (ob, ii->param_index); streamer_write_hwi (ob, ii->param_index);
streamer_write_hwi (ob, ii->offset);
bp = bitpack_create (ob->main_stream); bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, ii->polymorphic, 1); bp_pack_value (&bp, ii->polymorphic, 1);
bp_pack_value (&bp, ii->agg_contents, 1); bp_pack_value (&bp, ii->agg_contents, 1);
bp_pack_value (&bp, ii->member_ptr, 1); bp_pack_value (&bp, ii->member_ptr, 1);
bp_pack_value (&bp, ii->by_ref, 1); bp_pack_value (&bp, ii->by_ref, 1);
bp_pack_value (&bp, ii->maybe_in_construction, 1);
bp_pack_value (&bp, ii->maybe_derived_type, 1);
bp_pack_value (&bp, ii->speculative_maybe_derived_type, 1);
streamer_write_bitpack (&bp); 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 (ii->polymorphic)
{ {
streamer_write_hwi (ob, ii->otr_token); streamer_write_hwi (ob, ii->otr_token);
stream_write_tree (ob, ii->otr_type, true); stream_write_tree (ob, ii->otr_type, true);
stream_write_tree (ob, ii->outer_type, true); ii->context.stream_out (ob);
stream_write_tree (ob, ii->speculative_outer_type, true);
if (ii->speculative_outer_type)
streamer_write_hwi (ob, ii->speculative_offset);
} }
} }
...@@ -4762,30 +4739,27 @@ ipa_write_indirect_edge_info (struct output_block *ob, ...@@ -4762,30 +4739,27 @@ ipa_write_indirect_edge_info (struct output_block *ob,
static void static void
ipa_read_indirect_edge_info (struct lto_input_block *ib, ipa_read_indirect_edge_info (struct lto_input_block *ib,
struct data_in *data_in ATTRIBUTE_UNUSED, struct data_in *data_in,
struct cgraph_edge *cs) struct cgraph_edge *cs)
{ {
struct cgraph_indirect_call_info *ii = cs->indirect_info; struct cgraph_indirect_call_info *ii = cs->indirect_info;
struct bitpack_d bp; struct bitpack_d bp;
ii->param_index = (int) streamer_read_hwi (ib); ii->param_index = (int) streamer_read_hwi (ib);
ii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
bp = streamer_read_bitpack (ib); bp = streamer_read_bitpack (ib);
ii->polymorphic = bp_unpack_value (&bp, 1); ii->polymorphic = bp_unpack_value (&bp, 1);
ii->agg_contents = bp_unpack_value (&bp, 1); ii->agg_contents = bp_unpack_value (&bp, 1);
ii->member_ptr = bp_unpack_value (&bp, 1); ii->member_ptr = bp_unpack_value (&bp, 1);
ii->by_ref = bp_unpack_value (&bp, 1); ii->by_ref = bp_unpack_value (&bp, 1);
ii->maybe_in_construction = bp_unpack_value (&bp, 1); if (ii->agg_contents || ii->polymorphic)
ii->maybe_derived_type = bp_unpack_value (&bp, 1); ii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
ii->speculative_maybe_derived_type = bp_unpack_value (&bp, 1); else
ii->offset = 0;
if (ii->polymorphic) if (ii->polymorphic)
{ {
ii->otr_token = (HOST_WIDE_INT) streamer_read_hwi (ib); ii->otr_token = (HOST_WIDE_INT) streamer_read_hwi (ib);
ii->otr_type = stream_read_tree (ib, data_in); ii->otr_type = stream_read_tree (ib, data_in);
ii->outer_type = stream_read_tree (ib, data_in); ii->context.stream_in (ib, data_in);
ii->speculative_outer_type = stream_read_tree (ib, data_in);
if (ii->speculative_outer_type)
ii->speculative_offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
} }
} }
......
...@@ -34,114 +34,6 @@ struct ipa_dfs_info { ...@@ -34,114 +34,6 @@ struct ipa_dfs_info {
PTR aux; PTR aux;
}; };
/* Context of polymorphic call. This is used by ipa-devirt walkers of the
type inheritance graph. */
class ipa_polymorphic_call_context {
public:
/* The called object appears in an object of type OUTER_TYPE
at offset OFFSET. When information is not 100% reliable, we
use SPECULATIVE_OUTER_TYPE and SPECULATIVE_OFFSET. */
HOST_WIDE_INT offset;
HOST_WIDE_INT speculative_offset;
tree outer_type;
tree speculative_outer_type;
/* True if outer object may be in construction or destruction. */
bool maybe_in_construction;
/* True if outer object may be of derived type. */
bool maybe_derived_type;
/* True if speculative outer object may be of derived type. We always
speculate that construction does not happen. */
bool speculative_maybe_derived_type;
/* True if the context is invalid and all calls should be redirected
to BUILTIN_UNREACHABLE. */
bool invalid;
/* Build empty "I know nothing" context. */
ipa_polymorphic_call_context ();
/* Build polymorphic call context for indirect call E. */
ipa_polymorphic_call_context (cgraph_edge *e);
/* Build polymorphic call context for IP invariant CST.
If specified, OTR_TYPE specify the type of polymorphic call
that takes CST+OFFSET as a prameter. */
ipa_polymorphic_call_context (tree cst, tree otr_type = NULL,
HOST_WIDE_INT offset = 0);
/* Build context for pointer REF contained in FNDECL at statement STMT.
if INSTANCE is non-NULL, return pointer to the object described by
the context. */
ipa_polymorphic_call_context (tree fndecl, tree ref, gimple stmt,
tree *instance = NULL);
/* Look for vtable stores or constructor calls to work out dynamic type
of memory location. */
bool get_dynamic_type (tree, tree, tree, gimple);
/* Make context non-speculative. */
void clear_speculation ();
/* Walk container types and modify context to point to actual class
containing EXPECTED_TYPE as base class. */
bool restrict_to_inner_class (tree expected_type);
/* Dump human readable context to F. */
void dump (FILE *f) const;
void DEBUG_FUNCTION debug () const;
private:
void set_by_decl (tree, HOST_WIDE_INT);
bool set_by_invariant (tree, tree, HOST_WIDE_INT);
void clear_outer_type (tree otr_type = NULL);
};
/* Build polymorphic call context for indirect call E. */
inline
ipa_polymorphic_call_context::ipa_polymorphic_call_context (cgraph_edge *e)
{
gcc_checking_assert (e->indirect_info->polymorphic);
offset = e->indirect_info->offset;
speculative_offset = e->indirect_info->speculative_offset;
outer_type = e->indirect_info->outer_type;
speculative_outer_type = e->indirect_info->speculative_outer_type;
maybe_in_construction = e->indirect_info->maybe_in_construction;
maybe_derived_type = e->indirect_info->maybe_derived_type;
speculative_maybe_derived_type = e->indirect_info->speculative_maybe_derived_type;
invalid = false;
}
/* Build empty "I know nothing" context. */
inline
ipa_polymorphic_call_context::ipa_polymorphic_call_context ()
{
clear_speculation ();
clear_outer_type ();
invalid = false;
}
/* Make context non-speculative. */
inline void
ipa_polymorphic_call_context::clear_speculation ()
{
speculative_outer_type = NULL;
speculative_offset = 0;
speculative_maybe_derived_type = false;
}
/* Produce context specifying all derrived types of OTR_TYPE.
If OTR_TYPE is NULL or type of the OBJ_TYPE_REF, the context is set
to dummy "I know nothing" setting. */
inline void
ipa_polymorphic_call_context::clear_outer_type (tree otr_type)
{
outer_type = otr_type ? TYPE_MAIN_VARIANT (otr_type) : NULL;
offset = 0;
maybe_derived_type = true;
maybe_in_construction = true;
}
/* In ipa-utils.c */ /* In ipa-utils.c */
void ipa_print_order (FILE*, const char *, struct cgraph_node**, int); void ipa_print_order (FILE*, const char *, struct cgraph_node**, int);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment