mirror of git://gcc.gnu.org/git/gcc.git
cgraph.h (cgraph_node): Add predicate prevailing_p.
* cgraph.h (cgraph_node): Add predicate prevailing_p. (cgraph_edge): Add predicate possible_call_in_translation_unit_p. * ipa-prop.c (ipa_write_jump_function): Optimize streaming of ADDR_EXPR. (ipa_read_jump_function): Add prevails parameter; optimize streaming. (ipa_read_edge_info): Break out from ... (ipa_read_node_info): ... here; optimize streaming. * cgraph.c (cgraph_edge::possibly_call_in_translation_unit_p): New predicate. From-SVN: r267175
This commit is contained in:
parent
6263c29d28
commit
f714ecf522
|
|
@ -1,3 +1,14 @@
|
||||||
|
2018-12-15 Jan Hubicka <hubicka@ucw.cz>
|
||||||
|
|
||||||
|
* cgraph.h (cgraph_node): Add predicate prevailing_p.
|
||||||
|
(cgraph_edge): Add predicate possible_call_in_translation_unit_p.
|
||||||
|
* ipa-prop.c (ipa_write_jump_function): Optimize streaming of ADDR_EXPR.
|
||||||
|
(ipa_read_jump_function): Add prevails parameter; optimize streaming.
|
||||||
|
(ipa_read_edge_info): Break out from ...
|
||||||
|
(ipa_read_node_info): ... here; optimize streaming.
|
||||||
|
* cgraph.c (cgraph_edge::possibly_call_in_translation_unit_p): New
|
||||||
|
predicate.
|
||||||
|
|
||||||
2018-12-15 Jan Hubicka <hubicka@ucw.cz>
|
2018-12-15 Jan Hubicka <hubicka@ucw.cz>
|
||||||
|
|
||||||
* ipa-utils.c (ipa_merge_profiles): Do no merging when source function
|
* ipa-utils.c (ipa_merge_profiles): Do no merging when source function
|
||||||
|
|
|
||||||
35
gcc/cgraph.c
35
gcc/cgraph.c
|
|
@ -3766,6 +3766,41 @@ cgraph_edge::sreal_frequency ()
|
||||||
: caller->count);
|
: caller->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* During LTO stream in this can be used to check whether call can possibly
|
||||||
|
be internal to the current translation unit. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
cgraph_edge::possibly_call_in_translation_unit_p (void)
|
||||||
|
{
|
||||||
|
gcc_checking_assert (in_lto_p && caller->prevailing_p ());
|
||||||
|
|
||||||
|
/* While incremental linking we may end up getting function body later. */
|
||||||
|
if (flag_incremental_link == INCREMENTAL_LINK_LTO)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* We may be smarter here and avoid stremaing in indirect calls we can't
|
||||||
|
track, but that would require arranging stremaing the indirect call
|
||||||
|
summary first. */
|
||||||
|
if (!callee)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* If calle is local to the original translation unit, it will be defined. */
|
||||||
|
if (!TREE_PUBLIC (callee->decl) && !DECL_EXTERNAL (callee->decl))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Otherwise we need to lookup prevailing symbol (symbol table is not merged,
|
||||||
|
yet) and see if it is a definition. In fact we may also resolve aliases,
|
||||||
|
but that is probably not too important. */
|
||||||
|
symtab_node *node = callee;
|
||||||
|
for (int n = 10; node->previous_sharing_asm_name && n ; n--)
|
||||||
|
node = node->previous_sharing_asm_name;
|
||||||
|
if (node->previous_sharing_asm_name)
|
||||||
|
node = symtab_node::get_for_asmname (DECL_ASSEMBLER_NAME (callee->decl));
|
||||||
|
gcc_assert (TREE_PUBLIC (node->decl));
|
||||||
|
return node->get_availability () >= AVAIL_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
/* A stashed copy of "symtab" for use by selftest::symbol_table_test.
|
/* A stashed copy of "symtab" for use by selftest::symbol_table_test.
|
||||||
This needs to be a global so that it can be a GC root, and thus
|
This needs to be a global so that it can be a GC root, and thus
|
||||||
prevent the stashed copy from being garbage-collected if the GC runs
|
prevent the stashed copy from being garbage-collected if the GC runs
|
||||||
|
|
|
||||||
17
gcc/cgraph.h
17
gcc/cgraph.h
|
|
@ -308,6 +308,10 @@ public:
|
||||||
/* Return availability of NODE when referenced from REF. */
|
/* Return availability of NODE when referenced from REF. */
|
||||||
enum availability get_availability (symtab_node *ref = NULL);
|
enum availability get_availability (symtab_node *ref = NULL);
|
||||||
|
|
||||||
|
/* During LTO stream-in this predicate can be used to check whether node
|
||||||
|
in question prevails in the linking to save some memory usage. */
|
||||||
|
bool prevailing_p (void);
|
||||||
|
|
||||||
/* Return true if NODE binds to current definition in final executable
|
/* Return true if NODE binds to current definition in final executable
|
||||||
when referenced from REF. If REF is NULL return conservative value
|
when referenced from REF. If REF is NULL return conservative value
|
||||||
for any reference. */
|
for any reference. */
|
||||||
|
|
@ -1730,6 +1734,10 @@ struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
|
||||||
after passes that don't update the cgraph. */
|
after passes that don't update the cgraph. */
|
||||||
static void rebuild_references (void);
|
static void rebuild_references (void);
|
||||||
|
|
||||||
|
/* During LTO stream in this can be used to check whether call can possibly
|
||||||
|
be internal to the current translation unit. */
|
||||||
|
bool possibly_call_in_translation_unit_p (void);
|
||||||
|
|
||||||
/* Expected number of executions: calculated in profile.c. */
|
/* Expected number of executions: calculated in profile.c. */
|
||||||
profile_count count;
|
profile_count count;
|
||||||
cgraph_node *caller;
|
cgraph_node *caller;
|
||||||
|
|
@ -3357,6 +3365,15 @@ xstrdup_for_dump (const char *transient_str)
|
||||||
return ggc_strdup (transient_str);
|
return ggc_strdup (transient_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* During LTO stream-in this predicate can be used to check whether node
|
||||||
|
in question prevails in the linking to save some memory usage. */
|
||||||
|
inline bool
|
||||||
|
symtab_node::prevailing_p (void)
|
||||||
|
{
|
||||||
|
return definition && ((!TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
|
||||||
|
|| previous_sharing_asm_name == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
extern GTY(()) symbol_table *saved_symtab;
|
extern GTY(()) symbol_table *saved_symtab;
|
||||||
|
|
||||||
#if CHECKING_P
|
#if CHECKING_P
|
||||||
|
|
|
||||||
184
gcc/ipa-prop.c
184
gcc/ipa-prop.c
|
|
@ -4053,8 +4053,15 @@ ipa_write_jump_function (struct output_block *ob,
|
||||||
struct ipa_agg_jf_item *item;
|
struct ipa_agg_jf_item *item;
|
||||||
struct bitpack_d bp;
|
struct bitpack_d bp;
|
||||||
int i, count;
|
int i, count;
|
||||||
|
int flag = 0;
|
||||||
|
|
||||||
streamer_write_uhwi (ob, jump_func->type);
|
/* ADDR_EXPRs are very comon IP invariants; save some streamer data
|
||||||
|
as well as WPA memory by handling them specially. */
|
||||||
|
if (jump_func->type == IPA_JF_CONST
|
||||||
|
&& TREE_CODE (jump_func->value.constant.value) == ADDR_EXPR)
|
||||||
|
flag = 1;
|
||||||
|
|
||||||
|
streamer_write_uhwi (ob, jump_func->type * 2 + flag);
|
||||||
switch (jump_func->type)
|
switch (jump_func->type)
|
||||||
{
|
{
|
||||||
case IPA_JF_UNKNOWN:
|
case IPA_JF_UNKNOWN:
|
||||||
|
|
@ -4062,7 +4069,10 @@ ipa_write_jump_function (struct output_block *ob,
|
||||||
case IPA_JF_CONST:
|
case IPA_JF_CONST:
|
||||||
gcc_assert (
|
gcc_assert (
|
||||||
EXPR_LOCATION (jump_func->value.constant.value) == UNKNOWN_LOCATION);
|
EXPR_LOCATION (jump_func->value.constant.value) == UNKNOWN_LOCATION);
|
||||||
stream_write_tree (ob, jump_func->value.constant.value, true);
|
stream_write_tree (ob,
|
||||||
|
flag
|
||||||
|
? TREE_OPERAND (jump_func->value.constant.value, 0)
|
||||||
|
: jump_func->value.constant.value, true);
|
||||||
break;
|
break;
|
||||||
case IPA_JF_PASS_THROUGH:
|
case IPA_JF_PASS_THROUGH:
|
||||||
streamer_write_uhwi (ob, jump_func->value.pass_through.operation);
|
streamer_write_uhwi (ob, jump_func->value.pass_through.operation);
|
||||||
|
|
@ -4131,20 +4141,28 @@ static void
|
||||||
ipa_read_jump_function (struct lto_input_block *ib,
|
ipa_read_jump_function (struct lto_input_block *ib,
|
||||||
struct ipa_jump_func *jump_func,
|
struct ipa_jump_func *jump_func,
|
||||||
struct cgraph_edge *cs,
|
struct cgraph_edge *cs,
|
||||||
struct data_in *data_in)
|
struct data_in *data_in,
|
||||||
|
bool prevails)
|
||||||
{
|
{
|
||||||
enum jump_func_type jftype;
|
enum jump_func_type jftype;
|
||||||
enum tree_code operation;
|
enum tree_code operation;
|
||||||
int i, count;
|
int i, count;
|
||||||
|
int val = streamer_read_uhwi (ib);
|
||||||
|
bool flag = val & 1;
|
||||||
|
|
||||||
jftype = (enum jump_func_type) streamer_read_uhwi (ib);
|
jftype = (enum jump_func_type) (val / 2);
|
||||||
switch (jftype)
|
switch (jftype)
|
||||||
{
|
{
|
||||||
case IPA_JF_UNKNOWN:
|
case IPA_JF_UNKNOWN:
|
||||||
ipa_set_jf_unknown (jump_func);
|
ipa_set_jf_unknown (jump_func);
|
||||||
break;
|
break;
|
||||||
case IPA_JF_CONST:
|
case IPA_JF_CONST:
|
||||||
ipa_set_jf_constant (jump_func, stream_read_tree (ib, data_in), cs);
|
{
|
||||||
|
tree t = stream_read_tree (ib, data_in);
|
||||||
|
if (flag && prevails)
|
||||||
|
t = build_fold_addr_expr (t);
|
||||||
|
ipa_set_jf_constant (jump_func, t, cs);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case IPA_JF_PASS_THROUGH:
|
case IPA_JF_PASS_THROUGH:
|
||||||
operation = (enum tree_code) streamer_read_uhwi (ib);
|
operation = (enum tree_code) streamer_read_uhwi (ib);
|
||||||
|
|
@ -4177,9 +4195,12 @@ ipa_read_jump_function (struct lto_input_block *ib,
|
||||||
ipa_set_ancestor_jf (jump_func, offset, formal_id, agg_preserved);
|
ipa_set_ancestor_jf (jump_func, offset, formal_id, agg_preserved);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
fatal_error (UNKNOWN_LOCATION, "invalid jump function in LTO stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
count = streamer_read_uhwi (ib);
|
count = streamer_read_uhwi (ib);
|
||||||
|
if (prevails)
|
||||||
vec_alloc (jump_func->agg.items, count);
|
vec_alloc (jump_func->agg.items, count);
|
||||||
if (count)
|
if (count)
|
||||||
{
|
{
|
||||||
|
|
@ -4191,6 +4212,7 @@ ipa_read_jump_function (struct lto_input_block *ib,
|
||||||
struct ipa_agg_jf_item item;
|
struct ipa_agg_jf_item item;
|
||||||
item.offset = streamer_read_uhwi (ib);
|
item.offset = streamer_read_uhwi (ib);
|
||||||
item.value = stream_read_tree (ib, data_in);
|
item.value = stream_read_tree (ib, data_in);
|
||||||
|
if (prevails)
|
||||||
jump_func->agg.items->quick_push (item);
|
jump_func->agg.items->quick_push (item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4200,6 +4222,7 @@ ipa_read_jump_function (struct lto_input_block *ib,
|
||||||
{
|
{
|
||||||
widest_int value = streamer_read_widest_int (ib);
|
widest_int value = streamer_read_widest_int (ib);
|
||||||
widest_int mask = streamer_read_widest_int (ib);
|
widest_int mask = streamer_read_widest_int (ib);
|
||||||
|
if (prevails)
|
||||||
ipa_set_jfunc_bits (jump_func, value, mask);
|
ipa_set_jfunc_bits (jump_func, value, mask);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -4213,6 +4236,7 @@ ipa_read_jump_function (struct lto_input_block *ib,
|
||||||
VR_LAST);
|
VR_LAST);
|
||||||
tree min = stream_read_tree (ib, data_in);
|
tree min = stream_read_tree (ib, data_in);
|
||||||
tree max = stream_read_tree (ib, data_in);
|
tree max = stream_read_tree (ib, data_in);
|
||||||
|
if (prevails)
|
||||||
ipa_set_jfunc_vr (jump_func, type, min, max);
|
ipa_set_jfunc_vr (jump_func, type, min, max);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -4345,24 +4369,48 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If jump functions points to node we possibly can propagate into.
|
/* Stream in edge E from IB. */
|
||||||
At this moment symbol table is still not merged, but the prevailing
|
|
||||||
symbol is always first in the list. */
|
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
jump_function_useful_p (symtab_node *node)
|
ipa_read_edge_info (struct lto_input_block *ib,
|
||||||
|
struct data_in *data_in,
|
||||||
|
struct cgraph_edge *e, bool prevails)
|
||||||
{
|
{
|
||||||
/* While incremental linking we may end up getting function body later. */
|
int count = streamer_read_uhwi (ib);
|
||||||
if (flag_incremental_link == INCREMENTAL_LINK_LTO)
|
bool contexts_computed = count & 1;
|
||||||
return true;
|
|
||||||
if (!TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl))
|
count /= 2;
|
||||||
return true;
|
if (!count)
|
||||||
for (int n = 10; node->previous_sharing_asm_name && n ; n--)
|
return;
|
||||||
node = node->previous_sharing_asm_name;
|
if (prevails && e->possibly_call_in_translation_unit_p ())
|
||||||
if (node->previous_sharing_asm_name)
|
{
|
||||||
node = symtab_node::get_for_asmname (DECL_ASSEMBLER_NAME (node->decl));
|
struct ipa_edge_args *args = IPA_EDGE_REF (e);
|
||||||
gcc_assert (TREE_PUBLIC (node->decl));
|
vec_safe_grow_cleared (args->jump_functions, count);
|
||||||
return node->definition;
|
if (contexts_computed)
|
||||||
|
vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
|
||||||
|
for (int k = 0; k < count; k++)
|
||||||
|
{
|
||||||
|
ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
|
||||||
|
data_in, prevails);
|
||||||
|
if (contexts_computed)
|
||||||
|
ipa_get_ith_polymorhic_call_context (args, k)->stream_in
|
||||||
|
(ib, data_in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int k = 0; k < count; k++)
|
||||||
|
{
|
||||||
|
struct ipa_jump_func dummy;
|
||||||
|
ipa_read_jump_function (ib, &dummy, e,
|
||||||
|
data_in, prevails);
|
||||||
|
if (contexts_computed)
|
||||||
|
{
|
||||||
|
struct ipa_polymorphic_call_context ctx;
|
||||||
|
ctx.stream_in (ib, data_in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stream in NODE info from IB. */
|
/* Stream in NODE info from IB. */
|
||||||
|
|
@ -4371,82 +4419,50 @@ static void
|
||||||
ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node,
|
ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node,
|
||||||
struct data_in *data_in)
|
struct data_in *data_in)
|
||||||
{
|
{
|
||||||
struct ipa_node_params *info = IPA_NODE_REF (node);
|
|
||||||
int k;
|
int k;
|
||||||
struct cgraph_edge *e;
|
struct cgraph_edge *e;
|
||||||
struct bitpack_d bp;
|
struct bitpack_d bp;
|
||||||
|
bool prevails = node->prevailing_p ();
|
||||||
|
struct ipa_node_params *info = prevails ? IPA_NODE_REF (node) : NULL;
|
||||||
|
|
||||||
ipa_alloc_node_params (node, streamer_read_uhwi (ib));
|
int param_count = streamer_read_uhwi (ib);
|
||||||
|
if (prevails)
|
||||||
for (k = 0; k < ipa_get_param_count (info); k++)
|
{
|
||||||
|
ipa_alloc_node_params (node, param_count);
|
||||||
|
for (k = 0; k < param_count; k++)
|
||||||
(*info->descriptors)[k].move_cost = streamer_read_uhwi (ib);
|
(*info->descriptors)[k].move_cost = streamer_read_uhwi (ib);
|
||||||
|
|
||||||
bp = streamer_read_bitpack (ib);
|
|
||||||
if (ipa_get_param_count (info) != 0)
|
if (ipa_get_param_count (info) != 0)
|
||||||
info->analysis_done = true;
|
info->analysis_done = true;
|
||||||
info->node_enqueued = false;
|
info->node_enqueued = false;
|
||||||
for (k = 0; k < ipa_get_param_count (info); k++)
|
}
|
||||||
ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
|
else
|
||||||
for (k = 0; k < ipa_get_param_count (info); k++)
|
for (k = 0; k < param_count; k++)
|
||||||
|
streamer_read_uhwi (ib);
|
||||||
|
|
||||||
|
bp = streamer_read_bitpack (ib);
|
||||||
|
for (k = 0; k < param_count; k++)
|
||||||
{
|
{
|
||||||
ipa_set_controlled_uses (info, k, streamer_read_hwi (ib));
|
bool used = bp_unpack_value (&bp, 1);
|
||||||
(*info->descriptors)[k].decl_or_type = stream_read_tree (ib, data_in);
|
|
||||||
|
if (prevails)
|
||||||
|
ipa_set_param_used (info, k, used);
|
||||||
|
}
|
||||||
|
for (k = 0; k < param_count; k++)
|
||||||
|
{
|
||||||
|
int nuses = streamer_read_hwi (ib);
|
||||||
|
tree type = stream_read_tree (ib, data_in);
|
||||||
|
|
||||||
|
if (prevails)
|
||||||
|
{
|
||||||
|
ipa_set_controlled_uses (info, k, nuses);
|
||||||
|
(*info->descriptors)[k].decl_or_type = type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (e = node->callees; e; e = e->next_callee)
|
for (e = node->callees; e; e = e->next_callee)
|
||||||
{
|
ipa_read_edge_info (ib, data_in, e, prevails);
|
||||||
struct ipa_edge_args *args = IPA_EDGE_REF (e);
|
|
||||||
int count = streamer_read_uhwi (ib);
|
|
||||||
bool contexts_computed = count & 1;
|
|
||||||
count /= 2;
|
|
||||||
|
|
||||||
if (!count)
|
|
||||||
continue;
|
|
||||||
if (!jump_function_useful_p (e->callee))
|
|
||||||
{
|
|
||||||
for (k = 0; k < count; k++)
|
|
||||||
{
|
|
||||||
struct ipa_jump_func dummy;
|
|
||||||
ipa_read_jump_function (ib, &dummy, e, data_in);
|
|
||||||
if (contexts_computed)
|
|
||||||
{
|
|
||||||
struct ipa_polymorphic_call_context ctx;
|
|
||||||
ctx.stream_in (ib, data_in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
vec_safe_grow_cleared (args->jump_functions, count);
|
|
||||||
if (contexts_computed)
|
|
||||||
vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
|
|
||||||
|
|
||||||
for (k = 0; k < ipa_get_cs_argument_count (args); k++)
|
|
||||||
{
|
|
||||||
ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
|
|
||||||
data_in);
|
|
||||||
if (contexts_computed)
|
|
||||||
ipa_get_ith_polymorhic_call_context (args, k)->stream_in (ib, data_in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (e = node->indirect_calls; e; e = e->next_callee)
|
for (e = node->indirect_calls; e; e = e->next_callee)
|
||||||
{
|
{
|
||||||
struct ipa_edge_args *args = IPA_EDGE_REF (e);
|
ipa_read_edge_info (ib, data_in, e, prevails);
|
||||||
int count = streamer_read_uhwi (ib);
|
|
||||||
bool contexts_computed = count & 1;
|
|
||||||
count /= 2;
|
|
||||||
|
|
||||||
if (count)
|
|
||||||
{
|
|
||||||
vec_safe_grow_cleared (args->jump_functions, count);
|
|
||||||
if (contexts_computed)
|
|
||||||
vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
|
|
||||||
for (k = 0; k < ipa_get_cs_argument_count (args); k++)
|
|
||||||
{
|
|
||||||
ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
|
|
||||||
data_in);
|
|
||||||
if (contexts_computed)
|
|
||||||
ipa_get_ith_polymorhic_call_context (args, k)->stream_in (ib, data_in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ipa_read_indirect_edge_info (ib, data_in, e);
|
ipa_read_indirect_edge_info (ib, data_in, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue