cgraph.c (cgraph_get_body): Update call of lto_input_function_body.
* cgraph.c (cgraph_get_body): Update call of lto_input_function_body. * gimple-streamer-in.c (input_gimple_stmt): Move sanity check to ... * ipa-utils.c: Include lto-streamer.h, ipa-inline.h (ipa_merge_profiles): New function. * lto-streamer-in.c (lto_read_body): Take node instead of fn_decl. (lto_input_function_body): Likewise. From-SVN: r202130
This commit is contained in:
parent
57292ce9bd
commit
4843f03206
5 changed files with 189 additions and 10 deletions
|
@ -1,3 +1,12 @@
|
|||
2013-08-31 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* cgraph.c (cgraph_get_body): Update call of lto_input_function_body.
|
||||
* gimple-streamer-in.c (input_gimple_stmt): Move sanity check to ...
|
||||
* ipa-utils.c: Include lto-streamer.h, ipa-inline.h
|
||||
(ipa_merge_profiles): New function.
|
||||
* lto-streamer-in.c (lto_read_body): Take node instead of fn_decl.
|
||||
(lto_input_function_body): Likewise.
|
||||
|
||||
2013-08-31 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* cgraph.c (cgraph_speculative_call_info): Fix ref lookup
|
||||
|
|
|
@ -3111,7 +3111,7 @@ cgraph_get_body (struct cgraph_node *node)
|
|||
|
||||
gcc_assert (DECL_STRUCT_FUNCTION (decl) == NULL);
|
||||
|
||||
lto_input_function_body (file_data, node->symbol.decl, data);
|
||||
lto_input_function_body (file_data, node, data);
|
||||
lto_stats.num_function_bodies++;
|
||||
lto_free_section_data (file_data, LTO_section_function_body, name,
|
||||
data, len);
|
||||
|
|
|
@ -282,9 +282,6 @@ input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
|
|||
if (lhs && TREE_CODE (lhs) == SSA_NAME)
|
||||
SSA_NAME_DEF_STMT (lhs) = stmt;
|
||||
}
|
||||
else if (code == GIMPLE_LABEL)
|
||||
gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt))
|
||||
|| DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl);
|
||||
else if (code == GIMPLE_ASM)
|
||||
{
|
||||
unsigned i;
|
||||
|
|
173
gcc/ipa-utils.c
173
gcc/ipa-utils.c
|
@ -37,6 +37,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "flags.h"
|
||||
#include "diagnostic.h"
|
||||
#include "langhooks.h"
|
||||
#include "lto-streamer.h"
|
||||
#include "ipa-inline.h"
|
||||
|
||||
/* Debugging function for postorder and inorder code. NOTE is a string
|
||||
that is printed before the nodes are printed. ORDER is an array of
|
||||
|
@ -618,3 +620,174 @@ debug_varpool_node_set (varpool_node_set set)
|
|||
{
|
||||
dump_varpool_node_set (stderr, set);
|
||||
}
|
||||
|
||||
|
||||
/* SRC and DST are going to be merged. Take SRC's profile and merge it into
|
||||
DST so it is not going to be lost. Destroy SRC's body on the way. */
|
||||
|
||||
void
|
||||
ipa_merge_profiles (struct cgraph_node *dst,
|
||||
struct cgraph_node *src)
|
||||
{
|
||||
tree oldsrcdecl = src->symbol.decl;
|
||||
struct function *srccfun, *dstcfun;
|
||||
bool match = true;
|
||||
|
||||
if (!src->symbol.definition
|
||||
|| !dst->symbol.definition)
|
||||
return;
|
||||
if (src->frequency < dst->frequency)
|
||||
src->frequency = dst->frequency;
|
||||
if (!dst->count)
|
||||
return;
|
||||
if (cgraph_dump_file)
|
||||
{
|
||||
fprintf (cgraph_dump_file, "Merging profiles of %s/%i to %s/%i\n",
|
||||
xstrdup (cgraph_node_name (src)), src->symbol.order,
|
||||
xstrdup (cgraph_node_name (dst)), dst->symbol.order);
|
||||
}
|
||||
dst->count += src->count;
|
||||
|
||||
/* This is ugly. We need to get both function bodies into memory.
|
||||
If declaration is merged, we need to duplicate it to be able
|
||||
to load body that is being replaced. This makes symbol table
|
||||
temporarily inconsistent. */
|
||||
if (src->symbol.decl == dst->symbol.decl)
|
||||
{
|
||||
void **slot;
|
||||
struct lto_in_decl_state temp;
|
||||
struct lto_in_decl_state *state;
|
||||
|
||||
/* We are going to move the decl, we want to remove its file decl data.
|
||||
and link these with the new decl. */
|
||||
temp.fn_decl = src->symbol.decl;
|
||||
slot = htab_find_slot (src->symbol.lto_file_data->function_decl_states,
|
||||
&temp, NO_INSERT);
|
||||
state = (lto_in_decl_state *)*slot;
|
||||
htab_clear_slot (src->symbol.lto_file_data->function_decl_states, slot);
|
||||
gcc_assert (state);
|
||||
|
||||
/* Duplicate the decl and be sure it does not link into body of DST. */
|
||||
src->symbol.decl = copy_node (src->symbol.decl);
|
||||
DECL_STRUCT_FUNCTION (src->symbol.decl) = NULL;
|
||||
DECL_ARGUMENTS (src->symbol.decl) = NULL;
|
||||
DECL_INITIAL (src->symbol.decl) = NULL;
|
||||
DECL_RESULT (src->symbol.decl) = NULL;
|
||||
|
||||
/* Associate the decl state with new declaration, so LTO streamer
|
||||
can look it up. */
|
||||
state->fn_decl = src->symbol.decl;
|
||||
slot = htab_find_slot (src->symbol.lto_file_data->function_decl_states,
|
||||
state, INSERT);
|
||||
gcc_assert (!*slot);
|
||||
*slot = state;
|
||||
}
|
||||
cgraph_get_body (src);
|
||||
cgraph_get_body (dst);
|
||||
srccfun = DECL_STRUCT_FUNCTION (src->symbol.decl);
|
||||
dstcfun = DECL_STRUCT_FUNCTION (dst->symbol.decl);
|
||||
if (n_basic_blocks_for_function (srccfun)
|
||||
!= n_basic_blocks_for_function (dstcfun))
|
||||
{
|
||||
if (cgraph_dump_file)
|
||||
fprintf (cgraph_dump_file,
|
||||
"Giving up; number of basic block mismatch.\n");
|
||||
match = false;
|
||||
}
|
||||
else if (last_basic_block_for_function (srccfun)
|
||||
!= last_basic_block_for_function (dstcfun))
|
||||
{
|
||||
if (cgraph_dump_file)
|
||||
fprintf (cgraph_dump_file,
|
||||
"Giving up; last block mismatch.\n");
|
||||
match = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
basic_block srcbb, dstbb;
|
||||
|
||||
FOR_ALL_BB_FN (srcbb, srccfun)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
dstbb = BASIC_BLOCK_FOR_FUNCTION (dstcfun, srcbb->index);
|
||||
if (dstbb == NULL)
|
||||
{
|
||||
if (cgraph_dump_file)
|
||||
fprintf (cgraph_dump_file,
|
||||
"No matching block for bb %i.\n",
|
||||
srcbb->index);
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
if (EDGE_COUNT (srcbb->succs) != EDGE_COUNT (dstbb->succs))
|
||||
{
|
||||
if (cgraph_dump_file)
|
||||
fprintf (cgraph_dump_file,
|
||||
"Edge count mistmatch for bb %i.\n",
|
||||
srcbb->index);
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < EDGE_COUNT (srcbb->succs); i++)
|
||||
{
|
||||
edge srce = EDGE_SUCC (srcbb, i);
|
||||
edge dste = EDGE_SUCC (dstbb, i);
|
||||
if (srce->dest->index != dste->dest->index)
|
||||
{
|
||||
if (cgraph_dump_file)
|
||||
fprintf (cgraph_dump_file,
|
||||
"Succ edge mistmatch for bb %i.\n",
|
||||
srce->dest->index);
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match)
|
||||
{
|
||||
struct cgraph_edge *e;
|
||||
basic_block srcbb, dstbb;
|
||||
|
||||
/* TODO: merge also statement histograms. */
|
||||
FOR_ALL_BB_FN (srcbb, srccfun)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
dstbb = BASIC_BLOCK_FOR_FUNCTION (dstcfun, srcbb->index);
|
||||
dstbb->count += srcbb->count;
|
||||
for (i = 0; i < EDGE_COUNT (srcbb->succs); i++)
|
||||
{
|
||||
edge srce = EDGE_SUCC (srcbb, i);
|
||||
edge dste = EDGE_SUCC (dstbb, i);
|
||||
dste->count += srce->count;
|
||||
}
|
||||
}
|
||||
push_cfun (dstcfun);
|
||||
counts_to_freqs ();
|
||||
compute_function_frequency ();
|
||||
pop_cfun ();
|
||||
for (e = dst->callees; e; e = e->next_callee)
|
||||
{
|
||||
gcc_assert (!e->speculative);
|
||||
e->count = gimple_bb (e->call_stmt)->count;
|
||||
e->frequency = compute_call_stmt_bb_frequency
|
||||
(dst->symbol.decl,
|
||||
gimple_bb (e->call_stmt));
|
||||
}
|
||||
for (e = dst->indirect_calls; e; e = e->next_callee)
|
||||
{
|
||||
gcc_assert (!e->speculative);
|
||||
e->count = gimple_bb (e->call_stmt)->count;
|
||||
e->frequency = compute_call_stmt_bb_frequency
|
||||
(dst->symbol.decl,
|
||||
gimple_bb (e->call_stmt));
|
||||
}
|
||||
cgraph_release_function_body (src);
|
||||
inline_update_overall_summary (dst);
|
||||
}
|
||||
/* TODO: if there is no match, we can scale up. */
|
||||
src->symbol.decl = oldsrcdecl;
|
||||
}
|
||||
|
||||
|
|
|
@ -1001,14 +1001,14 @@ input_function (tree fn_decl, struct data_in *data_in,
|
|||
}
|
||||
|
||||
|
||||
/* Read the body from DATA for function FN_DECL and fill it in.
|
||||
/* Read the body from DATA for function NODE and fill it in.
|
||||
FILE_DATA are the global decls and types. SECTION_TYPE is either
|
||||
LTO_section_function_body or LTO_section_static_initializer. If
|
||||
section type is LTO_section_function_body, FN must be the decl for
|
||||
that function. */
|
||||
|
||||
static void
|
||||
lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
|
||||
lto_read_body (struct lto_file_decl_data *file_data, struct cgraph_node *node,
|
||||
const char *data, enum lto_section_type section_type)
|
||||
{
|
||||
const struct lto_function_header *header;
|
||||
|
@ -1018,6 +1018,7 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
|
|||
int string_offset;
|
||||
struct lto_input_block ib_cfg;
|
||||
struct lto_input_block ib_main;
|
||||
tree fn_decl = node->symbol.decl;
|
||||
|
||||
header = (const struct lto_function_header *) data;
|
||||
cfg_offset = sizeof (struct lto_function_header);
|
||||
|
@ -1044,7 +1045,6 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
|
|||
if (section_type == LTO_section_function_body)
|
||||
{
|
||||
struct lto_in_decl_state *decl_state;
|
||||
struct cgraph_node *node = cgraph_get_node (fn_decl);
|
||||
unsigned from;
|
||||
|
||||
gcc_checking_assert (node);
|
||||
|
@ -1094,14 +1094,14 @@ lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl,
|
|||
}
|
||||
|
||||
|
||||
/* Read the body of FN_DECL using DATA. FILE_DATA holds the global
|
||||
/* Read the body of NODE using DATA. FILE_DATA holds the global
|
||||
decls and types. */
|
||||
|
||||
void
|
||||
lto_input_function_body (struct lto_file_decl_data *file_data,
|
||||
tree fn_decl, const char *data)
|
||||
struct cgraph_node *node, const char *data)
|
||||
{
|
||||
lto_read_body (file_data, fn_decl, data, LTO_section_function_body);
|
||||
lto_read_body (file_data, node, data, LTO_section_function_body);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue