From 4843f03206f7ee188c5f7368ec6e64da7e90a396 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 31 Aug 2013 15:44:46 +0200 Subject: [PATCH] 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 --- gcc/ChangeLog | 9 ++ gcc/cgraph.c | 2 +- gcc/gimple-streamer-in.c | 3 - gcc/ipa-utils.c | 173 +++++++++++++++++++++++++++++++++++++++ gcc/lto-streamer-in.c | 12 +-- 5 files changed, 189 insertions(+), 10 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5666ce03846..a5824be71ad 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2013-08-31 Jan Hubicka + + * 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 * cgraph.c (cgraph_speculative_call_info): Fix ref lookup diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 88d7d985419..a240bfc49ac 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -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); diff --git a/gcc/gimple-streamer-in.c b/gcc/gimple-streamer-in.c index 03fbe91bbe2..4abf9cd739e 100644 --- a/gcc/gimple-streamer-in.c +++ b/gcc/gimple-streamer-in.c @@ -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; diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c index 00e65285c54..0ea02eab8cc 100644 --- a/gcc/ipa-utils.c +++ b/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; +} + diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c index 64303593272..f1d5935c427 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -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); }