diff options
author | rus <rus@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-11-09 20:58:24 +0000 |
---|---|---|
committer | rus <rus@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-11-09 20:58:24 +0000 |
commit | 7f4db7c80779ecbc57d1146654daf0acfe18de66 (patch) | |
tree | 3af522a3b5e149c3fd498ecb1255994daae2129a /gcc/ipa-reference.c | |
parent | 611349f0ec42a37591db2cd02974a11a48d10edb (diff) | |
download | gcc-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.c | 381 |
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 */ |