X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gcc%2Fipa-reference.c;h=78737aa9e3f3b8ace8e78f09814fc2982bb7e2fe;hb=ac71c66c0f8f737601d34ee7eb813cdfacf83455;hp=bee05651de04d2e736a19a0583b7da8e6a85468e;hpb=852f689eb9b7f6d7aafc2f72007e96129ac9bd45;p=thirdparty%2Fgcc.git diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c index bee05651de04..78737aa9e3f3 100644 --- a/gcc/ipa-reference.c +++ b/gcc/ipa-reference.c @@ -1,6 +1,5 @@ /* Callgraph based analysis of static variables. - Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 2004-2019 Free Software Foundation, Inc. Contributed by Kenneth Zadeck This file is part of GCC. @@ -40,32 +39,17 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" +#include "backend.h" #include "tree.h" -#include "tree-flow.h" -#include "tree-inline.h" +#include "gimple.h" #include "tree-pass.h" -#include "langhooks.h" -#include "pointer-set.h" +#include "cgraph.h" +#include "data-streamer.h" +#include "calls.h" #include "splay-tree.h" -#include "ggc.h" #include "ipa-utils.h" #include "ipa-reference.h" -#include "gimple.h" -#include "cgraph.h" -#include "output.h" -#include "flags.h" -#include "timevar.h" -#include "diagnostic.h" -#include "langhooks.h" -#include "lto-streamer.h" -#include "toplev.h" - -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); +#include "symbol-summary.h" /* The static variables defined within the compilation unit that are loaded or stored directly by function that owns this structure. */ @@ -74,14 +58,6 @@ struct ipa_reference_local_vars_info_d { bitmap statics_read; bitmap statics_written; - - /* Set when this function calls another function external to the - compilation unit or if the function has a asm clobber of memory. - In general, such calls are modeled as reading and writing all - variables (both bits on) but sometime there are attributes on the - called function so we can do better. */ - bool calls_read_all; - bool calls_write_all; }; /* Statics that are read and written by some set of functions. The @@ -95,7 +71,7 @@ struct ipa_reference_global_vars_info_d bitmap statics_written; }; -/* Information we save about every function after ipa-reference is completted. */ +/* Information we save about every function after ipa-reference is completed. */ struct ipa_reference_optimization_summary_d { @@ -103,9 +79,10 @@ struct ipa_reference_optimization_summary_d bitmap statics_not_written; }; -typedef struct ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t; -typedef struct ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t; -typedef struct ipa_reference_optimization_summary_d *ipa_reference_optimization_summary_t; +typedef ipa_reference_local_vars_info_d *ipa_reference_local_vars_info_t; +typedef ipa_reference_global_vars_info_d *ipa_reference_global_vars_info_t; +typedef ipa_reference_optimization_summary_d * + ipa_reference_optimization_summary_t; struct ipa_reference_vars_info_d { @@ -119,10 +96,13 @@ typedef struct ipa_reference_vars_info_d *ipa_reference_vars_info_t; being considered by the compilation level alias analysis. */ static splay_tree reference_vars_to_consider; -/* A bit is set for every module static we are considering. This is - ored into the local info when asm code is found that clobbers all - memory. */ +/* Set of all interesting module statics. A bit is set for every module + static we are considering. This is added to the local info when asm + code is found that clobbers all memory. */ static bitmap all_module_statics; +/* Set of all statics that should be ignored because they are touched by + -fno-ipa-reference code. */ +static bitmap ignore_module_statics; /* Obstack holding bitmaps of local analysis (live from analysis to propagation) */ @@ -130,122 +110,144 @@ static bitmap_obstack local_info_obstack; /* Obstack holding global analysis live forever. */ static bitmap_obstack optimization_summary_obstack; -/* Holders of ipa cgraph hooks: */ -static struct cgraph_2node_hook_list *node_duplication_hook_holder; -static struct cgraph_node_hook_list *node_removal_hook_holder; +class ipa_ref_var_info_summary_t: public fast_function_summary + +{ +public: + ipa_ref_var_info_summary_t (symbol_table *symtab): + fast_function_summary (symtab) {} +}; -/* Vector where the reference var infos are actually stored. */ -DEF_VEC_P (ipa_reference_vars_info_t); -DEF_VEC_ALLOC_P (ipa_reference_vars_info_t, heap); -static VEC (ipa_reference_vars_info_t, heap) *ipa_reference_vars_vector; -DEF_VEC_P (ipa_reference_optimization_summary_t); -DEF_VEC_ALLOC_P (ipa_reference_optimization_summary_t, heap); -static VEC (ipa_reference_optimization_summary_t, heap) *ipa_reference_opt_sum_vector; +static ipa_ref_var_info_summary_t *ipa_ref_var_info_summaries = NULL; + +class ipa_ref_opt_summary_t: public fast_function_summary + +{ +public: + ipa_ref_opt_summary_t (symbol_table *symtab): + fast_function_summary (symtab) {} + + virtual void remove (cgraph_node *src_node, + ipa_reference_optimization_summary_d *data); + virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node, + ipa_reference_optimization_summary_d *src_data, + ipa_reference_optimization_summary_d *dst_data); +}; + +static ipa_ref_opt_summary_t *ipa_ref_opt_sum_summaries = NULL; /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ static inline ipa_reference_vars_info_t get_reference_vars_info (struct cgraph_node *node) { - if (!ipa_reference_vars_vector - || VEC_length (ipa_reference_vars_info_t, - ipa_reference_vars_vector) <= (unsigned int) node->uid) + if (ipa_ref_var_info_summaries == NULL) return NULL; - return VEC_index (ipa_reference_vars_info_t, ipa_reference_vars_vector, - node->uid); + + ipa_reference_vars_info_t v = ipa_ref_var_info_summaries->get (node); + return v == NULL ? NULL : v; } /* Return the ipa_reference_vars structure starting from the cgraph NODE. */ static inline ipa_reference_optimization_summary_t get_reference_optimization_summary (struct cgraph_node *node) { - if (!ipa_reference_opt_sum_vector - || (VEC_length (ipa_reference_optimization_summary_t, - ipa_reference_opt_sum_vector) - <= (unsigned int) node->uid)) + if (ipa_ref_opt_sum_summaries == NULL) return NULL; - return VEC_index (ipa_reference_optimization_summary_t, ipa_reference_opt_sum_vector, - node->uid); -} -/* Return the ipa_reference_vars structure starting from the cgraph NODE. */ -static inline void -set_reference_vars_info (struct cgraph_node *node, - ipa_reference_vars_info_t info) -{ - if (!ipa_reference_vars_vector - || VEC_length (ipa_reference_vars_info_t, - ipa_reference_vars_vector) <= (unsigned int) node->uid) - VEC_safe_grow_cleared (ipa_reference_vars_info_t, heap, - ipa_reference_vars_vector, node->uid + 1); - VEC_replace (ipa_reference_vars_info_t, ipa_reference_vars_vector, - node->uid, info); -} + ipa_reference_optimization_summary_t v + = ipa_ref_opt_sum_summaries->get (node); -/* Return the ipa_reference_vars structure starting from the cgraph NODE. */ -static inline void -set_reference_optimization_summary (struct cgraph_node *node, - ipa_reference_optimization_summary_t info) -{ - if (!ipa_reference_opt_sum_vector - || (VEC_length (ipa_reference_optimization_summary_t, - ipa_reference_opt_sum_vector) - <= (unsigned int) node->uid)) - VEC_safe_grow_cleared (ipa_reference_optimization_summary_t, - heap, ipa_reference_opt_sum_vector, node->uid + 1); - VEC_replace (ipa_reference_optimization_summary_t, - ipa_reference_opt_sum_vector, node->uid, info); + return v == NULL ? NULL : v; } -/* Return a bitmap indexed by_DECL_UID uid for the static variables - that are not read during the execution of the function FN. Returns +/* Return a bitmap indexed by ipa_reference_var_uid for the static variables + that are *not* read during the execution of the function FN. Returns NULL if no data is available. */ bitmap ipa_reference_get_not_read_global (struct cgraph_node *fn) { - ipa_reference_optimization_summary_t info; + if (!opt_for_fn (current_function_decl, flag_ipa_reference)) + return NULL; - info = get_reference_optimization_summary (fn); - if (info) + enum availability avail; + struct cgraph_node *fn2 = fn->function_symbol (&avail); + ipa_reference_optimization_summary_t info = + get_reference_optimization_summary (fn2); + + if (info + && (avail >= AVAIL_AVAILABLE + || (avail == AVAIL_INTERPOSABLE + && flags_from_decl_or_type (fn->decl) & ECF_LEAF)) + && opt_for_fn (fn2->decl, flag_ipa_reference)) return info->statics_not_read; + else if (avail == AVAIL_NOT_AVAILABLE + && flags_from_decl_or_type (fn->decl) & ECF_LEAF) + return all_module_statics; else return NULL; } -/* Return a bitmap indexed by DECL_UID uid for the static variables - that are not written during the execution of the function FN. Note +/* Return a bitmap indexed by ipa_reference_var_uid for the static variables + that are *not* written during the execution of the function FN. Note that variables written may or may not be read during the function call. Returns NULL if no data is available. */ bitmap ipa_reference_get_not_written_global (struct cgraph_node *fn) { - ipa_reference_optimization_summary_t info; + if (!opt_for_fn (current_function_decl, flag_ipa_reference)) + return NULL; + + enum availability avail; + struct cgraph_node *fn2 = fn->function_symbol (&avail); + ipa_reference_optimization_summary_t info = + get_reference_optimization_summary (fn2); - info = get_reference_optimization_summary (fn); - if (info) + if (info + && (avail >= AVAIL_AVAILABLE + || (avail == AVAIL_INTERPOSABLE + && flags_from_decl_or_type (fn->decl) & ECF_LEAF)) + && opt_for_fn (fn2->decl, flag_ipa_reference)) return info->statics_not_written; + else if (avail == AVAIL_NOT_AVAILABLE + && flags_from_decl_or_type (fn->decl) & ECF_LEAF) + return all_module_statics; else return NULL; } - -/* Add VAR to all_module_statics and the two - reference_vars_to_consider* sets. */ - -static inline void -add_static_var (tree var) +/* Hepler for is_proper_for_analysis. */ +static bool +is_improper (symtab_node *n, void *v ATTRIBUTE_UNUSED) { - int uid = DECL_UID (var); - gcc_assert (TREE_CODE (var) == VAR_DECL); - if (!bitmap_bit_p (all_module_statics, uid)) - { - if (dump_file) - splay_tree_insert (reference_vars_to_consider, - uid, (splay_tree_value)var); - bitmap_set_bit (all_module_statics, uid); - } + tree t = n->decl; + /* If the variable has the "used" attribute, treat it as if it had a + been touched by the devil. */ + if (DECL_PRESERVE_P (t)) + return true; + + /* Do not want to do anything with volatile except mark any + function that uses one to be not const or pure. */ + if (TREE_THIS_VOLATILE (t)) + return true; + + /* We do not need to analyze readonly vars, we already know they do not + alias. */ + if (TREE_READONLY (t)) + return true; + + /* We cannot track variables with address taken. */ + if (TREE_ADDRESSABLE (t)) + return true; + + /* TODO: We could track public variables that are not addressable, but + currently frontends don't give us those. */ + if (TREE_PUBLIC (t)) + return true; + + return false; } /* Return true if the variable T is the right kind of static variable to @@ -254,29 +256,13 @@ add_static_var (tree var) static inline bool is_proper_for_analysis (tree t) { - /* We handle only variables whose address is never taken. */ - if (TREE_ADDRESSABLE (t)) - return false; - /* If the variable has the "used" attribute, treat it as if it had a - been touched by the devil. */ - if (DECL_PRESERVE_P (t)) - return false; - - /* Do not want to do anything with volatile except mark any - function that uses one to be not const or pure. */ - if (TREE_THIS_VOLATILE (t)) + if (bitmap_bit_p (ignore_module_statics, ipa_reference_var_uid (t))) return false; - /* We cannot touch decls where the type needs constructing. */ - if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (t))) + if (symtab_node::get (t) + ->call_for_symbol_and_aliases (is_improper, NULL, true)) return false; - /* This is a variable we care about. Check if we have seen it - before, and if not add it the set of variables we care about. */ - if (all_module_statics - && !bitmap_bit_p (all_module_statics, DECL_UID (t))) - add_static_var (t); - return true; } @@ -288,71 +274,128 @@ get_static_name (int index) { splay_tree_node stn = splay_tree_lookup (reference_vars_to_consider, index); - if (stn) - return lang_hooks.decl_printable_name ((tree)(stn->value), 2); - return NULL; + return fndecl_name ((tree)(stn->value)); } -/* Or in all of the bits from every callee of X into X_GLOBAL, the caller's cycle, - bit vector. There are several cases to check to avoid the sparse - bitmap oring. */ +/* Dump a set of static vars to FILE. */ +static void +dump_static_vars_set_to_file (FILE *f, bitmap set) +{ + unsigned int index; + bitmap_iterator bi; + if (set == NULL) + return; + else if (set == all_module_statics) + fprintf (f, "ALL"); + else + EXECUTE_IF_SET_IN_BITMAP (set, 0, index, bi) + { + fprintf (f, "%s ", get_static_name (index)); + } +} + +/* Compute X |= Y, taking into account the possibility that + either X or Y is already the maximum set. + Return true if X is the maximum set after taking the union with Y. */ + +static bool +union_static_var_sets (bitmap &x, bitmap y) +{ + if (x != all_module_statics) + { + if (y == all_module_statics) + { + BITMAP_FREE (x); + x = all_module_statics; + } + else if (bitmap_ior_into (x, y)) + { + /* The union may have reduced X to the maximum set. + In that case, we want to make that visible explicitly. + Even though bitmap_equal_p can be very expensive, it + turns out to be an overall win to check this here for + an LTO bootstrap of GCC itself. Liberally extrapoliate + that result to be applicable to all cases. */ + if (bitmap_equal_p (x, all_module_statics)) + { + BITMAP_FREE (x); + x = all_module_statics; + } + } + } + return x == all_module_statics; +} + +/* Return a copy of SET on the bitmap obstack containing SET. + But if SET is NULL or the maximum set, return that instead. */ + +static bitmap +copy_static_var_set (bitmap set) +{ + if (set == NULL || set == all_module_statics) + return set; + bitmap_obstack *o = set->obstack; + gcc_checking_assert (o); + bitmap copy = BITMAP_ALLOC (o); + bitmap_copy (copy, set); + return copy; +} + +/* Compute the union all of the statics read and written by every callee of X + into X_GLOBAL->statics_read and X_GLOBAL->statics_written. X_GLOBAL is + actually the set representing the cycle containing X. If the read and + written sets of X_GLOBAL has been reduced to the maximum set, we don't + have to look at the remaining callees. */ static void propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x) { struct cgraph_edge *e; - for (e = x->callees; e; e = e->next_callee) + bool read_all = x_global->statics_read == all_module_statics; + bool write_all = x_global->statics_written == all_module_statics; + for (e = x->callees; + e && !(read_all && write_all); + e = e->next_callee) { - struct cgraph_node *y = e->callee; + enum availability avail; + struct cgraph_node *y = e->callee->function_symbol (&avail); + if (!y) + continue; /* Only look into nodes we can propagate something. */ - if (cgraph_function_body_availability (e->callee) > AVAIL_OVERWRITABLE) + int flags = flags_from_decl_or_type (y->decl); + if (opt_for_fn (y->decl, flag_ipa_reference) + && (avail > AVAIL_INTERPOSABLE + || (avail == AVAIL_INTERPOSABLE && (flags & ECF_LEAF)))) { if (get_reference_vars_info (y)) { - ipa_reference_vars_info_t y_info - = get_reference_vars_info (y); + ipa_reference_vars_info_t y_info = get_reference_vars_info (y); ipa_reference_global_vars_info_t y_global = &y_info->global; - /* Calls in current cycle do not have global computed yet. */ + /* Calls in the current cycle do not have their global set + computed yet (but everything else does because we're + visiting nodes in topological order). */ if (!y_global->statics_read) continue; - if (x_global->statics_read - != all_module_statics) - { - if (y_global->statics_read - == all_module_statics) - { - BITMAP_FREE (x_global->statics_read); - x_global->statics_read - = all_module_statics; - } - /* Skip bitmaps that are pointer equal to node's bitmap - (no reason to spin within the cycle). */ - else if (x_global->statics_read - != y_global->statics_read) - bitmap_ior_into (x_global->statics_read, + /* If the function is const, it reads no memory even if it + seems so to local analysis. */ + if (flags & ECF_CONST) + continue; + + union_static_var_sets (x_global->statics_read, y_global->statics_read); - } - if (x_global->statics_written - != all_module_statics) - { - if (y_global->statics_written - == all_module_statics) - { - BITMAP_FREE (x_global->statics_written); - x_global->statics_written - = all_module_statics; - } - /* Skip bitmaps that are pointer equal to node's bitmap - (no reason to spin within the cycle). */ - else if (x_global->statics_written - != y_global->statics_written) - bitmap_ior_into (x_global->statics_written, + /* If the function is pure, it has no stores even if it + seems so to local analysis. If we cannot return from + the function, we can safely ignore the call. */ + if ((flags & ECF_PURE) + || e->cannot_lead_to_return_p ()) + continue; + + union_static_var_sets (x_global->statics_written, y_global->statics_written); - } } else gcc_unreachable (); @@ -360,29 +403,34 @@ propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x } } +static bool ipa_init_p = false; + /* The init routine for analyzing global static variable usage. See comments at top for description. */ static void ipa_init (void) { - static bool init_p = false; - - if (init_p) + if (ipa_init_p) return; - init_p = true; + ipa_init_p = true; if (dump_file) reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0); bitmap_obstack_initialize (&local_info_obstack); bitmap_obstack_initialize (&optimization_summary_obstack); - all_module_statics = BITMAP_ALLOC (&local_info_obstack); + all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack); + ignore_module_statics = BITMAP_ALLOC (&optimization_summary_obstack); + + if (ipa_ref_var_info_summaries == NULL) + ipa_ref_var_info_summaries = new ipa_ref_var_info_summary_t (symtab); - 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); + if (ipa_ref_opt_sum_summaries != NULL) + { + delete ipa_ref_opt_sum_summaries; + ipa_ref_opt_sum_summaries = NULL; + } } @@ -392,10 +440,7 @@ static ipa_reference_local_vars_info_t init_function_info (struct cgraph_node *fn) { ipa_reference_vars_info_t info - = XCNEW (struct ipa_reference_vars_info_d); - - /* Add the info to the tree's annotation. */ - set_reference_vars_info (fn, info); + = ipa_ref_var_info_summaries->get_create (fn); info->local.statics_read = BITMAP_ALLOC (&local_info_obstack); info->local.statics_written = BITMAP_ALLOC (&local_info_obstack); @@ -411,108 +456,79 @@ static void analyze_function (struct cgraph_node *fn) { ipa_reference_local_vars_info_t local; - struct ipa_ref *ref; + struct ipa_ref *ref = NULL; int i; tree var; - struct cgraph_edge *ie; + if (!opt_for_fn (fn->decl, flag_ipa_reference)) + return; local = init_function_info (fn); - /* Process indirect calls. All direct calles are handled at propagation - time. */ - for (ie = fn->indirect_calls; ie; ie = ie->next_callee) - if (!(ie->indirect_info->ecf_flags & ECF_CONST)) - { - local->calls_read_all = true; - if (!(ie->indirect_info->ecf_flags & ECF_PURE) - && ((ie->indirect_info->ecf_flags & (ECF_NOTHROW | ECF_NORETURN)) - != (ECF_NOTHROW | ECF_NORETURN))) - local->calls_write_all = true; - } - for (i = 0; ipa_ref_list_reference_iterate (&fn->ref_list, i, ref); i++) + for (i = 0; fn->iterate_reference (i, ref); i++) { - if (ref->refered_type != IPA_REF_VARPOOL) + if (!is_a (ref->referred)) continue; - var = ipa_ref_varpool_node (ref)->decl; - if (ipa_ref_varpool_node (ref)->externally_visible - || !ipa_ref_varpool_node (ref)->analyzed - || !is_proper_for_analysis (var)) + var = ref->referred->decl; + if (!is_proper_for_analysis (var)) continue; + /* This is a variable we care about. Check if we have seen it + before, and if not add it the set of variables we care about. */ + if (all_module_statics + && bitmap_set_bit (all_module_statics, ipa_reference_var_uid (var))) + { + if (dump_file) + splay_tree_insert (reference_vars_to_consider, + ipa_reference_var_uid (var), + (splay_tree_value)var); + } switch (ref->use) { case IPA_REF_LOAD: - bitmap_set_bit (local->statics_read, DECL_UID (var)); + bitmap_set_bit (local->statics_read, ipa_reference_var_uid (var)); break; case IPA_REF_STORE: - bitmap_set_bit (local->statics_written, DECL_UID (var)); + if (ref->cannot_lead_to_return ()) + break; + bitmap_set_bit (local->statics_written, ipa_reference_var_uid (var)); break; case IPA_REF_ADDR: break; + default: + gcc_unreachable (); } } - if ((flags_from_decl_or_type (fn->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); -} - -static bitmap -copy_global_bitmap (bitmap src) -{ - bitmap dst; - if (!src) - return NULL; - dst = BITMAP_ALLOC (&optimization_summary_obstack); - bitmap_copy (dst, src); - return dst; + if (fn->cannot_return_p ()) + bitmap_clear (local->statics_written); } /* Called when new clone is inserted to callgraph late. */ -static void -duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst, - void *data ATTRIBUTE_UNUSED) +void +ipa_ref_opt_summary_t::duplicate (cgraph_node *, cgraph_node *, + ipa_reference_optimization_summary_d *ginfo, + ipa_reference_optimization_summary_d + *dst_ginfo) { - ipa_reference_optimization_summary_t ginfo; - ipa_reference_optimization_summary_t dst_ginfo; - - ginfo = get_reference_optimization_summary (src); - if (!ginfo) - return; - dst_ginfo = XCNEW (struct ipa_reference_optimization_summary_d); - set_reference_optimization_summary (dst, dst_ginfo); - dst_ginfo->statics_not_read = copy_global_bitmap (ginfo->statics_not_read); - dst_ginfo->statics_not_written = copy_global_bitmap (ginfo->statics_not_written); + dst_ginfo->statics_not_read = + copy_static_var_set (ginfo->statics_not_read); + dst_ginfo->statics_not_written = + copy_static_var_set (ginfo->statics_not_written); } /* Called when node is removed. */ -static void -remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) +void +ipa_ref_opt_summary_t::remove (cgraph_node *, + ipa_reference_optimization_summary_d *ginfo) { - ipa_reference_optimization_summary_t ginfo; - ginfo = get_reference_optimization_summary (node); - if (ginfo) - { - if (ginfo->statics_not_read - && ginfo->statics_not_read != all_module_statics) - BITMAP_FREE (ginfo->statics_not_read); - - if (ginfo->statics_not_written - && ginfo->statics_not_written != all_module_statics) - BITMAP_FREE (ginfo->statics_not_written); - free (ginfo); - set_reference_optimization_summary (node, NULL); - } + if (ginfo->statics_not_read + && ginfo->statics_not_read != all_module_statics) + BITMAP_FREE (ginfo->statics_not_read); + + if (ginfo->statics_not_written + && ginfo->statics_not_written != all_module_statics) + BITMAP_FREE (ginfo->statics_not_written); } /* Analyze each function in the cgraph to see which global or statics @@ -524,28 +540,40 @@ generate_summary (void) struct cgraph_node *node; unsigned int index; bitmap_iterator bi; - bitmap bm_temp; ipa_init (); - bm_temp = BITMAP_ALLOC (&local_info_obstack); /* Process all of the functions next. */ - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed) - analyze_function (node); + FOR_EACH_DEFINED_FUNCTION (node) + if (!node->alias && !opt_for_fn (node->decl, flag_ipa_reference)) + { + struct ipa_ref *ref = NULL; + int i; + tree var; + for (i = 0; node->iterate_reference (i, ref); i++) + { + if (!is_a (ref->referred)) + continue; + var = ref->referred->decl; + if (!is_proper_for_analysis (var)) + continue; + bitmap_set_bit (ignore_module_statics, ipa_reference_var_uid (var)); + } + } + FOR_EACH_DEFINED_FUNCTION (node) + analyze_function (node); if (dump_file) EXECUTE_IF_SET_IN_BITMAP (all_module_statics, 0, index, bi) { - fprintf (dump_file, "\nPromotable global:%s", - get_static_name (index)); + fprintf (dump_file, "\nPromotable global:%s (uid=%u)\n", + get_static_name (index), index); } - BITMAP_FREE(bm_temp); - if (dump_file) - for (node = cgraph_nodes; node; node = node->next) - if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) + FOR_EACH_DEFINED_FUNCTION (node) + if (node->get_availability () >= AVAIL_INTERPOSABLE + && opt_for_fn (node->decl, flag_ipa_reference)) { ipa_reference_local_vars_info_t l; unsigned int index; @@ -553,8 +581,7 @@ generate_summary (void) l = &get_reference_vars_info (node)->local; fprintf (dump_file, - "\nFunction name:%s/%i:", - cgraph_node_name (node), node->uid); + "\nFunction name:%s:", node->dump_name ()); fprintf (dump_file, "\n locals read: "); if (l->statics_read) EXECUTE_IF_SET_IN_BITMAP (l->statics_read, @@ -568,342 +595,331 @@ generate_summary (void) EXECUTE_IF_SET_IN_BITMAP (l->statics_written, 0, index, bi) { - fprintf(dump_file, "%s ", - get_static_name (index)); + 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: "); } } -/* Set READ_ALL/WRITE_ALL based on DECL flags. */ +/* Set READ_ALL/WRITE_ALL based on decl flags of NODE. */ static void -read_write_all_from_decl (tree decl, bool * read_all, bool * write_all) +read_write_all_from_decl (struct cgraph_node *node, + bool &read_all, bool &write_all) { + tree decl = node->decl; int flags = flags_from_decl_or_type (decl); - if (flags & ECF_CONST) + if ((flags & ECF_LEAF) + && node->get_availability () < AVAIL_INTERPOSABLE) ; - else if (flags & ECF_PURE) - *read_all = true; + else if (flags & ECF_CONST) + ; + else if ((flags & ECF_PURE) || node->cannot_return_p ()) + { + read_all = true; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %s -> read all\n", node->dump_name ()); + } else { /* TODO: To be able to produce sane results, we should also handle common builtins, in particular throw. */ - *read_all = true; - /* When function does not return, 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; + read_all = true; + write_all = true; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " %s -> read all, write all\n", + node->dump_name ()); } } +/* Set READ_ALL/WRITE_ALL based on decl flags of NODE or any member + in the cycle of NODE. */ + +static void +get_read_write_all_from_node (struct cgraph_node *node, + bool &read_all, bool &write_all) +{ + struct cgraph_edge *e, *ie; + + /* When function is overwritable, we cannot assume anything. */ + if (node->get_availability () <= AVAIL_INTERPOSABLE + || (node->analyzed && !opt_for_fn (node->decl, flag_ipa_reference))) + read_write_all_from_decl (node, read_all, write_all); + + for (e = node->callees; + e && !(read_all && write_all); + e = e->next_callee) + { + enum availability avail; + struct cgraph_node *callee = e->callee->function_symbol (&avail); + gcc_checking_assert (callee); + if (avail <= AVAIL_INTERPOSABLE + || (callee->analyzed && !opt_for_fn (callee->decl, + flag_ipa_reference))) + read_write_all_from_decl (callee, read_all, write_all); + } + + for (ie = node->indirect_calls; + ie && !(read_all && write_all); + ie = ie->next_callee) + if (!(ie->indirect_info->ecf_flags & ECF_CONST)) + { + read_all = true; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " indirect call -> read all\n"); + if (!ie->cannot_lead_to_return_p () + && !(ie->indirect_info->ecf_flags & ECF_PURE)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " indirect call -> write all\n"); + write_all = true; + } + } +} + +/* Skip edges from and to nodes without ipa_reference enabled. + Ignore not available symbols. This leave + them out of strongly connected components and makes them easy to skip in the + propagation loop bellow. */ + +static bool +ignore_edge_p (cgraph_edge *e) +{ + enum availability avail; + cgraph_node *ultimate_target + = e->callee->function_or_virtual_thunk_symbol (&avail, e->caller); + + return (avail < AVAIL_INTERPOSABLE + || (avail == AVAIL_INTERPOSABLE + && !(flags_from_decl_or_type (e->callee->decl) & ECF_LEAF)) + || !opt_for_fn (e->caller->decl, flag_ipa_reference) + || !opt_for_fn (ultimate_target->decl, flag_ipa_reference)); +} + /* Produce the global information by preforming a transitive closure - on the local information that was produced by ipa_analyze_function */ + on the local information that was produced by ipa_analyze_function. */ static unsigned int propagate (void) { struct cgraph_node *node; - struct cgraph_node *w; struct cgraph_node **order = - XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); - int order_pos = ipa_utils_reduced_inorder (order, false, true, NULL); + XCNEWVEC (struct cgraph_node *, symtab->cgraph_count); + int order_pos; int i; + bool remove_p; if (dump_file) - dump_cgraph (dump_file); + cgraph_node::dump_cgraph (dump_file); - ipa_discover_readonly_nonaddressable_vars (); + remove_p = ipa_discover_variable_flags (); generate_summary (); - /* Propagate the local information thru the call graph to produce + /* Propagate the local information through the call graph to produce the global information. All the nodes within a cycle will have the same info so we collapse cycles first. Then we can do the propagation in one pass from the leaves to the roots. */ - order_pos = ipa_utils_reduced_inorder (order, true, true, NULL); + order_pos = ipa_reduced_postorder (order, true, ignore_edge_p); if (dump_file) - ipa_utils_print_order(dump_file, "reduced", order, order_pos); + ipa_print_order (dump_file, "reduced", order, order_pos); for (i = 0; i < order_pos; i++ ) { + unsigned x; + struct cgraph_node *w; ipa_reference_vars_info_t node_info; ipa_reference_global_vars_info_t node_g; ipa_reference_local_vars_info_t node_l; - struct cgraph_edge *e; - - bool read_all; - bool write_all; - struct ipa_dfs_info * w_info; + bool read_all = false; + bool write_all = false; node = order[i]; - node_info = get_reference_vars_info (node); - if (!node_info) - { - dump_cgraph_node (stderr, node); - dump_cgraph (stderr); - gcc_unreachable (); - } + if (node->alias || !opt_for_fn (node->decl, flag_ipa_reference)) + continue; + node_info = get_reference_vars_info (node); + gcc_assert (node_info); node_l = &node_info->local; node_g = &node_info->global; - 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 (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Starting cycle with %s\n", node->dump_name ()); + vec cycle_nodes = ipa_get_nodes_in_cycle (node); - /* 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; - w = w_info->next_cycle; - while (w) + /* If any node in a cycle is read_all or write_all, they all are. */ + FOR_EACH_VEC_ELT (cycle_nodes, x, w) { - 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; - - w_info = (struct ipa_dfs_info *) w->aux; - w = w_info->next_cycle; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " Visiting %s\n", w->dump_asm_name ()); + get_read_write_all_from_node (w, read_all, write_all); + if (read_all && write_all) + break; } - - /* Initialized the bitmaps for the reduced nodes */ + /* Initialized the bitmaps global sets for the reduced node. */ if (read_all) node_g->statics_read = all_module_statics; else - { - node_g->statics_read = BITMAP_ALLOC (&local_info_obstack); - bitmap_copy (node_g->statics_read, - node_l->statics_read); - } + node_g->statics_read = copy_static_var_set (node_l->statics_read); if (write_all) node_g->statics_written = all_module_statics; else - { - node_g->statics_written = BITMAP_ALLOC (&local_info_obstack); - bitmap_copy (node_g->statics_written, - node_l->statics_written); - } + node_g->statics_written = copy_static_var_set (node_l->statics_written); - propagate_bits (node_g, node); - w_info = (struct ipa_dfs_info *) node->aux; - w = w_info->next_cycle; - while (w) + /* Merge the sets of this cycle with all sets of callees reached + from this cycle. */ + FOR_EACH_VEC_ELT (cycle_nodes, x, w) { - ipa_reference_vars_info_t w_ri = - get_reference_vars_info (w); - ipa_reference_local_vars_info_t w_l = &w_ri->local; - - /* These global bitmaps are initialized from the local info - of all of the nodes in the region. However there is no - need to do any work if the bitmaps were set to - all_module_statics. */ - if (!read_all) - bitmap_ior_into (node_g->statics_read, - w_l->statics_read); - if (!write_all) - bitmap_ior_into (node_g->statics_written, - w_l->statics_written); + if (read_all && write_all) + break; + + if (w != node) + { + ipa_reference_vars_info_t w_ri = get_reference_vars_info (w); + ipa_reference_local_vars_info_t w_l = &w_ri->local; + int flags = flags_from_decl_or_type (w->decl); + + if (!(flags & ECF_CONST)) + read_all = union_static_var_sets (node_g->statics_read, + w_l->statics_read); + if (!(flags & ECF_PURE) + && !w->cannot_return_p ()) + write_all = union_static_var_sets (node_g->statics_written, + w_l->statics_written); + } + propagate_bits (node_g, w); - w_info = (struct ipa_dfs_info *) w->aux; - w = w_info->next_cycle; } /* All nodes within a cycle have the same global info bitmaps. */ - node_info->global = *node_g; - w_info = (struct ipa_dfs_info *) node->aux; - w = w_info->next_cycle; - while (w) + FOR_EACH_VEC_ELT (cycle_nodes, x, w) { - ipa_reference_vars_info_t w_ri = - get_reference_vars_info (w); - + ipa_reference_vars_info_t w_ri = get_reference_vars_info (w); w_ri->global = *node_g; - - w_info = (struct ipa_dfs_info *) w->aux; - w = w_info->next_cycle; } + + cycle_nodes.release (); } if (dump_file) { - for (i = 0; i < order_pos; i++ ) + for (i = 0; i < order_pos; i++) { - ipa_reference_vars_info_t node_info; - ipa_reference_global_vars_info_t node_g; - ipa_reference_local_vars_info_t node_l; - unsigned int index; - bitmap_iterator bi; - struct ipa_dfs_info * w_info; + unsigned x; + struct cgraph_node *w; node = order[i]; - node_info = get_reference_vars_info (node); - node_g = &node_info->global; - node_l = &node_info->local; - fprintf (dump_file, - "\nFunction name:%s/%i:", - cgraph_node_name (node), node->uid); - fprintf (dump_file, "\n locals read: "); - 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: "); - 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)); - } + if (node->alias || !opt_for_fn (node->decl, flag_ipa_reference)) + continue; + + fprintf (dump_file, "\nFunction name:%s:", node->dump_asm_name ()); + + ipa_reference_vars_info_t node_info = get_reference_vars_info (node); + ipa_reference_global_vars_info_t node_g = &node_info->global; - w_info = (struct ipa_dfs_info *) node->aux; - w = w_info->next_cycle; - while (w) + vec cycle_nodes = ipa_get_nodes_in_cycle (node); + FOR_EACH_VEC_ELT (cycle_nodes, x, w) { - ipa_reference_vars_info_t w_ri = - get_reference_vars_info (w); + ipa_reference_vars_info_t w_ri = get_reference_vars_info (w); ipa_reference_local_vars_info_t w_l = &w_ri->local; - fprintf (dump_file, "\n next cycle: %s/%i ", - cgraph_node_name (w), w->uid); + if (w != node) + fprintf (dump_file, "\n next cycle: %s ", w->dump_asm_name ()); fprintf (dump_file, "\n locals read: "); - if (w_l->statics_read) - EXECUTE_IF_SET_IN_BITMAP (w_l->statics_read, - 0, index, bi) - { - fprintf (dump_file, "%s ", - get_static_name (index)); - } - + dump_static_vars_set_to_file (dump_file, w_l->statics_read); fprintf (dump_file, "\n locals written: "); - if (w_l->statics_written) - EXECUTE_IF_SET_IN_BITMAP (w_l->statics_written, - 0, index, bi) - { - fprintf (dump_file, "%s ", - get_static_name (index)); - } - - w_info = (struct ipa_dfs_info *) w->aux; - w = w_info->next_cycle; + dump_static_vars_set_to_file (dump_file, w_l->statics_written); } + cycle_nodes.release (); + fprintf (dump_file, "\n globals read: "); - 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)); - } + dump_static_vars_set_to_file (dump_file, node_g->statics_read); fprintf (dump_file, "\n globals written: "); - 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)); - } + dump_static_vars_set_to_file (dump_file, node_g->statics_written); + fprintf (dump_file, "\n"); } } + if (ipa_ref_opt_sum_summaries == NULL) + ipa_ref_opt_sum_summaries = new ipa_ref_opt_summary_t (symtab); + /* Cleanup. */ - for (node = cgraph_nodes; node; node = node->next) + FOR_EACH_DEFINED_FUNCTION (node) { ipa_reference_vars_info_t node_info; ipa_reference_global_vars_info_t node_g; - ipa_reference_optimization_summary_t opt; - - if (!node->analyzed) - continue; node_info = get_reference_vars_info (node); - if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE) + if (!node->alias && opt_for_fn (node->decl, flag_ipa_reference) + && (node->get_availability () > AVAIL_INTERPOSABLE + || (flags_from_decl_or_type (node->decl) & ECF_LEAF))) { node_g = &node_info->global; - opt = XCNEW (struct ipa_reference_optimization_summary_d); - set_reference_optimization_summary (node, opt); + ipa_reference_optimization_summary_d *opt + = ipa_ref_opt_sum_summaries->get_create (node); /* Create the complimentary sets. */ - opt->statics_not_read = BITMAP_ALLOC (&optimization_summary_obstack); - opt->statics_not_written = BITMAP_ALLOC (&optimization_summary_obstack); - - if (node_g->statics_read != all_module_statics) - bitmap_and_compl (opt->statics_not_read, - all_module_statics, - node_g->statics_read); - - if (node_g->statics_written - != all_module_statics) - bitmap_and_compl (opt->statics_not_written, - all_module_statics, - node_g->statics_written); - } - if (node_info) - free (node_info); - if (node->aux) - { - free (node->aux); - node->aux = NULL; + + if (bitmap_empty_p (node_g->statics_read)) + opt->statics_not_read = all_module_statics; + else + { + opt->statics_not_read + = BITMAP_ALLOC (&optimization_summary_obstack); + if (node_g->statics_read != all_module_statics) + bitmap_and_compl (opt->statics_not_read, + all_module_statics, + node_g->statics_read); + } + + if (bitmap_empty_p (node_g->statics_written)) + opt->statics_not_written = all_module_statics; + else + { + opt->statics_not_written + = BITMAP_ALLOC (&optimization_summary_obstack); + if (node_g->statics_written != all_module_statics) + bitmap_and_compl (opt->statics_not_written, + all_module_statics, + node_g->statics_written); + } } } + ipa_free_postorder_info (); free (order); bitmap_obstack_release (&local_info_obstack); - VEC_free (ipa_reference_vars_info_t, heap, ipa_reference_vars_vector); - ipa_reference_vars_vector = NULL; + + if (ipa_ref_var_info_summaries == NULL) + { + delete ipa_ref_var_info_summaries; + ipa_ref_var_info_summaries = NULL; + } + + ipa_ref_var_info_summaries = NULL; if (dump_file) splay_tree_delete (reference_vars_to_consider); reference_vars_to_consider = NULL; - all_module_statics = NULL; - return 0; + return remove_p ? TODO_remove_functions : 0; } /* Return true if we need to write summary of NODE. */ static bool write_node_summary_p (struct cgraph_node *node, - cgraph_node_set set, - varpool_node_set vset, + lto_symtab_encoder_t encoder, bitmap ltrans_statics) { ipa_reference_optimization_summary_t info; /* See if we have (non-empty) info. */ - if (!node->analyzed || node->global.inlined_to) + if (!node->definition || node->global.inlined_to) return false; info = get_reference_optimization_summary (node); - if (!info || (bitmap_empty_p (info->statics_not_read) - && bitmap_empty_p (info->statics_not_written))) + if (!info + || (bitmap_empty_p (info->statics_not_read) + && bitmap_empty_p (info->statics_not_written))) return false; /* See if we want to encode it. @@ -912,8 +928,8 @@ write_node_summary_p (struct cgraph_node *node, In future we might also want to include summaries of functions references by initializers of constant variables references in current unit. */ - if (!reachable_from_this_partition_p (node, set) - && !referenced_from_this_partition_p (&node->ref_list, set, vset)) + if (!reachable_from_this_partition_p (node, encoder) + && !referenced_from_this_partition_p (node, encoder)) return false; /* See if the info has non-empty intersections with vars we want to encode. */ @@ -923,77 +939,112 @@ write_node_summary_p (struct cgraph_node *node, return true; } -/* Stream out BITS<RANS_STATICS as list of decls to OB. */ +/* Stream out BITS<RANS_STATICS as list of decls to OB. + LTRANS_STATICS_BITCOUNT specify number of bits in LTRANS_STATICS + or -1. When it is positive, just output -1 when + BITS<RANS_STATICS == BITS<RANS_STATICS. */ static void stream_out_bitmap (struct lto_simple_output_block *ob, - bitmap bits, bitmap ltrans_statics) + bitmap bits, bitmap ltrans_statics, + int ltrans_statics_bitcount) { - unsigned int count = 0; + int count = 0; unsigned int index; bitmap_iterator bi; + if (bits == all_module_statics) + { + streamer_write_hwi_stream (ob->main_stream, -1); + return; + } EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi) count ++; - lto_output_uleb128_stream (ob->main_stream, count); + if (count == ltrans_statics_bitcount) + { + streamer_write_hwi_stream (ob->main_stream, -1); + return; + } + streamer_write_hwi_stream (ob->main_stream, count); if (!count) return; EXECUTE_IF_AND_IN_BITMAP (bits, ltrans_statics, 0, index, bi) { - tree decl = (tree)splay_tree_lookup (reference_vars_to_consider, index)->value; - lto_output_var_decl_index(ob->decl_state, ob->main_stream, decl); + tree decl = (tree)splay_tree_lookup (reference_vars_to_consider, + index)->value; + lto_output_var_decl_index (ob->decl_state, ob->main_stream, decl); } } /* Serialize the ipa info for lto. */ static void -ipa_reference_write_optimization_summary (cgraph_node_set set, - varpool_node_set vset) +ipa_reference_write_optimization_summary (void) { - struct cgraph_node *node; - struct varpool_node *vnode; struct lto_simple_output_block *ob = lto_create_simple_output_block (LTO_section_ipa_reference); unsigned int count = 0; - lto_cgraph_encoder_t encoder = ob->decl_state->cgraph_node_encoder; - bitmap ltrans_statics = BITMAP_ALLOC (NULL); + int ltrans_statics_bitcount = 0; + lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder; + auto_bitmap ltrans_statics; + int i; reference_vars_to_consider = splay_tree_new (splay_tree_compare_ints, 0, 0); /* See what variables we are interested in. */ - for (vnode = varpool_nodes; vnode; vnode = vnode->next) - if (referenced_from_this_partition_p (&vnode->ref_list, set, vset)) + for (i = 0; i < lto_symtab_encoder_size (encoder); i++) + { + symtab_node *snode = lto_symtab_encoder_deref (encoder, i); + varpool_node *vnode = dyn_cast (snode); + if (vnode + && bitmap_bit_p (all_module_statics, + ipa_reference_var_uid (vnode->decl)) + && referenced_from_this_partition_p (vnode, encoder)) + { + tree decl = vnode->decl; + bitmap_set_bit (ltrans_statics, ipa_reference_var_uid (decl)); + splay_tree_insert (reference_vars_to_consider, + ipa_reference_var_uid (decl), + (splay_tree_value)decl); + ltrans_statics_bitcount ++; + } + } + + + if (ltrans_statics_bitcount) + for (i = 0; i < lto_symtab_encoder_size (encoder); i++) { - tree decl = vnode->decl; - if (is_proper_for_analysis (decl)) - { - bitmap_set_bit (ltrans_statics, DECL_UID (decl)); - splay_tree_insert (reference_vars_to_consider, - DECL_UID (decl), (splay_tree_value)decl); - } + symtab_node *snode = lto_symtab_encoder_deref (encoder, i); + cgraph_node *cnode = dyn_cast (snode); + if (cnode && write_node_summary_p (cnode, encoder, ltrans_statics)) + count++; } - for (node = cgraph_nodes; node; node = node->next) - if (write_node_summary_p (node, set, vset, ltrans_statics)) - count++; - - lto_output_uleb128_stream (ob->main_stream, count); + streamer_write_uhwi_stream (ob->main_stream, count); + if (count) + stream_out_bitmap (ob, ltrans_statics, ltrans_statics, + -1); /* Process all of the functions. */ - for (node = cgraph_nodes; node; node = node->next) - if (write_node_summary_p (node, set, vset, ltrans_statics)) + if (ltrans_statics_bitcount) + for (i = 0; i < lto_symtab_encoder_size (encoder); i++) { - ipa_reference_optimization_summary_t info; - int node_ref; + symtab_node *snode = lto_symtab_encoder_deref (encoder, i); + cgraph_node *cnode = dyn_cast (snode); + if (cnode && write_node_summary_p (cnode, encoder, ltrans_statics)) + { + ipa_reference_optimization_summary_t info; + int node_ref; - info = get_reference_optimization_summary (node); - node_ref = lto_cgraph_encoder_encode (encoder, node); - lto_output_uleb128_stream (ob->main_stream, node_ref); + info = get_reference_optimization_summary (cnode); + node_ref = lto_symtab_encoder_encode (encoder, snode); + streamer_write_uhwi_stream (ob->main_stream, node_ref); - stream_out_bitmap (ob, info->statics_not_read, ltrans_statics); - stream_out_bitmap (ob, info->statics_not_written, ltrans_statics); + stream_out_bitmap (ob, info->statics_not_read, ltrans_statics, + ltrans_statics_bitcount); + stream_out_bitmap (ob, info->statics_not_written, ltrans_statics, + ltrans_statics_bitcount); + } } - BITMAP_FREE (ltrans_statics); lto_destroy_simple_output_block (ob); splay_tree_delete (reference_vars_to_consider); } @@ -1009,72 +1060,106 @@ ipa_reference_read_optimization_summary (void) unsigned int j = 0; bitmap_obstack_initialize (&optimization_summary_obstack); - 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); + if (ipa_ref_opt_sum_summaries == NULL) + ipa_ref_opt_sum_summaries = new ipa_ref_opt_summary_t (symtab); + + all_module_statics = BITMAP_ALLOC (&optimization_summary_obstack); while ((file_data = file_data_vec[j++])) { const char *data; size_t len; - struct lto_input_block *ib + class 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); + unsigned int f_count = streamer_read_uhwi (ib); + int b_count; + if (!f_count) + continue; + b_count = streamer_read_hwi (ib); + if (dump_file) + fprintf (dump_file, "all module statics:"); + for (i = 0; i < (unsigned int)b_count; i++) + { + unsigned int var_index = streamer_read_uhwi (ib); + tree v_decl = lto_file_decl_data_get_var_decl (file_data, + var_index); + bitmap_set_bit (all_module_statics, + ipa_reference_var_uid (v_decl)); + if (dump_file) + fprintf (dump_file, " %s", fndecl_name (v_decl)); + } for (i = 0; i < f_count; i++) { unsigned int j, index; struct cgraph_node *node; - ipa_reference_optimization_summary_t info; 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); - info = XCNEW (struct ipa_reference_optimization_summary_d); - set_reference_optimization_summary (node, info); - info->statics_not_read = BITMAP_ALLOC (&optimization_summary_obstack); - info->statics_not_written = BITMAP_ALLOC (&optimization_summary_obstack); + lto_symtab_encoder_t encoder; + + index = streamer_read_uhwi (ib); + encoder = file_data->symtab_node_encoder; + node = dyn_cast (lto_symtab_encoder_deref + (encoder, index)); + + ipa_reference_optimization_summary_d *info + = ipa_ref_opt_sum_summaries->get_create (node); + + info->statics_not_read = BITMAP_ALLOC + (&optimization_summary_obstack); + info->statics_not_written = BITMAP_ALLOC + (&optimization_summary_obstack); if (dump_file) fprintf (dump_file, - "\nFunction name:%s/%i:\n static not read:", - cgraph_node_name (node), node->uid); + "\nFunction name:%s:\n static not read:", + node->dump_asm_name ()); /* Set the statics not read. */ - v_count = lto_input_uleb128 (ib); - for (j = 0; j < (unsigned int)v_count; j++) + v_count = streamer_read_hwi (ib); + if (v_count == -1) { - unsigned int var_index = lto_input_uleb128 (ib); - tree v_decl = lto_file_decl_data_get_var_decl (file_data, - var_index); - bitmap_set_bit (info->statics_not_read, DECL_UID (v_decl)); + info->statics_not_read = all_module_statics; if (dump_file) - fprintf (dump_file, " %s", - lang_hooks.decl_printable_name (v_decl, 2)); + fprintf (dump_file, " all module statics"); } + else + for (j = 0; j < (unsigned int)v_count; j++) + { + unsigned int var_index = streamer_read_uhwi (ib); + tree v_decl = lto_file_decl_data_get_var_decl (file_data, + var_index); + bitmap_set_bit (info->statics_not_read, + ipa_reference_var_uid (v_decl)); + if (dump_file) + fprintf (dump_file, " %s", fndecl_name (v_decl)); + } if (dump_file) fprintf (dump_file, "\n static not written:"); /* Set the statics not written. */ - v_count = lto_input_uleb128 (ib); - for (j = 0; j < (unsigned int)v_count; j++) + v_count = streamer_read_hwi (ib); + if (v_count == -1) { - unsigned int var_index = lto_input_uleb128 (ib); - tree v_decl = lto_file_decl_data_get_var_decl (file_data, - var_index); - bitmap_set_bit (info->statics_not_written, DECL_UID (v_decl)); + info->statics_not_written = all_module_statics; if (dump_file) - fprintf (dump_file, " %s", - lang_hooks.decl_printable_name (v_decl, 2)); + fprintf (dump_file, " all module statics"); } + else + for (j = 0; j < (unsigned int)v_count; j++) + { + unsigned int var_index = streamer_read_uhwi (ib); + tree v_decl = lto_file_decl_data_get_var_decl (file_data, + var_index); + bitmap_set_bit (info->statics_not_written, + ipa_reference_var_uid (v_decl)); + if (dump_file) + fprintf (dump_file, " %s", fndecl_name (v_decl)); + } if (dump_file) fprintf (dump_file, "\n"); } @@ -1084,45 +1169,82 @@ ipa_reference_read_optimization_summary (void) ib, data, len); } else - /* Fatal error here. We do not want to support compiling ltrans units with - different version of compiler or different flags than the WPA unit, so - this should never happen. */ - fatal_error ("ipa reference summary is missing in ltrans unit"); + /* Fatal error here. We do not want to support compiling ltrans units + with different version of compiler or different flags than + the WPA unit, so this should never happen. */ + fatal_error (input_location, + "ipa reference summary is missing in ltrans unit"); } } -static bool -gate_reference (void) +namespace { + +const pass_data pass_data_ipa_reference = { - return (flag_ipa_reference - /* Don't bother doing anything if the program has errors. */ - && !seen_error ()); + IPA_PASS, /* type */ + "static-var", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_IPA_REFERENCE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_ipa_reference : public ipa_opt_pass_d +{ +public: + pass_ipa_reference (gcc::context *ctxt) + : ipa_opt_pass_d (pass_data_ipa_reference, ctxt, + NULL, /* generate_summary */ + NULL, /* write_summary */ + NULL, /* read_summary */ + ipa_reference_write_optimization_summary, /* + write_optimization_summary */ + ipa_reference_read_optimization_summary, /* + read_optimization_summary */ + NULL, /* stmt_fixup */ + 0, /* function_transform_todo_flags_start */ + NULL, /* function_transform */ + NULL) /* variable_transform */ + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + return ((in_lto_p || flag_ipa_reference) + /* Don't bother doing anything if the program has errors. */ + && !seen_error ()); + } + + virtual unsigned int execute (function *) { return propagate (); } + +}; // class pass_ipa_reference + +} // anon namespace + +ipa_opt_pass_d * +make_pass_ipa_reference (gcc::context *ctxt) +{ + return new pass_ipa_reference (ctxt); } -struct ipa_opt_pass_d pass_ipa_reference = +/* Reset all state within ipa-reference.c so that we can rerun the compiler + within the same process. For use by toplev::finalize. */ + +void +ipa_reference_c_finalize (void) { - { - IPA_PASS, - "static-var", /* name */ - gate_reference, /* gate */ - propagate, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_IPA_REFERENCE, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0 /* todo_flags_finish */ - }, - NULL, /* generate_summary */ - NULL, /* write_summary */ - NULL, /* read_summary */ - ipa_reference_write_optimization_summary,/* write_optimization_summary */ - ipa_reference_read_optimization_summary,/* read_optimization_summary */ - NULL, /* stmt_fixup */ - 0, /* TODOs */ - NULL, /* function_transform */ - NULL /* variable_transform */ -}; + if (ipa_ref_opt_sum_summaries != NULL) + { + delete ipa_ref_opt_sum_summaries; + ipa_ref_opt_sum_summaries = NULL; + } + + if (ipa_init_p) + { + bitmap_obstack_release (&optimization_summary_obstack); + ipa_init_p = false; + } +}