summaryrefslogtreecommitdiff
path: root/gcc/ipa-reference.c
diff options
context:
space:
mode:
authorrus <rus@138bc75d-0d04-0410-961f-82ee72b054a4>2009-11-09 20:58:24 +0000
committerrus <rus@138bc75d-0d04-0410-961f-82ee72b054a4>2009-11-09 20:58:24 +0000
commit7f4db7c80779ecbc57d1146654daf0acfe18de66 (patch)
tree3af522a3b5e149c3fd498ecb1255994daae2129a /gcc/ipa-reference.c
parent611349f0ec42a37591db2cd02974a11a48d10edb (diff)
downloadgcc-7f4db7c80779ecbc57d1146654daf0acfe18de66.tar.gz
merge from trunkprofile-stdlib
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/profile-stdlib@154052 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ipa-reference.c')
-rw-r--r--gcc/ipa-reference.c381
1 files changed, 309 insertions, 72 deletions
diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c
index 10daf56eab6..8610f13311f 100644
--- a/gcc/ipa-reference.c
+++ b/gcc/ipa-reference.c
@@ -68,6 +68,15 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "diagnostic.h"
#include "langhooks.h"
+#include "lto-streamer.h"
+
+static void add_new_function (struct cgraph_node *node,
+ void *data ATTRIBUTE_UNUSED);
+static void remove_node_data (struct cgraph_node *node,
+ void *data ATTRIBUTE_UNUSED);
+static void duplicate_node_data (struct cgraph_node *src,
+ struct cgraph_node *dst,
+ void *data ATTRIBUTE_UNUSED);
/* The static variables defined within the compilation unit that are
loaded or stored directly by function that owns this structure. */
@@ -309,6 +318,8 @@ has_proper_scope_for_analysis (tree t)
if (!TREE_STATIC (t) && !DECL_EXTERNAL (t))
return false;
+ /* FIXME: for LTO we should include PUBLIC vars too. This is bit difficult
+ as summarie would need unsharing. */
if (DECL_EXTERNAL (t) || TREE_PUBLIC (t))
return false;
@@ -404,31 +415,25 @@ check_call (ipa_reference_local_vars_info_t local, gimple stmt)
{
int flags = gimple_call_flags (stmt);
tree callee_t = gimple_call_fndecl (stmt);
- enum availability avail = AVAIL_NOT_AVAILABLE;
- if (callee_t)
+ /* Process indirect calls. All direct calles are handled at propagation
+ time. */
+ if (!callee_t)
{
- struct cgraph_node* callee = cgraph_node(callee_t);
- avail = cgraph_function_body_availability (callee);
- }
-
- if (avail <= AVAIL_OVERWRITABLE)
- if (local)
- {
- if (flags & ECF_CONST)
- ;
- else if (flags & ECF_PURE)
+ if (flags & ECF_CONST)
+ ;
+ else if (flags & ECF_PURE)
+ local->calls_read_all = true;
+ else
+ {
local->calls_read_all = true;
- else
- {
- local->calls_read_all = true;
+ /* When function does not reutrn, it is safe to ignore anythign it writes
+ to, because the effect will never happen. */
+ if ((flags & (ECF_NOTHROW | ECF_NORETURN))
+ != (ECF_NOTHROW | ECF_NORETURN))
local->calls_write_all = true;
- }
- }
- /* TODO: To be able to produce sane results, we should also handle
- common builtins, in particular throw.
- Indirect calls hsould be only counted and as inliner is replacing them
- by direct calls, we can conclude if any indirect calls are left in body */
+ }
+ }
}
/* TP is the part of the tree currently under the microscope.
@@ -518,7 +523,7 @@ propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x
{
struct cgraph_node *y = e->callee;
- /* Only look at the master nodes and skip external nodes. */
+ /* Only look into nodes we can propagate something. */
if (cgraph_function_body_availability (e->callee) > AVAIL_OVERWRITABLE)
{
if (get_reference_vars_info (y))
@@ -578,6 +583,13 @@ propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x
static void
ipa_init (void)
{
+ static bool init_p = false;
+
+ if (init_p)
+ return;
+
+ init_p = true;
+
memory_identifier_string = build_string(7, "memory");
reference_vars_to_consider =
@@ -594,6 +606,13 @@ ipa_init (void)
since all we would be interested in are the addressof
operations. */
visited_nodes = pointer_set_create ();
+
+ function_insertion_hook_holder =
+ cgraph_add_function_insertion_hook (&add_new_function, NULL);
+ node_removal_hook_holder =
+ cgraph_add_node_removal_hook (&remove_node_data, NULL);
+ node_duplication_hook_holder =
+ cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
}
/* Check out the rhs of a static or global initialization VNODE to see
@@ -614,6 +633,7 @@ analyze_variable (struct varpool_node *vnode)
&wi, wi.pset);
}
+
/* Set up the persistent info for FN. */
static ipa_reference_local_vars_info_t
@@ -634,9 +654,10 @@ init_function_info (struct cgraph_node *fn)
return l;
}
+
/* This is the main routine for finding the reference patterns for
global variables within a function FN. */
-
+
static void
analyze_function (struct cgraph_node *fn)
{
@@ -646,6 +667,7 @@ analyze_function (struct cgraph_node *fn)
#ifdef ENABLE_CHECKING
tree step;
#endif
+ ipa_reference_local_vars_info_t local;
if (dump_file)
fprintf (dump_file, "\n local analysis of %s\n", cgraph_node_name (fn));
@@ -680,6 +702,21 @@ analyze_function (struct cgraph_node *fn)
scan_stmt_for_static_refs (&gsi, fn);
}
+ local = get_reference_vars_info (fn)->local;
+ if ((flags_from_decl_or_type (decl) & (ECF_NOTHROW | ECF_NORETURN))
+ == (ECF_NOTHROW | ECF_NORETURN))
+ {
+ local->calls_write_all = false;
+ bitmap_clear (local->statics_written);
+ }
+
+ /* Free bitmaps of direct references if we can not use them anyway. */
+ if (local->calls_write_all)
+ BITMAP_FREE (local->statics_written);
+ if (local->calls_read_all)
+ BITMAP_FREE (local->statics_read);
+
+
#ifdef ENABLE_CHECKING
/* Verify that all local initializers was expanded by gimplifier. */
for (step = DECL_STRUCT_FUNCTION (decl)->local_decls;
@@ -845,12 +882,6 @@ generate_summary (void)
bitmap module_statics_readonly;
bitmap bm_temp;
- function_insertion_hook_holder =
- cgraph_add_function_insertion_hook (&add_new_function, NULL);
- node_removal_hook_holder =
- cgraph_add_node_removal_hook (&remove_node_data, NULL);
- node_duplication_hook_holder =
- cgraph_add_node_duplication_hook (&duplicate_node_data, NULL);
ipa_init ();
module_statics_readonly = BITMAP_ALLOC (&local_info_obstack);
bm_temp = BITMAP_ALLOC (&local_info_obstack);
@@ -945,10 +976,12 @@ generate_summary (void)
removed from the local maps. This will include all of the
variables that were found to escape in the function
scanning. */
- bitmap_and_into (l->statics_read,
- all_module_statics);
- bitmap_and_into (l->statics_written,
- all_module_statics);
+ if (l->statics_read)
+ bitmap_and_into (l->statics_read,
+ all_module_statics);
+ if (l->statics_written)
+ bitmap_and_into (l->statics_written,
+ all_module_statics);
}
BITMAP_FREE(module_statics_readonly);
@@ -967,26 +1000,203 @@ generate_summary (void)
"\nFunction name:%s/%i:",
cgraph_node_name (node), node->uid);
fprintf (dump_file, "\n locals read: ");
- EXECUTE_IF_SET_IN_BITMAP (l->statics_read,
- 0, index, bi)
- {
- fprintf (dump_file, "%s ",
- get_static_name (index));
- }
+ if (l->statics_read)
+ EXECUTE_IF_SET_IN_BITMAP (l->statics_read,
+ 0, index, bi)
+ {
+ fprintf (dump_file, "%s ",
+ get_static_name (index));
+ }
fprintf (dump_file, "\n locals written: ");
- EXECUTE_IF_SET_IN_BITMAP (l->statics_written,
- 0, index, bi)
- {
- fprintf(dump_file, "%s ",
- get_static_name (index));
- }
+ if (l->statics_written)
+ EXECUTE_IF_SET_IN_BITMAP (l->statics_written,
+ 0, index, bi)
+ {
+ fprintf(dump_file, "%s ",
+ get_static_name (index));
+ }
if (l->calls_read_all)
fprintf (dump_file, "\n calls read all: ");
if (l->calls_write_all)
fprintf (dump_file, "\n calls read all: ");
}
}
+
+
+/* Return true if we need to write summary of NODE. */
+
+static bool
+write_node_summary_p (struct cgraph_node *node)
+{
+ gcc_assert (node->global.inlined_to == NULL);
+ return (node->analyzed
+ && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE
+ && get_reference_vars_info (node) != NULL);
+}
+
+/* Serialize the ipa info for lto. */
+
+static void
+ipa_reference_write_summary (cgraph_node_set set)
+{
+ struct cgraph_node *node;
+ struct lto_simple_output_block *ob
+ = lto_create_simple_output_block (LTO_section_ipa_reference);
+ unsigned int count = 0;
+ cgraph_node_set_iterator csi;
+
+ for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
+ if (write_node_summary_p (csi_node (csi)))
+ count++;
+
+ lto_output_uleb128_stream (ob->main_stream, count);
+
+ /* Process all of the functions. */
+ for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
+ {
+ node = csi_node (csi);
+ if (write_node_summary_p (node))
+ {
+ ipa_reference_local_vars_info_t l
+ = get_reference_vars_info (node)->local;
+ unsigned int index;
+ bitmap_iterator bi;
+ lto_cgraph_encoder_t encoder;
+ int node_ref;
+
+ encoder = ob->decl_state->cgraph_node_encoder;
+ node_ref = lto_cgraph_encoder_encode (encoder, node);
+ lto_output_uleb128_stream (ob->main_stream, node_ref);
+
+ /* Stream out the statics read. */
+ if (l->calls_read_all)
+ lto_output_sleb128_stream (ob->main_stream, -1);
+ else
+ {
+ lto_output_sleb128_stream (ob->main_stream,
+ bitmap_count_bits (l->statics_read));
+ EXECUTE_IF_SET_IN_BITMAP (l->statics_read, 0, index, bi)
+ lto_output_var_decl_index(ob->decl_state, ob->main_stream,
+ get_static_decl (index));
+ }
+
+ /* Stream out the statics written. */
+ if (l->calls_write_all)
+ lto_output_sleb128_stream (ob->main_stream, -1);
+ else
+ {
+ lto_output_sleb128_stream (ob->main_stream,
+ bitmap_count_bits (l->statics_written));
+ EXECUTE_IF_SET_IN_BITMAP (l->statics_written, 0, index, bi)
+ lto_output_var_decl_index(ob->decl_state, ob->main_stream,
+ get_static_decl (index));
+ }
+ }
+ }
+ lto_destroy_simple_output_block (ob);
+}
+
+
+/* Deserialize the ipa info for lto. */
+
+static void
+ipa_reference_read_summary (void)
+{
+ struct lto_file_decl_data ** file_data_vec
+ = lto_get_file_decl_data ();
+ struct lto_file_decl_data * file_data;
+ unsigned int j = 0;
+
+ ipa_init ();
+
+ while ((file_data = file_data_vec[j++]))
+ {
+ const char *data;
+ size_t len;
+ struct lto_input_block *ib
+ = lto_create_simple_input_block (file_data,
+ LTO_section_ipa_reference,
+ &data, &len);
+ if (ib)
+ {
+ unsigned int i;
+ unsigned int f_count = lto_input_uleb128 (ib);
+
+ for (i = 0; i < f_count; i++)
+ {
+ unsigned int j, index;
+ struct cgraph_node *node;
+ ipa_reference_local_vars_info_t l;
+ int v_count;
+ lto_cgraph_encoder_t encoder;
+
+ index = lto_input_uleb128 (ib);
+ encoder = file_data->cgraph_node_encoder;
+ node = lto_cgraph_encoder_deref (encoder, index);
+ l = init_function_info (node);
+
+ /* Set the statics read. */
+ v_count = lto_input_sleb128 (ib);
+ if (v_count == -1)
+ l->calls_read_all = true;
+ else
+ for (j = 0; j < (unsigned int)v_count; j++)
+ {
+ unsigned int var_index = lto_input_uleb128 (ib);
+ tree v_decl = lto_file_decl_data_get_var_decl (file_data,
+ var_index);
+ add_static_var (v_decl);
+ bitmap_set_bit (l->statics_read, DECL_UID (v_decl));
+ }
+
+ /* Set the statics written. */
+ v_count = lto_input_sleb128 (ib);
+ if (v_count == -1)
+ l->calls_write_all = true;
+ else
+ for (j = 0; j < (unsigned int)v_count; j++)
+ {
+ unsigned int var_index = lto_input_uleb128 (ib);
+ tree v_decl = lto_file_decl_data_get_var_decl (file_data,
+ var_index);
+ add_static_var (v_decl);
+ bitmap_set_bit (l->statics_written, DECL_UID (v_decl));
+ }
+ }
+
+ lto_destroy_simple_input_block (file_data,
+ LTO_section_ipa_reference,
+ ib, data, len);
+ }
+ }
+}
+
+
+/* Set READ_ALL/WRITE_ALL based on DECL flags. */
+static void
+read_write_all_from_decl (tree decl, bool * read_all, bool * write_all)
+{
+ int flags = flags_from_decl_or_type (decl);
+ if (flags & ECF_CONST)
+ ;
+ else if (flags & ECF_PURE)
+ *read_all = true;
+ else
+ {
+ /* TODO: To be able to produce sane results, we should also handle
+ common builtins, in particular throw.
+ Indirect calls hsould be only counted and as inliner is replacing them
+ by direct calls, we can conclude if any indirect calls are left in body */
+ *read_all = true;
+ /* When function does not reutrn, it is safe to ignore anythign it writes
+ to, because the effect will never happen. */
+ if ((flags & (ECF_NOTHROW | ECF_NORETURN))
+ != (ECF_NOTHROW | ECF_NORETURN))
+ *write_all = true;
+ }
+}
+
/* Produce the global information by preforming a transitive closure
on the local information that was produced by ipa_analyze_function
and ipa_analyze_variable. */
@@ -1019,6 +1229,7 @@ propagate (void)
ipa_reference_global_vars_info_t node_g =
XCNEW (struct ipa_reference_global_vars_info_d);
ipa_reference_local_vars_info_t node_l;
+ struct cgraph_edge *e;
bool read_all;
bool write_all;
@@ -1039,6 +1250,15 @@ propagate (void)
read_all = node_l->calls_read_all;
write_all = node_l->calls_write_all;
+ /* When function is overwrittable, we can not assume anything. */
+ if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
+ read_write_all_from_decl (node->decl, &read_all, &write_all);
+
+ for (e = node->callees; e; e = e->next_callee)
+ if (cgraph_function_body_availability (e->callee) <= AVAIL_OVERWRITABLE)
+ read_write_all_from_decl (e->callee->decl, &read_all, &write_all);
+
+
/* If any node in a cycle is calls_read_all or calls_write_all
they all are. */
w_info = (struct ipa_dfs_info *) node->aux;
@@ -1047,6 +1267,15 @@ propagate (void)
{
ipa_reference_local_vars_info_t w_l =
get_reference_vars_info (w)->local;
+
+ /* When function is overwrittable, we can not assume anything. */
+ if (cgraph_function_body_availability (w) <= AVAIL_OVERWRITABLE)
+ read_write_all_from_decl (w->decl, &read_all, &write_all);
+
+ for (e = w->callees; e; e = e->next_callee)
+ if (cgraph_function_body_availability (e->callee) <= AVAIL_OVERWRITABLE)
+ read_write_all_from_decl (e->callee->decl, &read_all, &write_all);
+
read_all |= w_l->calls_read_all;
write_all |= w_l->calls_write_all;
@@ -1054,6 +1283,7 @@ propagate (void)
w = w_info->next_cycle;
}
+
/* Initialized the bitmaps for the reduced nodes */
if (read_all)
node_g->statics_read = all_module_statics;
@@ -1063,7 +1293,6 @@ propagate (void)
bitmap_copy (node_g->statics_read,
node_l->statics_read);
}
-
if (write_all)
node_g->statics_written = all_module_statics;
else
@@ -1135,19 +1364,21 @@ propagate (void)
"\nFunction name:%s/%i:",
cgraph_node_name (node), node->uid);
fprintf (dump_file, "\n locals read: ");
- EXECUTE_IF_SET_IN_BITMAP (node_l->statics_read,
- 0, index, bi)
- {
- fprintf (dump_file, "%s ",
- get_static_name (index));
- }
+ if (node_l->statics_read)
+ EXECUTE_IF_SET_IN_BITMAP (node_l->statics_read,
+ 0, index, bi)
+ {
+ fprintf (dump_file, "%s ",
+ get_static_name (index));
+ }
fprintf (dump_file, "\n locals written: ");
- EXECUTE_IF_SET_IN_BITMAP (node_l->statics_written,
- 0, index, bi)
- {
- fprintf(dump_file, "%s ",
- get_static_name (index));
- }
+ if (node_l->statics_written)
+ EXECUTE_IF_SET_IN_BITMAP (node_l->statics_written,
+ 0, index, bi)
+ {
+ fprintf(dump_file, "%s ",
+ get_static_name (index));
+ }
w_info = (struct ipa_dfs_info *) node->aux;
w = w_info->next_cycle;
@@ -1179,19 +1410,25 @@ propagate (void)
w = w_info->next_cycle;
}
fprintf (dump_file, "\n globals read: ");
- EXECUTE_IF_SET_IN_BITMAP (node_g->statics_read,
- 0, index, bi)
- {
- fprintf (dump_file, "%s ",
- get_static_name (index));
- }
+ if (node_g->statics_read == all_module_statics)
+ fprintf (dump_file, "ALL");
+ else
+ EXECUTE_IF_SET_IN_BITMAP (node_g->statics_read,
+ 0, index, bi)
+ {
+ fprintf (dump_file, "%s ",
+ get_static_name (index));
+ }
fprintf (dump_file, "\n globals written: ");
- EXECUTE_IF_SET_IN_BITMAP (node_g->statics_written,
- 0, index, bi)
- {
- fprintf (dump_file, "%s ",
- get_static_name (index));
- }
+ if (node_g->statics_written == all_module_statics)
+ fprintf (dump_file, "ALL");
+ else
+ EXECUTE_IF_SET_IN_BITMAP (node_g->statics_written,
+ 0, index, bi)
+ {
+ fprintf (dump_file, "%s ",
+ get_static_name (index));
+ }
}
}
@@ -1271,8 +1508,8 @@ struct ipa_opt_pass_d pass_ipa_reference =
0 /* todo_flags_finish */
},
generate_summary, /* generate_summary */
- NULL, /* write_summary */
- NULL, /* read_summary */
+ ipa_reference_write_summary, /* write_summary */
+ ipa_reference_read_summary, /* read_summary */
NULL, /* function_read_summary */
0, /* TODOs */
NULL, /* function_transform */