aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2013-08-31 15:44:46 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2013-08-31 13:44:46 +0000
commit4843f03206f7ee188c5f7368ec6e64da7e90a396 (patch)
treed06573f8980bf9312721db9d6677d8f26547ca5d
parent57292ce9bd9df2ff43d3cb13f3761b6eb5cf6334 (diff)
downloadgcc-4843f03206f7ee188c5f7368ec6e64da7e90a396.zip
gcc-4843f03206f7ee188c5f7368ec6e64da7e90a396.tar.gz
gcc-4843f03206f7ee188c5f7368ec6e64da7e90a396.tar.bz2
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
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/cgraph.c2
-rw-r--r--gcc/gimple-streamer-in.c3
-rw-r--r--gcc/ipa-utils.c173
-rw-r--r--gcc/lto-streamer-in.c12
5 files changed, 189 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5666ce0..a5824be 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,14 @@
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
2013-08-31 Jan Hubicka <jh@suse.cz>
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 88d7d98..a240bfc 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 03fbe91..4abf9cd 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 00e6528..0ea02ea 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 6430359..f1d5935 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);
}