diff options
40 files changed, 676 insertions, 486 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e93f209..54f944a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,122 @@ 2013-05-29 Jan Hubicka <jh@suse.cz> + * cgraph.h (symtab_node_base): Add definition, alias and analyzed + flags; reorder rest of fields in more consistent way. + (varpool_node): Remove analyzed, finalized and alias. + (cgraph_ndoe): Likewise. + (symtab_alias_ultimate_target): New function. + (cgraph_function_node): Move offline. + (cgraph_reset_node): Declare. + (cgraph_comdat_can_be_unshared_p): Remove. + (varpool_remove_initializer): Declare. + (varpool_first_defined_variable, varpool_next_defined_variable + cgraph_first_defined_function, cgraph_next_defined_function): Update. + (cgraph_function_with_gimple_body_p): Update. + (varpool_all_refs_explicit_p): Update. + (symtab_alias_target): New function. + (cgraph_alias_aliased_node, varpool_alias_aliased_node): Rename to ... + (cgraph_alias_target, varpool_alias_target): .. this one; simplify. + (cgraph_function_or_thunk_node): Simplify using symtab_alias_ultimate_target. + (varpool_variable_node): Likewise. + * cgraph.c (cgraph_create_function_alias): Update. + (cgraph_add_thunk): Update. + (cgraph_remove_node): Update. + (dump_cgraph_node): Do not dump removed flags. + (cgraph_function_body_availability): Update. + (cgraph_propagate_frequency): Update. + (verify_cgraph_node): Check sanity of local flag. + (cgraph_function_node): Move here from cgraph.h; revamp for + cgraph_function_or_thunk_node. + * lto-symtab.c (lto_varpool_replace_node): Update. + (lto_symtab_resolve_can_prevail_p): Update. + (lto_symtab_merge_cgraph_nodes): Update. + * ipa-cp.c (determine_versionability, initialize_node_lattices, + propagate_constants_accross_call, devirtualization_time_bonus, + ipcp_propagate_stage): Update. + * tree-emutls.c (create_emultls_var, ipa_lower_emutls): Update. + * ipa-inline-transform.c (clone_inlined_nodes, preserve_function_body_p): Update. + * ipa-reference.c (propagate): Update. + (write_node_summary_p): Update. + * toplev.c (wrapup_global_declaration_2): Update. + * cgraphunit.c (cgraph_analyze_function): Rename to ... + (analyze_function) ... this one. + (cgraph_process_new_functions): Update. + (cgraph_reset_node): Export. + (cgraph_finalize_function): Update. + (cgraph_add_new_function): Update. + (process_function_and_variable_attributes): Update. + (varpool_finalize_decl): Update. + (symbol_finalized): Remove. + (symbol_finalized_and_needed): Rename to ... + (symbol_defined_and_needed): ... update. + (cgraph_analyze_functions): Update. + (handle_alias_pairs): Update. + (mark_functions_to_output): Update. + (assemble_thunk): Update. + (output_in_order): Update. + (output_weakrefs): Update. + (finalize_compilation_unit): Update. + * lto-cgraph.c (reachable_from_other_partition_p, lto_output_node, + lto_output_varpool_node, compute_ltrans_boundary, input_overwrite_node, + input_node, input_varpool_node): Update. + * dbxout.c (dbxout_expand_expr): Update. + * cgraphclones.c (cgraph_clone_node): Update. + (cgraph_copy_node_for_versioning): Update. + (cgraph_materialize_clone): Update. + (cgraph_materialize_all_clones): Update. + * ipa-pure-const.c (analyze_function, pure_const_write_summary, + propagate_pure_const, propagate_nothrow): Update. + * lto-streamer-out.c (lto_output, write_symbol): Update. + * ipa-utils.c (ipa_reverse_postorder): Update. + * ipa-inline.c (can_inline_edge_p): Update. + (update_caller_keys, ipa_inline): Update. + * dwarf2out.c (reference_to_unused, + premark_types_used_by_global_vars_helper): Update. + * tree-eh.c (tree_could_trap_p): Update. + * ipa-split.c (consider_split, execute_split_functions): Update. + * ipa.c (cgraph_non_local_node_p_1, cgraph_local_node_p, + has_addr_references_p): Update; + move ahead in file for better readability. + (process_references): Simplify. + (symtab_remove_unreachable_nodes): Update; cleanup way function/var + bodies are removed. + (cgraph_comdat_can_be_unshared_p): Make static. + (cgraph_externally_visible_p): Update. + (varpool_externally_visible_p): Update. + (function_and_variable_visibility): Update. + * trans-mem.c (get_cg_data, ipa_tm_mayenterirr_function, + ipa_tm_mark_force_output_node): Update. + * ipa-inline-analysis.c (dump_inline_summary, initialize_inline_failed, + estimate_edge_devirt_benefit, inline_generate_summary, + inline_write_summary): Update. + * gimple-fold.c (can_refer_decl_in_current_unit_p): Update. + * ipa-prop.c (ipa_compute_jump_functions): Update. + (ipa_print_node_params, ipa_prop_read_section, ipa_update_after_lto_read, + read_replacements_section): Update. + * varasm.c (mark_decl_referenced): Update. + (assemble_alias, dump_tm_clone_pairs): Update. + * tree-inline.c (copy_bb): Update. + (estimate_num_insns, optimize_inline_calls, tree_function_versioning): + Update. + * symtab.c (dump_symtab_base): Print new flags. + (verify_symtab_base): Verify new flags. + (symtab_alias_ultimate_target): New function. + * tree-ssa-structalias.c (get_constraint_for_ssa_var, + create_variable_info_for, associate_varinfo_to_alias, ipa_pta_execute): + Update. + * passes.c (ipa_write_summaries, ipa_write_optimization_summaries): Update. + * i386.c (ix86_get_function_versions_dispatcher, + ix86_generate_version_dispatcher_body): Update. + (fold_builtin_cpu): Use varpool_add_new_variable. + * varpool.c (varpool_remove_initializer): Break out from ... + (varpool_remove_node): ... this one. + (dump_varpool_node, varpool_node_for_asm, + cgraph_variable_initializer_availability, varpool_analyze_node, + varpool_assemble_decl, varpool_remove_unreferenced_decls, + varpool_finalize_named_section_flags, varpool_create_variable_alias): Update + +2013-05-29 Jan Hubicka <jh@suse.cz> + * passes.c (init_optimization_passes): Move OMP expansion into lowering. 2013-05-29 Easwaran Raman <eraman@google.com> diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 2a2973b..735f48a 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -563,10 +563,10 @@ cgraph_create_function_alias (tree alias, tree decl) gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); gcc_assert (TREE_CODE (alias) == FUNCTION_DECL); alias_node = cgraph_get_create_node (alias); - gcc_assert (!alias_node->local.finalized); + gcc_assert (!alias_node->symbol.definition); alias_node->thunk.alias = decl; - alias_node->local.finalized = true; - alias_node->alias = 1; + alias_node->symbol.definition = true; + alias_node->symbol.alias = true; return alias_node; } @@ -613,8 +613,8 @@ cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, node = cgraph_get_node (alias); if (node) { - gcc_assert (node->local.finalized); - gcc_assert (!node->alias); + gcc_assert (node->symbol.definition); + gcc_assert (!node->symbol.alias); gcc_assert (!node->thunk.thunk_p); cgraph_remove_node (node); } @@ -629,7 +629,7 @@ cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, node->thunk.virtual_offset_p = virtual_offset != NULL; node->thunk.alias = real_alias; node->thunk.thunk_p = true; - node->local.finalized = true; + node->symbol.definition = true; return node; } @@ -1384,7 +1384,7 @@ cgraph_remove_node (struct cgraph_node *node) && (cgraph_global_info_ready && (TREE_ASM_WRITTEN (n->symbol.decl) || DECL_EXTERNAL (n->symbol.decl) - || !n->analyzed + || !n->symbol.analyzed || n->symbol.in_other_partition)))) cgraph_release_function_body (node); @@ -1521,8 +1521,6 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) cgraph_availability_names [cgraph_function_body_availability (node)]); fprintf (f, " Function flags:"); - if (node->analyzed) - fprintf (f, " analyzed"); if (node->count) fprintf (f, " executed "HOST_WIDEST_INT_PRINT_DEC"x", (HOST_WIDEST_INT)node->count); @@ -1534,16 +1532,12 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) fprintf (f, " process"); if (node->local.local) fprintf (f, " local"); - if (node->local.finalized) - fprintf (f, " finalized"); if (node->local.redefined_extern_inline) fprintf (f, " redefined_extern_inline"); if (node->only_called_at_startup) fprintf (f, " only_called_at_startup"); if (node->only_called_at_exit) fprintf (f, " only_called_at_exit"); - else if (node->alias) - fprintf (f, " alias"); if (node->tm_clone) fprintf (f, " tm_clone"); @@ -1559,7 +1553,8 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node) (int)node->thunk.virtual_value, (int)node->thunk.virtual_offset_p); } - if (node->alias && node->thunk.alias && DECL_P (node->thunk.alias)) + if (node->symbol.alias && node->thunk.alias + && DECL_P (node->thunk.alias)) { fprintf (f, " Alias of %s", lang_hooks.decl_printable_name (node->thunk.alias, 2)); @@ -1676,7 +1671,7 @@ cgraph_function_body_availability (struct cgraph_node *node) { enum availability avail; gcc_assert (cgraph_function_flags_ready); - if (!node->analyzed) + if (!node->symbol.analyzed) avail = AVAIL_NOT_AVAILABLE; else if (node->local.local) avail = AVAIL_LOCAL; @@ -1983,7 +1978,7 @@ cgraph_propagate_frequency (struct cgraph_node *node) if (!node->local.local) return false; - gcc_assert (node->analyzed); + gcc_assert (node->symbol.analyzed); if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Processing frequency %s\n", cgraph_node_name (node)); @@ -2342,6 +2337,11 @@ verify_cgraph_node (struct cgraph_node *node) error ("inline clone in same comdat group list"); error_found = true; } + if (!node->symbol.definition && node->local.local) + { + error ("local symbols must be defined"); + error_found = true; + } if (node->global.inlined_to && node->symbol.externally_visible) { error ("externally visible inline clone"); @@ -2455,7 +2455,7 @@ verify_cgraph_node (struct cgraph_node *node) error_found = true; } - if (node->analyzed && node->alias) + if (node->symbol.analyzed && node->symbol.alias) { bool ref_found = false; int i; @@ -2486,7 +2486,7 @@ verify_cgraph_node (struct cgraph_node *node) error_found = true; } } - if (node->analyzed && node->thunk.thunk_p) + if (node->symbol.analyzed && node->thunk.thunk_p) { if (!node->callees) { @@ -2504,7 +2504,7 @@ verify_cgraph_node (struct cgraph_node *node) error_found = true; } } - else if (node->analyzed && gimple_has_body_p (node->symbol.decl) + else if (node->symbol.analyzed && gimple_has_body_p (node->symbol.decl) && !TREE_ASM_WRITTEN (node->symbol.decl) && (!DECL_EXTERNAL (node->symbol.decl) || node->global.inlined_to) && !flag_wpa) @@ -2653,4 +2653,32 @@ cgraph_get_create_real_symbol_node (tree decl) node->symbol.order); return node; } + + +/* Given NODE, walk the alias chain to return the function NODE is alias of. + Walk through thunk, too. + When AVAILABILITY is non-NULL, get minimal availability in the chain. */ + +struct cgraph_node * +cgraph_function_node (struct cgraph_node *node, enum availability *availability) +{ + do + { + node = cgraph_function_or_thunk_node (node, availability); + if (node->thunk.thunk_p) + { + node = node->callees->callee; + if (availability) + { + enum availability a; + a = cgraph_function_body_availability (node); + if (a < *availability) + *availability = a; + } + node = cgraph_function_or_thunk_node (node, availability); + } + } while (node && node->thunk.thunk_p); + return node; +} + #include "gt-cgraph.h" diff --git a/gcc/cgraph.h b/gcc/cgraph.h index fcb9261..0dcc1a6 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -30,7 +30,7 @@ along with GCC; see the file COPYING3. If not see #include "ipa-ref.h" /* Symbol table consists of functions and variables. - TODO: add labels, constant pool and aliases. */ + TODO: add labels and CONST_DECLs. */ enum symtab_type { SYMTAB_SYMBOL, @@ -48,15 +48,21 @@ struct GTY(()) symtab_node_base /* The symbols resolution. */ ENUM_BITFIELD (ld_plugin_symbol_resolution) resolution : 8; - /* Set when function has address taken. - In current implementation it imply needed flag. */ - unsigned address_taken : 1; - /* Set when variable is used from other LTRANS partition. */ - unsigned used_from_other_partition : 1; - /* Set when function is available in the other LTRANS partition. - During WPA output it is used to mark nodes that are present in - multiple partitions. */ - unsigned in_other_partition : 1; + /*** Flags representing the symbol type. ***/ + + /* True when symbol corresponds to a definition in current unit. + set via cgraph_finalize_function or varpool_finalize_decl */ + unsigned definition : 1; + /* True when symbol is an alias. + Set by assemble_alias. */ + unsigned alias : 1; + /* Set once the definition was analyzed. The list of references and + other properties are built during analysis. */ + unsigned analyzed : 1; + + + /*** Visibility and linkage flags. ***/ + /* Set when function is visible by other units. */ unsigned externally_visible : 1; /* Needed variables might become dead by optimization. This flag @@ -65,30 +71,57 @@ struct GTY(()) symtab_node_base /* True when the name is known to be unique and thus it does not need mangling. */ unsigned unique_name : 1; - /* Ordering of all symtab entries. */ - int order; - tree decl; + /*** WHOPR Partitioning flags. + These flags are used at ltrans stage when only part of the callgraph is + available. ***/ - /* Vectors of referring and referenced entities. */ - struct ipa_ref_list ref_list; + /* Set when variable is used from other LTRANS partition. */ + unsigned used_from_other_partition : 1; + /* Set when function is available in the other LTRANS partition. + During WPA output it is used to mark nodes that are present in + multiple partitions. */ + unsigned in_other_partition : 1; - /* Circular list of nodes in the same comdat group if non-NULL. */ - symtab_node same_comdat_group; - /* File stream where this node is being written to. */ - struct lto_file_decl_data * lto_file_data; + + /*** other flags. ***/ + + /* Set when symbol has address taken. */ + unsigned address_taken : 1; + + + /* Ordering of all symtab entries. */ + int order; + + /* Declaration representing the symbol. */ + tree decl; /* Linked list of symbol table entries starting with symtab_nodes. */ symtab_node next; symtab_node previous; + /* Linked list of symbols with the same asm name. There may be multiple - entries for single symbol name in the case of LTO resolutions, - existence of inline clones, or duplicated declaration. The last case - is a long standing bug frontends and builtin handling. */ + entries for single symbol name during LTO, because symbols are renamed + only after partitioning. + + Because inline clones are kept in the assembler name has, they also produce + duplicate entries. + + There are also several long standing bugs where frontends and builtin + code produce duplicated decls. */ symtab_node next_sharing_asm_name; symtab_node previous_sharing_asm_name; + /* Circular list of nodes in the same comdat group if non-NULL. */ + symtab_node same_comdat_group; + + /* Vectors of referring and referenced entities. */ + struct ipa_ref_list ref_list; + + /* File stream where this node is being written to. */ + struct lto_file_decl_data * lto_file_data; + PTR GTY ((skip)) aux; }; @@ -142,9 +175,6 @@ struct GTY(()) cgraph_local_info { and its address is never taken. */ unsigned local : 1; - /* Set once it has been finalized so we consider it to be output. */ - unsigned finalized : 1; - /* False when there is something makes versioning impossible. */ unsigned versionable : 1; @@ -260,11 +290,7 @@ struct GTY(()) cgraph_node { unsigned lowered : 1; /* Set once the function has been instantiated and its callee lists created. */ - unsigned analyzed : 1; - /* Set when function is scheduled to be processed by local passes. */ unsigned process : 1; - /* Set for aliases once they got through assemble_alias. */ - unsigned alias : 1; /* Set for aliases created as C++ same body aliases. */ unsigned same_body_alias : 1; /* How commonly executed the node is. Initialized during branch @@ -455,16 +481,8 @@ struct GTY(()) varpool_node { /* For aliases points to declaration DECL is alias of. */ tree alias_of; - /* Set once the variable has been instantiated and its callee - lists created. */ - unsigned analyzed : 1; - /* Set once it has been finalized so we consider it to be output. */ - unsigned finalized : 1; /* Set when variable is scheduled to be assembled. */ unsigned output : 1; - /* Set for aliases once they got through assemble_alias. Also set for - extra name aliases in varpool_extra_name_alias. */ - unsigned alias : 1; unsigned extra_name_alias : 1; }; @@ -558,6 +576,7 @@ void verify_symtab_node (symtab_node); bool verify_symtab_base (symtab_node); bool symtab_used_from_object_file_p (symtab_node); void symtab_make_decl_local (tree); +symtab_node symtab_alias_ultimate_target (symtab_node, enum availability *); /* In cgraph.c */ void dump_cgraph (FILE *); @@ -653,6 +672,7 @@ struct cgraph_2node_hook_list *cgraph_add_node_duplication_hook (cgraph_2node_ho void cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *); gimple cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *); bool cgraph_propagate_frequency (struct cgraph_node *node); +struct cgraph_node * cgraph_function_node (struct cgraph_node *, enum availability *); /* In cgraphunit.c */ struct asm_node *add_asm_node (tree); @@ -663,10 +683,11 @@ void compile (void); void init_cgraph (void); bool cgraph_process_new_functions (void); void cgraph_process_same_body_aliases (void); -void fixup_same_cpp_alias_visibility (symtab_node node, symtab_node target, tree alias); +void fixup_same_cpp_alias_visibility (symtab_node, symtab_node target, tree); /* Initialize datastructures so DECL is a function in lowered gimple form. IN_SSA is true if the gimple is in SSA. */ -basic_block init_lowered_empty_function (tree decl, bool in_ssa); +basic_block init_lowered_empty_function (tree, bool); +void cgraph_reset_node (struct cgraph_node *); /* In cgraphclones.c */ @@ -728,7 +749,6 @@ void dump_varpool_node_set (FILE *, varpool_node_set); void debug_varpool_node_set (varpool_node_set); void free_varpool_node_set (varpool_node_set); void ipa_discover_readonly_nonaddressable_vars (void); -bool cgraph_comdat_can_be_unshared_p (struct cgraph_node *); bool varpool_externally_visible_p (struct varpool_node *); /* In predict.c */ @@ -765,6 +785,7 @@ bool varpool_for_node_and_aliases (struct varpool_node *, void varpool_add_new_variable (tree); void symtab_initialize_asm_name_hash (void); void symtab_prevail_in_asm_name_hash (symtab_node node); +void varpool_remove_initializer (struct varpool_node *); /* Return callgraph node for given symbol and check it is a function. */ @@ -900,7 +921,7 @@ varpool_first_defined_variable (void) for (node = symtab_nodes; node; node = node->symbol.next) { varpool_node *vnode = dyn_cast <varpool_node> (node); - if (vnode && vnode->analyzed) + if (vnode && vnode->symbol.definition) return vnode; } return NULL; @@ -914,7 +935,7 @@ varpool_next_defined_variable (struct varpool_node *node) for (; node1; node1 = node1->symbol.next) { varpool_node *vnode1 = dyn_cast <varpool_node> (node1); - if (vnode1 && vnode1->analyzed) + if (vnode1 && vnode1->symbol.definition) return vnode1; } return NULL; @@ -932,7 +953,7 @@ cgraph_first_defined_function (void) for (node = symtab_nodes; node; node = node->symbol.next) { cgraph_node *cn = dyn_cast <cgraph_node> (node); - if (cn && cn->analyzed) + if (cn && cn->symbol.definition) return cn; } return NULL; @@ -946,7 +967,7 @@ cgraph_next_defined_function (struct cgraph_node *node) for (; node1; node1 = node1->symbol.next) { cgraph_node *cn1 = dyn_cast <cgraph_node> (node1); - if (cn1 && cn1->analyzed) + if (cn1 && cn1->symbol.definition) return cn1; } return NULL; @@ -992,7 +1013,7 @@ cgraph_next_function (struct cgraph_node *node) static inline bool cgraph_function_with_gimple_body_p (struct cgraph_node *node) { - return node->analyzed && !node->thunk.thunk_p && !node->alias; + return node->symbol.definition && !node->thunk.thunk_p && !node->symbol.alias; } /* Return first function with body defined. */ @@ -1197,7 +1218,7 @@ varpool_can_remove_if_no_refs (struct varpool_node *node) static inline bool varpool_all_refs_explicit_p (struct varpool_node *vnode) { - return (vnode->analyzed + return (vnode->symbol.definition && !vnode->symbol.externally_visible && !vnode->symbol.used_from_other_partition && !vnode->symbol.force_output); @@ -1211,60 +1232,25 @@ htab_t constant_pool_htab (void); /* Return node that alias N is aliasing. */ -static inline struct cgraph_node * -cgraph_alias_aliased_node (struct cgraph_node *n) +static inline symtab_node +symtab_alias_target (symtab_node n) { struct ipa_ref *ref; - ipa_ref_list_reference_iterate (&n->symbol.ref_list, 0, ref); gcc_checking_assert (ref->use == IPA_REF_ALIAS); - if (is_a <cgraph_node> (ref->referred)) - return ipa_ref_node (ref); - return NULL; + return ref->referred; } -/* Return node that alias N is aliasing. */ - -static inline struct varpool_node * -varpool_alias_aliased_node (struct varpool_node *n) +static inline struct cgraph_node * +cgraph_alias_target (struct cgraph_node *n) { - struct ipa_ref *ref; - - ipa_ref_list_reference_iterate (&n->symbol.ref_list, 0, ref); - gcc_checking_assert (ref->use == IPA_REF_ALIAS); - if (is_a <varpool_node> (ref->referred)) - return ipa_ref_varpool_node (ref); - return NULL; + return dyn_cast <cgraph_node> (symtab_alias_target ((symtab_node) n)); } -/* Given NODE, walk the alias chain to return the function NODE is alias of. - Walk through thunk, too. - When AVAILABILITY is non-NULL, get minimal availability in the chain. */ - -static inline struct cgraph_node * -cgraph_function_node (struct cgraph_node *node, enum availability *availability) +static inline struct varpool_node * +varpool_alias_target (struct varpool_node *n) { - if (availability) - *availability = cgraph_function_body_availability (node); - while (node) - { - if (node->alias && node->analyzed) - node = cgraph_alias_aliased_node (node); - else if (node->thunk.thunk_p) - node = node->callees->callee; - else - return node; - if (node && availability) - { - enum availability a; - a = cgraph_function_body_availability (node); - if (a < *availability) - *availability = a; - } - } - if (availability) - *availability = AVAIL_NOT_AVAILABLE; - return NULL; + return dyn_cast <varpool_node> (symtab_alias_target ((symtab_node) n)); } /* Given NODE, walk the alias chain to return the function NODE is alias of. @@ -1274,27 +1260,13 @@ cgraph_function_node (struct cgraph_node *node, enum availability *availability) static inline struct cgraph_node * cgraph_function_or_thunk_node (struct cgraph_node *node, enum availability *availability) { - if (availability) - *availability = cgraph_function_body_availability (node); - while (node) - { - if (node->alias && node->analyzed) - node = cgraph_alias_aliased_node (node); - else - return node; - if (node && availability) - { - enum availability a; - a = cgraph_function_body_availability (node); - if (a < *availability) - *availability = a; - } - } - if (availability) + struct cgraph_node *n; + + n = dyn_cast <cgraph_node> (symtab_alias_ultimate_target ((symtab_node)node, availability)); + if (!n) *availability = AVAIL_NOT_AVAILABLE; - return NULL; + return n; } - /* Given NODE, walk the alias chain to return the function NODE is alias of. Do not walk through thunks. When AVAILABILITY is non-NULL, get minimal availability in the chain. */ @@ -1302,25 +1274,12 @@ cgraph_function_or_thunk_node (struct cgraph_node *node, enum availability *avai static inline struct varpool_node * varpool_variable_node (struct varpool_node *node, enum availability *availability) { - if (availability) - *availability = cgraph_variable_initializer_availability (node); - while (node) - { - if (node->alias && node->analyzed) - node = varpool_alias_aliased_node (node); - else - return node; - if (node && availability) - { - enum availability a; - a = cgraph_variable_initializer_availability (node); - if (a < *availability) - *availability = a; - } - } - if (availability) + struct varpool_node *n; + + n = dyn_cast <varpool_node> (symtab_alias_ultimate_target ((symtab_node)node, availability)); + if (!n) *availability = AVAIL_NOT_AVAILABLE; - return NULL; + return n; } /* Return true when the edge E represents a direct recursion. */ @@ -1355,7 +1314,7 @@ cgraph_mark_force_output_node (struct cgraph_node *node) } /* Return true when the symbol is real symbol, i.e. it is not inline clone - or extern function kept around just for inlining. */ + or abstract function kept for debug info purposes only. */ static inline bool symtab_real_symbol_p (symtab_node node) diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index a002c68..d82eb37 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -189,7 +189,8 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, new_node->next_nested = new_node->origin->nested; new_node->origin->nested = new_node; } - new_node->analyzed = n->analyzed; + new_node->symbol.analyzed = n->symbol.analyzed; + new_node->symbol.definition = n->symbol.definition; new_node->local = n->local; new_node->symbol.externally_visible = false; new_node->local.local = true; @@ -638,10 +639,11 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version, new_version = cgraph_create_node (new_decl); - new_version->analyzed = old_version->analyzed; + new_version->symbol.analyzed = old_version->symbol.analyzed; + new_version->symbol.definition = old_version->symbol.definition; new_version->local = old_version->local; new_version->symbol.externally_visible = false; - new_version->local.local = old_version->analyzed; + new_version->local.local = new_version->symbol.definition; new_version->global = old_version->global; new_version->rtl = old_version->rtl; new_version->count = old_version->count; @@ -791,7 +793,7 @@ cgraph_materialize_clone (struct cgraph_node *node) node->clone_of->clones = node->next_sibling_clone; node->next_sibling_clone = NULL; node->prev_sibling_clone = NULL; - if (!node->clone_of->analyzed && !node->clone_of->clones) + if (!node->clone_of->symbol.analyzed && !node->clone_of->clones) { cgraph_release_function_body (node->clone_of); cgraph_node_remove_callees (node->clone_of); @@ -874,7 +876,7 @@ cgraph_materialize_all_clones (void) } } FOR_EACH_FUNCTION (node) - if (!node->analyzed && node->callees) + if (!node->symbol.analyzed && node->callees) cgraph_node_remove_callees (node); if (cgraph_dump_file) fprintf (cgraph_dump_file, "Materialization Call site updates done.\n"); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 6ebf8d4..ca314a6 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -202,7 +202,7 @@ cgraph_node_set cgraph_new_nodes; static void expand_all_functions (void); static void mark_functions_to_output (void); static void expand_function (struct cgraph_node *); -static void cgraph_analyze_function (struct cgraph_node *); +static void analyze_function (struct cgraph_node *); static void handle_alias_pairs (void); FILE *cgraph_dump_file; @@ -309,8 +309,8 @@ cgraph_process_new_functions (void) cgraph but not on this function. */ gimple_register_cfg_hooks (); - if (!node->analyzed) - cgraph_analyze_function (node); + if (!node->symbol.analyzed) + analyze_function (node); push_cfun (DECL_STRUCT_FUNCTION (fndecl)); if ((cgraph_state == CGRAPH_STATE_IPA_SSA && !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl))) @@ -354,7 +354,7 @@ cgraph_process_new_functions (void) ??? It may make more sense to use one body for inlining and other body for expanding the function but this is difficult to do. */ -static void +void cgraph_reset_node (struct cgraph_node *node) { /* If node->process is set, then we have already begun whole-unit analysis. @@ -368,10 +368,11 @@ cgraph_reset_node (struct cgraph_node *node) memset (&node->local, 0, sizeof (node->local)); memset (&node->global, 0, sizeof (node->global)); memset (&node->rtl, 0, sizeof (node->rtl)); - node->analyzed = false; - node->local.finalized = false; + node->symbol.analyzed = false; + node->symbol.definition = false; cgraph_node_remove_callees (node); + ipa_remove_all_references (&node->symbol.ref_list); } /* Return true when there are references to NODE. */ @@ -401,14 +402,14 @@ cgraph_finalize_function (tree decl, bool nested) { struct cgraph_node *node = cgraph_get_create_node (decl); - if (node->local.finalized) + if (node->symbol.definition) { cgraph_reset_node (node); node->local.redefined_extern_inline = true; } notice_global_symbol (decl); - node->local.finalized = true; + node->symbol.definition = true; node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL; /* With -fkeep-inline-functions we are keeping all inline functions except @@ -488,7 +489,7 @@ cgraph_add_new_function (tree fndecl, bool lowered) analyzing and compilation. */ node = cgraph_get_create_node (fndecl); node->local.local = false; - node->local.finalized = true; + node->symbol.definition = true; node->symbol.force_output = true; if (!lowered && cgraph_state == CGRAPH_STATE_EXPANSION) { @@ -515,7 +516,8 @@ cgraph_add_new_function (tree fndecl, bool lowered) node = cgraph_create_node (fndecl); if (lowered) node->lowered = true; - cgraph_analyze_function (node); + node->symbol.definition = true; + analyze_function (node); push_cfun (DECL_STRUCT_FUNCTION (fndecl)); gimple_register_cfg_hooks (); bitmap_obstack_initialize (NULL); @@ -589,23 +591,23 @@ fixup_same_cpp_alias_visibility (symtab_node node, symtab_node target, tree alia /* Analyze the function scheduled to be output. */ static void -cgraph_analyze_function (struct cgraph_node *node) +analyze_function (struct cgraph_node *node) { tree decl = node->symbol.decl; location_t saved_loc = input_location; input_location = DECL_SOURCE_LOCATION (decl); - if (node->alias && node->thunk.alias) + if (node->symbol.alias && node->thunk.alias) { struct cgraph_node *tgt = cgraph_get_node (node->thunk.alias); struct cgraph_node *n; - for (n = tgt; n && n->alias; - n = n->analyzed ? cgraph_alias_aliased_node (n) : NULL) + for (n = tgt; n && n->symbol.alias; + n = n->symbol.analyzed ? cgraph_alias_target (n) : NULL) if (n == node) { error ("function %q+D part of alias cycle", node->symbol.decl); - node->alias = false; + node->symbol.alias = false; input_location = saved_loc; return; } @@ -622,7 +624,7 @@ cgraph_analyze_function (struct cgraph_node *node) } if (node->symbol.address_taken) - cgraph_mark_address_taken_node (cgraph_alias_aliased_node (node)); + cgraph_mark_address_taken_node (cgraph_alias_target (node)); } else if (node->thunk.thunk_p) { @@ -677,7 +679,7 @@ cgraph_analyze_function (struct cgraph_node *node) pop_cfun (); } - node->analyzed = true; + node->symbol.analyzed = true; input_location = saved_loc; } @@ -766,7 +768,7 @@ process_function_and_variable_attributes (struct cgraph_node *first, " attribute have effect only on public objects"); } if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)) - && (node->local.finalized && !node->alias)) + && (node->symbol.definition && !node->symbol.alias)) { warning_at (DECL_SOURCE_LOCATION (node->symbol.decl), OPT_Wattributes, "%<weakref%> attribute ignored" @@ -803,7 +805,7 @@ process_function_and_variable_attributes (struct cgraph_node *first, " attribute have effect only on public objects"); } if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)) - && vnode->finalized + && vnode->symbol.definition && DECL_INITIAL (decl)) { warning_at (DECL_SOURCE_LOCATION (vnode->symbol.decl), OPT_Wattributes, @@ -828,10 +830,10 @@ varpool_finalize_decl (tree decl) gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl)); - if (node->finalized) + if (node->symbol.definition) return; notice_global_symbol (decl); - node->finalized = true; + node->symbol.definition = true; if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl) /* Traditionally we do not eliminate static variables when not optimizing and when not doing toplevel reoder. */ @@ -855,36 +857,23 @@ varpool_finalize_decl (tree decl) /* Determine if a symbol NODE is finalized and needed. */ inline static bool -symbol_finalized_and_needed (symtab_node node) +symbol_defined_and_needed (symtab_node node) { if (cgraph_node *cnode = dyn_cast <cgraph_node> (node)) - return cnode->local.finalized + return cnode->symbol.definition && cgraph_decide_is_function_needed (cnode, cnode->symbol.decl); if (varpool_node *vnode = dyn_cast <varpool_node> (node)) - return vnode->finalized + return vnode->symbol.definition && !DECL_EXTERNAL (vnode->symbol.decl) && decide_is_variable_needed (vnode, vnode->symbol.decl); return false; } -/* Determine if a symbol NODE is finalized. */ - -inline static bool -symbol_finalized (symtab_node node) -{ - if (cgraph_node *cnode= dyn_cast <cgraph_node> (node)) - return cnode->local.finalized; - if (varpool_node *vnode = dyn_cast <varpool_node> (node)) - return vnode->finalized; - return false; -} - - /* Discover all functions and variables that are trivially needed, analyze them as well as all functions and variables referred by them */ static void -cgraph_analyze_functions (void) +analyze_functions (void) { /* Keep track of already processed nodes when called multiple times for intermodule optimization. */ @@ -914,7 +903,7 @@ cgraph_analyze_functions (void) node != (symtab_node)first_analyzed && node != (symtab_node)first_analyzed_var; node = node->symbol.next) { - if (symbol_finalized_and_needed (node)) + if (symbol_defined_and_needed (node)) { enqueue_node (node); if (!changed && cgraph_dump_file) @@ -942,7 +931,7 @@ cgraph_analyze_functions (void) node = first; first = (symtab_node)first->symbol.aux; cgraph_node *cnode = dyn_cast <cgraph_node> (node); - if (cnode && cnode->local.finalized) + if (cnode && cnode->symbol.definition) { struct cgraph_edge *edge; tree decl = cnode->symbol.decl; @@ -951,7 +940,7 @@ cgraph_analyze_functions (void) and later using weak alias attribute to kill its body. See gcc.c-torture/compile/20011119-1.c */ if (!DECL_STRUCT_FUNCTION (decl) - && (!cnode->alias || !cnode->thunk.alias) + && (!cnode->symbol.alias || !cnode->thunk.alias) && !cnode->thunk.thunk_p && !cnode->dispatcher_function) { @@ -960,11 +949,11 @@ cgraph_analyze_functions (void) continue; } - if (!cnode->analyzed) - cgraph_analyze_function (cnode); + if (!cnode->symbol.analyzed) + analyze_function (cnode); for (edge = cnode->callees; edge; edge = edge->next_callee) - if (edge->callee->local.finalized) + if (edge->callee->symbol.definition) enqueue_node ((symtab_node)edge->callee); /* If decl is a clone of an abstract function, @@ -981,7 +970,7 @@ cgraph_analyze_functions (void) else { varpool_node *vnode = dyn_cast <varpool_node> (node); - if (vnode && vnode->finalized) + if (vnode && vnode->symbol.definition) varpool_analyze_node (vnode); } @@ -994,7 +983,7 @@ cgraph_analyze_functions (void) enqueue_node (next); } for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++) - if (symbol_finalized (ref->referred)) + if (ref->referred->symbol.definition) enqueue_node (ref->referred); cgraph_process_new_functions (); } @@ -1026,15 +1015,15 @@ cgraph_analyze_functions (void) { tree decl = node->symbol.decl; - if (cnode->local.finalized && !gimple_has_body_p (decl) - && (!cnode->alias || !cnode->thunk.alias) + if (cnode->symbol.definition && !gimple_has_body_p (decl) + && (!cnode->symbol.alias || !cnode->thunk.alias) && !cnode->thunk.thunk_p) cgraph_reset_node (cnode); - gcc_assert (!cnode->local.finalized || cnode->thunk.thunk_p - || cnode->alias + gcc_assert (!cnode->symbol.definition || cnode->thunk.thunk_p + || cnode->symbol.alias || gimple_has_body_p (decl)); - gcc_assert (cnode->analyzed == cnode->local.finalized); + gcc_assert (cnode->symbol.analyzed == cnode->symbol.definition); } node->symbol.aux = NULL; } @@ -1071,13 +1060,13 @@ handle_alias_pairs (void) if (TREE_CODE (p->decl) == FUNCTION_DECL) { struct cgraph_node *anode = cgraph_get_create_node (p->decl); - anode->alias = true; + anode->symbol.alias = true; anode->thunk.alias = p->target; } else { struct varpool_node *anode = varpool_get_node (p->decl); - anode->alias = true; + anode->symbol.alias = true; anode->alias_of = p->target; } DECL_EXTERNAL (p->decl) = 1; @@ -1117,7 +1106,7 @@ handle_alias_pairs (void) && target_node && is_a <cgraph_node> (target_node)) { struct cgraph_node *src_node = cgraph_get_node (p->decl); - if (src_node && src_node->local.finalized) + if (src_node && src_node->symbol.definition) cgraph_reset_node (src_node); cgraph_create_function_alias (p->decl, target_node->symbol.decl); alias_pairs->unordered_remove (i); @@ -1165,9 +1154,9 @@ mark_functions_to_output (void) /* We need to output all local functions that are used and not always inlined, as well as those that are reachable from outside the current compilation unit. */ - if (node->analyzed + if (node->symbol.analyzed && !node->thunk.thunk_p - && !node->alias + && !node->symbol.alias && !node->global.inlined_to && !TREE_ASM_WRITTEN (decl) && !DECL_EXTERNAL (decl)) @@ -1179,7 +1168,7 @@ mark_functions_to_output (void) for (next = cgraph (node->symbol.same_comdat_group); next != node; next = cgraph (next->symbol.same_comdat_group)) - if (!next->thunk.thunk_p && !next->alias) + if (!next->thunk.thunk_p && !next->symbol.alias) next->process = 1; } } @@ -1199,7 +1188,7 @@ mark_functions_to_output (void) are inside partition, we can end up not removing the body since we no longer have analyzed node pointing to it. */ && !node->symbol.in_other_partition - && !node->alias + && !node->symbol.alias && !node->clones && !DECL_EXTERNAL (decl)) { @@ -1435,7 +1424,7 @@ assemble_thunk (struct cgraph_node *node) set_cfun (NULL); TREE_ASM_WRITTEN (thunk_fndecl) = 1; node->thunk.thunk_p = false; - node->analyzed = false; + node->symbol.analyzed = false; } else { @@ -1800,7 +1789,7 @@ output_in_order (void) FOR_EACH_DEFINED_FUNCTION (pf) { - if (pf->process && !pf->thunk.thunk_p && !pf->alias) + if (pf->process && !pf->thunk.thunk_p && !pf->symbol.alias) { i = pf->symbol.order; gcc_assert (nodes[i].kind == ORDER_UNDEFINED); @@ -1943,14 +1932,14 @@ output_weakrefs (void) struct cgraph_node *node; struct varpool_node *vnode; FOR_EACH_FUNCTION (node) - if (node->alias && DECL_EXTERNAL (node->symbol.decl) + if (node->symbol.alias && DECL_EXTERNAL (node->symbol.decl) && !TREE_ASM_WRITTEN (node->symbol.decl) && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl))) do_assemble_alias (node->symbol.decl, node->thunk.alias && DECL_P (node->thunk.alias) ? DECL_ASSEMBLER_NAME (node->thunk.alias) : get_alias_symbol (node->symbol.decl)); FOR_EACH_VARIABLE (vnode) - if (vnode->alias && DECL_EXTERNAL (vnode->symbol.decl) + if (vnode->symbol.alias && DECL_EXTERNAL (vnode->symbol.decl) && !TREE_ASM_WRITTEN (vnode->symbol.decl) && lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->symbol.decl))) do_assemble_alias (vnode->symbol.decl, @@ -2115,13 +2104,13 @@ finalize_compilation_unit (void) /* Gimplify and lower all functions, compute reachability and remove unreachable nodes. */ - cgraph_analyze_functions (); + analyze_functions (); /* Mark alias targets necessary and emit diagnostics. */ handle_alias_pairs (); /* Gimplify and lower thunks. */ - cgraph_analyze_functions (); + analyze_functions (); /* Finally drive the pass manager. */ compile (); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index a025909..9d05a7b 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -29468,7 +29468,7 @@ ix86_get_function_versions_dispatcher (void *decl) dispatcher_version_info = insert_new_cgraph_node_version (dispatcher_node); dispatcher_version_info->next = default_version_info; - dispatcher_node->local.finalized = 1; + dispatcher_node->symbol.definition = 1; /* Set the dispatcher for all the versions. */ it_v = default_version_info; @@ -29623,7 +29623,7 @@ ix86_generate_version_dispatcher_body (void *node_p) default_ver_decl = node_version_info->next->this_node->symbol.decl; /* node is going to be an alias, so remove the finalized bit. */ - node->local.finalized = false; + node->symbol.definition = false; resolver_decl = make_resolver_func (default_ver_decl, node->symbol.decl, &empty_bb); @@ -29817,6 +29817,9 @@ fold_builtin_cpu (tree fndecl, tree *args) tree __cpu_model_var = make_var_decl (__processor_model_type, "__cpu_model"); + + varpool_add_new_variable (__cpu_model_var); + gcc_assert ((args != NULL) && (*args != NULL)); param_string_cst = *args; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index ed1d479..ed26fa0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2013-05-29 Jan Hubicka <jh@suse.cz> + + * tree.c (cp_fix_function_decl_p): Update for new symtab flags. + * decl2.c )var_finalized_p, cp_write_global_declarations): Likewise. + 2013-05-25 Paolo Carlini <paolo.carlini@oracle.com> PR c++/25666 diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 8119210..409a743 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1803,7 +1803,7 @@ import_export_class (tree ctype) static bool var_finalized_p (tree var) { - return varpool_node_for_decl (var)->finalized; + return varpool_node_for_decl (var)->symbol.definition; } /* DECL is a VAR_DECL or FUNCTION_DECL which, for whatever reason, @@ -4202,7 +4202,7 @@ cp_write_global_declarations (void) node = cgraph_get_node (decl); if (node->same_body_alias) - node = cgraph_alias_aliased_node (node); + node = cgraph_alias_target (node); cgraph_for_node_and_aliases (node, clear_decl_external, NULL, true); @@ -4224,7 +4224,7 @@ cp_write_global_declarations (void) if (!DECL_EXTERNAL (decl) && decl_needed_p (decl) && !TREE_ASM_WRITTEN (decl) - && !cgraph_get_node (decl)->local.finalized) + && !cgraph_get_node (decl)->symbol.definition) { /* We will output the function; no longer consider it in this loop. */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 0fbb33d..8524f6c 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3980,7 +3980,7 @@ cp_fix_function_decl_p (tree decl) /* Don't fix same_body aliases. Although they don't have their own CFG, they share it with what they alias to. */ - if (!node || !node->alias + if (!node || !node->symbol.alias || !vec_safe_length (node->symbol.ref_list.references)) return true; } diff --git a/gcc/dbxout.c b/gcc/dbxout.c index 4d9fc4e..1cc5d52 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -2480,7 +2480,7 @@ dbxout_expand_expr (tree expr) return NULL, otherwise stabs might reference an undefined symbol. */ struct varpool_node *node = varpool_get_node (expr); - if (!node || !node->analyzed) + if (!node || !node->symbol.definition) return NULL; } /* FALLTHRU */ diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index e4a3c07..b615b18 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -14919,7 +14919,7 @@ reference_to_unused (tree * tp, int * walk_subtrees, else if (TREE_CODE (*tp) == VAR_DECL) { struct varpool_node *node = varpool_get_node (*tp); - if (!node || !node->analyzed) + if (!node || !node->symbol.definition) return *tp; } else if (TREE_CODE (*tp) == FUNCTION_DECL @@ -17597,7 +17597,7 @@ premark_types_used_by_global_vars_helper (void **slot, /* Ask cgraph if the global variable really is to be emitted. If yes, then we'll keep the DIE of ENTRY->TYPE. */ struct varpool_node *node = varpool_get_node (entry->var_decl); - if (node && node->analyzed) + if (node && node->symbol.definition) { die->die_perennial_p = 1; /* Keep the parent DIEs as well. */ diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 1de281a9..181d28d 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -114,7 +114,7 @@ can_refer_decl_in_current_unit_p (tree decl, tree from_decl) The second is important when devirtualization happens during final compilation stage when making a new reference no longer makes callee to be compiled. */ - if (!node || !node->analyzed || node->global.inlined_to) + if (!node || !node->symbol.definition || node->global.inlined_to) { gcc_checking_assert (!TREE_ASM_WRITTEN (decl)); return false; @@ -123,7 +123,7 @@ can_refer_decl_in_current_unit_p (tree decl, tree from_decl) else if (TREE_CODE (decl) == VAR_DECL) { vnode = varpool_get_node (decl); - if (!vnode || !vnode->analyzed) + if (!vnode || !vnode->symbol.definition) { gcc_checking_assert (!TREE_ASM_WRITTEN (decl)); return false; diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 4bb1754..af4e948 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -440,14 +440,14 @@ determine_versionability (struct cgraph_node *node) /* There are a number of generic reasons functions cannot be versioned. We also cannot remove parameters if there are type attributes such as fnspec present. */ - if (node->alias || node->thunk.thunk_p) + if (node->symbol.alias || node->thunk.thunk_p) reason = "alias or thunk"; else if (!node->local.versionable) reason = "not a tree_versionable_function"; else if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) reason = "insufficient body availability"; - if (reason && dump_file && !node->alias && !node->thunk.thunk_p) + if (reason && dump_file && !node->symbol.alias && !node->thunk.thunk_p) fprintf (dump_file, "Function %s/%i is not versionable, reason: %s.\n", cgraph_node_name (node), node->symbol.order, reason); @@ -727,7 +727,7 @@ initialize_node_lattices (struct cgraph_node *node) set_all_contains_variable (plats); } if (dump_file && (dump_flags & TDF_DETAILS) - && !node->alias && !node->thunk.thunk_p) + && !node->symbol.alias && !node->thunk.thunk_p) fprintf (dump_file, "Marking all lattices of %s/%i as %s\n", cgraph_node_name (node), node->symbol.order, disable ? "BOTTOM" : "VARIABLE"); @@ -1418,7 +1418,7 @@ propagate_constants_accross_call (struct cgraph_edge *cs) int i, args_count, parms_count; callee = cgraph_function_node (cs->callee, &availability); - if (!callee->analyzed) + if (!callee->symbol.definition) return false; gcc_checking_assert (cgraph_function_with_gimple_body_p (callee)); callee_info = IPA_NODE_REF (callee); @@ -1431,8 +1431,8 @@ propagate_constants_accross_call (struct cgraph_edge *cs) parameter. However, we might need to uncover a thunk from below a series of aliases first. */ alias_or_thunk = cs->callee; - while (alias_or_thunk->alias) - alias_or_thunk = cgraph_alias_aliased_node (alias_or_thunk); + while (alias_or_thunk->symbol.alias) + alias_or_thunk = cgraph_alias_target (alias_or_thunk); if (alias_or_thunk->thunk.thunk_p) { ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, @@ -1601,7 +1601,7 @@ devirtualization_time_bonus (struct cgraph_node *node, /* Only bare minimum benefit for clearly un-inlineable targets. */ res += 1; callee = cgraph_get_node (target); - if (!callee || !callee->analyzed) + if (!callee || !callee->symbol.definition) continue; isummary = inline_summary (callee); if (!isummary->inlinable) @@ -2231,9 +2231,10 @@ ipcp_propagate_stage (struct topo_info *topo) ipa_get_param_count (info)); initialize_node_lattices (node); } + if (node->symbol.definition && !node->symbol.alias) + overall_size += inline_summary (node)->self_size; if (node->count > max_count) max_count = node->count; - overall_size += inline_summary (node)->self_size; } max_new_size = overall_size; diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index c6f127e..a25f517 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -1351,7 +1351,7 @@ dump_inline_edge_summary (FILE *f, int indent, struct cgraph_node *node, void dump_inline_summary (FILE *f, struct cgraph_node *node) { - if (node->analyzed) + if (node->symbol.definition) { struct inline_summary *s = inline_summary (node); size_time_entry *e; @@ -1427,7 +1427,7 @@ initialize_inline_failed (struct cgraph_edge *e) if (e->indirect_unknown_callee) e->inline_failed = CIF_INDIRECT_UNKNOWN_CALL; - else if (!callee->analyzed) + else if (!callee->symbol.definition) e->inline_failed = CIF_BODY_NOT_AVAILABLE; else if (callee->local.redefined_extern_inline) e->inline_failed = CIF_REDEFINED_EXTERN_INLINE; @@ -2765,7 +2765,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie, gcc_checking_assert (*size >= 0); callee = cgraph_get_node (target); - if (!callee || !callee->analyzed) + if (!callee || !callee->symbol.definition) return false; isummary = inline_summary (callee); return isummary->inlinable; @@ -3683,7 +3683,7 @@ inline_generate_summary (void) inline_free_summary (); FOR_EACH_DEFINED_FUNCTION (node) - if (!node->alias) + if (!node->symbol.alias) inline_analyze_function (node); } @@ -3917,7 +3917,7 @@ inline_write_summary (void) { symtab_node snode = lto_symtab_encoder_deref (encoder, i); cgraph_node *cnode = dyn_cast <cgraph_node> (snode); - if (cnode && cnode->analyzed) + if (cnode && cnode->symbol.definition && !cnode->symbol.alias) count++; } streamer_write_uhwi (ob, count); @@ -3926,7 +3926,7 @@ inline_write_summary (void) { symtab_node snode = lto_symtab_encoder_deref (encoder, i); cgraph_node *cnode = dyn_cast <cgraph_node> (snode); - if (cnode && (node = cnode)->analyzed) + if (cnode && (node = cnode)->symbol.definition && !node->symbol.alias) { struct inline_summary *info = inline_summary (node); struct bitpack_d bp; diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c index cb819d7..9e131a4 100644 --- a/gcc/ipa-inline-transform.c +++ b/gcc/ipa-inline-transform.c @@ -153,7 +153,7 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, cgraph_remove_unreachable_functions gets rid of them. */ gcc_assert (!e->callee->global.inlined_to); symtab_dissolve_same_comdat_group_list ((symtab_node) e->callee); - if (e->callee->analyzed && !DECL_EXTERNAL (e->callee->symbol.decl)) + if (e->callee->symbol.definition && !DECL_EXTERNAL (e->callee->symbol.decl)) { if (overall_size) *overall_size -= inline_summary (e->callee)->size; @@ -236,7 +236,7 @@ inline_call (struct cgraph_edge *e, bool update_original, if (!alias->callers && can_remove_node_now_p (alias, e)) { - next_alias = cgraph_alias_aliased_node (alias); + next_alias = cgraph_alias_target (alias); cgraph_remove_node (alias); alias = next_alias; } @@ -381,7 +381,7 @@ static bool preserve_function_body_p (struct cgraph_node *node) { gcc_assert (cgraph_global_info_ready); - gcc_assert (!node->alias && !node->thunk.thunk_p); + gcc_assert (!node->symbol.alias && !node->thunk.thunk_p); /* Look if there is any clone around. */ if (node->clones) diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 35fce6d..a378c08 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -253,7 +253,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report) gcc_assert (e->inline_failed); - if (!callee || !callee->analyzed) + if (!callee || !callee->symbol.definition) { e->inline_failed = CIF_BODY_NOT_AVAILABLE; inlinable = false; @@ -1100,7 +1100,7 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node, int i; struct ipa_ref *ref; - if ((!node->alias && !inline_summary (node)->inlinable) + if ((!node->symbol.alias && !inline_summary (node)->inlinable) || cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE || node->global.inlined_to) return; @@ -1795,6 +1795,9 @@ ipa_inline (void) } inline_small_functions (); + + /* Do first after-inlining removal. We want to remove all "stale" extern inline + functions and virtual functions so we really know what is called once. */ symtab_remove_unreachable_nodes (false, dump_file); free (order); diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 7c3987e..8918c5b 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -1521,7 +1521,7 @@ ipa_compute_jump_functions (struct cgraph_node *node, NULL); /* We do not need to bother analyzing calls to unknown functions unless they may become known during lto/whopr. */ - if (!callee->analyzed && !flag_lto) + if (!callee->symbol.definition && !flag_lto) continue; ipa_compute_jump_functions_for_edge (parms_ainfo, cs); } @@ -2978,7 +2978,7 @@ ipa_print_node_params (FILE *f, struct cgraph_node *node) tree temp; struct ipa_node_params *info; - if (!node->analyzed) + if (!node->symbol.definition) return; info = IPA_NODE_REF (node); fprintf (f, " function %s/%i parameter descriptors:\n", @@ -3972,7 +3972,7 @@ ipa_prop_read_section (struct lto_file_decl_data *file_data, const char *data, index = streamer_read_uhwi (&ib_main); encoder = file_data->symtab_node_encoder; node = cgraph (lto_symtab_encoder_deref (encoder, index)); - gcc_assert (node->analyzed); + gcc_assert (node->symbol.definition); ipa_read_node_info (&ib_main, node, data_in); } lto_free_section_data (file_data, LTO_section_jump_functions, NULL, data, @@ -4016,8 +4016,7 @@ ipa_update_after_lto_read (void) ipa_check_create_edge_args (); FOR_EACH_DEFINED_FUNCTION (node) - if (node->analyzed) - ipa_initialize_node_params (node); + ipa_initialize_node_params (node); } void @@ -4154,7 +4153,7 @@ read_replacements_section (struct lto_file_decl_data *file_data, index = streamer_read_uhwi (&ib_main); encoder = file_data->symtab_node_encoder; node = cgraph (lto_symtab_encoder_deref (encoder, index)); - gcc_assert (node->analyzed); + gcc_assert (node->symbol.definition); read_agg_replacement_chain (&ib_main, node, data_in); } lto_free_section_data (file_data, LTO_section_jump_functions, NULL, data, diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index 0dd6838..c6c41c6 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -738,7 +738,7 @@ analyze_function (struct cgraph_node *fn, bool ipa) flags_from_decl_or_type (fn->symbol.decl), cgraph_node_cannot_return (fn)); - if (fn->thunk.thunk_p || fn->alias) + if (fn->thunk.thunk_p || fn->symbol.alias) { /* Thunk gets propagated through, so nothing interesting happens. */ gcc_assert (ipa); @@ -951,7 +951,7 @@ pure_const_write_summary (void) lsei_next_function_in_partition (&lsei)) { node = lsei_cgraph_node (lsei); - if (node->analyzed && has_function_state (node)) + if (node->symbol.definition && has_function_state (node)) count++; } @@ -962,7 +962,7 @@ pure_const_write_summary (void) lsei_next_function_in_partition (&lsei)) { node = lsei_cgraph_node (lsei); - if (node->analyzed && has_function_state (node)) + if (node->symbol.definition && has_function_state (node)) { struct bitpack_d bp; funct_state fs; @@ -1124,7 +1124,7 @@ propagate_pure_const (void) int count = 0; node = order[i]; - if (node->alias) + if (node->symbol.alias) continue; if (dump_file && (dump_flags & TDF_DETAILS)) @@ -1394,7 +1394,7 @@ propagate_nothrow (void) bool can_throw = false; node = order[i]; - if (node->alias) + if (node->symbol.alias) continue; /* Find the worst state for any node in the cycle. */ diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c index f3c483f..9c56b7f 100644 --- a/gcc/ipa-reference.c +++ b/gcc/ipa-reference.c @@ -684,7 +684,7 @@ propagate (void) || TREE_ADDRESSABLE (vnode->symbol.decl) || TREE_READONLY (vnode->symbol.decl) || !is_proper_for_analysis (vnode->symbol.decl) - || !vnode->analyzed) + || !vnode->symbol.definition) bitmap_clear_bit (all_module_statics, DECL_UID (vnode->symbol.decl)); /* Forget info we collected "just for fun" on variables that turned out to be @@ -716,7 +716,7 @@ propagate (void) bool write_all = false; node = order[i]; - if (node->alias) + if (node->symbol.alias) continue; node_info = get_reference_vars_info (node); @@ -794,7 +794,7 @@ propagate (void) struct cgraph_node *w; node = order[i]; - if (node->alias) + if (node->symbol.alias) continue; fprintf (dump_file, @@ -835,7 +835,7 @@ propagate (void) ipa_reference_optimization_summary_t opt; node_info = get_reference_vars_info (node); - if (!node->alias + if (!node->symbol.alias && (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE || (flags_from_decl_or_type (node->symbol.decl) & ECF_LEAF))) { @@ -894,7 +894,7 @@ write_node_summary_p (struct cgraph_node *node, ipa_reference_optimization_summary_t info; /* See if we have (non-empty) info. */ - if (!node->analyzed || node->global.inlined_to) + if (!node->symbol.definition || node->global.inlined_to) return false; info = get_reference_optimization_summary (node); if (!info || (bitmap_empty_p (info->statics_not_read) diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index 107c7a9..e786478 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -367,23 +367,46 @@ consider_split (struct split_point *current, bitmap non_ssa_vars, unsigned int i; int incoming_freq = 0; tree retval; + bool back_edge = false; if (dump_file && (dump_flags & TDF_DETAILS)) dump_split_point (dump_file, current); FOR_EACH_EDGE (e, ei, current->entry_bb->preds) - if (!bitmap_bit_p (current->split_bbs, e->src->index)) - incoming_freq += EDGE_FREQUENCY (e); + { + if (e->flags & EDGE_DFS_BACK) + back_edge = true; + if (!bitmap_bit_p (current->split_bbs, e->src->index)) + incoming_freq += EDGE_FREQUENCY (e); + } /* Do not split when we would end up calling function anyway. */ if (incoming_freq >= (ENTRY_BLOCK_PTR->frequency * PARAM_VALUE (PARAM_PARTIAL_INLINING_ENTRY_PROBABILITY) / 100)) { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, - " Refused: incoming frequency is too large.\n"); - return; + /* When profile is guessed, we can not expect it to give us + realistic estimate on likelyness of function taking the + complex path. As a special case, when tail of the function is + a loop, enable splitting since inlining code skipping the loop + is likely noticeable win. */ + if (back_edge + && profile_status != PROFILE_READ + && incoming_freq < ENTRY_BLOCK_PTR->frequency) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, + " Split before loop, accepting despite low frequencies %i %i.\n", + incoming_freq, + ENTRY_BLOCK_PTR->frequency); + } + else + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, + " Refused: incoming frequency is too large.\n"); + return; + } } if (!current->header_size) @@ -1533,6 +1556,11 @@ execute_split_functions (void) return 0; } + /* We enforce splitting after loop headers when profile info is not + available. */ + if (profile_status != PROFILE_READ) + mark_dfs_back_edges (); + /* Initialize bitmap to track forbidden calls. */ forbidden_dominators = BITMAP_ALLOC (NULL); calculate_dominance_info (CDI_DOMINATORS); diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c index cef67de..00e6528 100644 --- a/gcc/ipa-utils.c +++ b/gcc/ipa-utils.c @@ -287,7 +287,7 @@ ipa_reverse_postorder (struct cgraph_node **order) && (pass || (!node->symbol.address_taken && !node->global.inlined_to - && !node->alias && !node->thunk.thunk_p + && !node->symbol.alias && !node->thunk.thunk_p && !cgraph_only_called_directly_p (node)))) { stack_size = 0; @@ -39,6 +39,53 @@ along with GCC; see the file COPYING3. If not see #include "lto-streamer.h" #include "data-streamer.h" +/* Return true when NODE can not be local. Worker for cgraph_local_node_p. */ + +static bool +cgraph_non_local_node_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) +{ + /* FIXME: Aliases can be local, but i386 gets thunks wrong then. */ + return !(cgraph_only_called_directly_or_aliased_p (node) + && !ipa_ref_has_aliases_p (&node->symbol.ref_list) + && node->symbol.definition + && !DECL_EXTERNAL (node->symbol.decl) + && !node->symbol.externally_visible + && !node->symbol.used_from_other_partition + && !node->symbol.in_other_partition); +} + +/* Return true when function can be marked local. */ + +static bool +cgraph_local_node_p (struct cgraph_node *node) +{ + struct cgraph_node *n = cgraph_function_or_thunk_node (node, NULL); + + /* FIXME: thunks can be considered local, but we need prevent i386 + from attempting to change calling convention of them. */ + if (n->thunk.thunk_p) + return false; + return !cgraph_for_node_and_aliases (n, + cgraph_non_local_node_p_1, NULL, true); + +} + +/* Return true when NODE has ADDR reference. */ + +static bool +has_addr_references_p (struct cgraph_node *node, + void *data ATTRIBUTE_UNUSED) +{ + int i; + struct ipa_ref *ref; + + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, + i, ref); i++) + if (ref->use == IPA_REF_ADDR) + return true; + return false; +} + /* Look for all functions inlined to NODE and update their inlined_to pointers to INLINED_TO. */ @@ -89,79 +136,23 @@ process_references (struct ipa_ref_list *list, struct ipa_ref *ref; for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++) { - if (is_a <cgraph_node> (ref->referred)) - { - struct cgraph_node *node = ipa_ref_node (ref); - - if (node->analyzed - && (!DECL_EXTERNAL (node->symbol.decl) - || node->alias - || before_inlining_p)) - pointer_set_insert (reachable, node); - enqueue_node ((symtab_node) node, first, reachable); - } - else - { - struct varpool_node *node = ipa_ref_varpool_node (ref); - - if (node->analyzed - && (!DECL_EXTERNAL (node->symbol.decl) - || node->alias - || before_inlining_p)) - pointer_set_insert (reachable, node); - enqueue_node ((symtab_node) node, first, reachable); - } + symtab_node node = ref->referred; + + if (node->symbol.definition + && (!DECL_EXTERNAL (node->symbol.decl) + || node->symbol.alias + || (before_inlining_p + /* We use variable constructors during late complation for + constant folding. Keep references alive so partitioning + knows about potential references. */ + || (TREE_CODE (node->symbol.decl) == VAR_DECL + && flag_wpa && const_value_known_p (node->symbol.decl))))) + pointer_set_insert (reachable, node); + enqueue_node ((symtab_node) node, first, reachable); } } -/* Return true when NODE can not be local. Worker for cgraph_local_node_p. */ - -static bool -cgraph_non_local_node_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) -{ - /* FIXME: Aliases can be local, but i386 gets thunks wrong then. */ - return !(cgraph_only_called_directly_or_aliased_p (node) - && !ipa_ref_has_aliases_p (&node->symbol.ref_list) - && node->analyzed - && !DECL_EXTERNAL (node->symbol.decl) - && !node->symbol.externally_visible - && !node->symbol.used_from_other_partition - && !node->symbol.in_other_partition); -} - -/* Return true when function can be marked local. */ - -static bool -cgraph_local_node_p (struct cgraph_node *node) -{ - struct cgraph_node *n = cgraph_function_or_thunk_node (node, NULL); - - /* FIXME: thunks can be considered local, but we need prevent i386 - from attempting to change calling convention of them. */ - if (n->thunk.thunk_p) - return false; - return !cgraph_for_node_and_aliases (n, - cgraph_non_local_node_p_1, NULL, true); - -} - -/* Return true when NODE has ADDR reference. */ - -static bool -has_addr_references_p (struct cgraph_node *node, - void *data ATTRIBUTE_UNUSED) -{ - int i; - struct ipa_ref *ref; - - for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, - i, ref); i++) - if (ref->use == IPA_REF_ADDR) - return true; - return false; -} - /* Perform reachability analysis and reclaim all unreachable nodes. The algorithm is basically mark&sweep but with some extra refinements: @@ -303,10 +294,10 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) struct cgraph_edge *e; for (e = cnode->callees; e; e = e->next_callee) { - if (e->callee->analyzed + if (e->callee->symbol.definition && (!e->inline_failed || !DECL_EXTERNAL (e->callee->symbol.decl) - || cnode->alias + || cnode->symbol.alias || before_inlining_p)) pointer_set_insert (reachable, e->callee); enqueue_node ((symtab_node) e->callee, &first, reachable); @@ -314,7 +305,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) /* When inline clone exists, mark body to be preserved so when removing offline copy of the function we don't kill it. */ - if (!cnode->alias && cnode->global.inlined_to) + if (!cnode->symbol.alias && cnode->global.inlined_to) pointer_set_insert (body_needed_for_clonning, cnode->symbol.decl); } @@ -339,7 +330,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) varpool_node *vnode = dyn_cast <varpool_node> (node); if (vnode && DECL_EXTERNAL (node->symbol.decl) - && !vnode->alias + && !vnode->symbol.alias && in_boundary_p) { struct ipa_ref *ref; @@ -352,6 +343,8 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) for (node = cgraph_first_function (); node; node = next) { next = cgraph_next_function (node); + + /* If node is not needed at all, remove it. */ if (!node->symbol.aux) { if (file) @@ -359,20 +352,18 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) cgraph_remove_node (node); changed = true; } + /* If node is unreachable, remove its body. */ else if (!pointer_set_contains (reachable, node)) { - if (node->analyzed) + if (!pointer_set_contains (body_needed_for_clonning, node->symbol.decl)) + cgraph_release_function_body (node); + if (node->symbol.definition) { if (file) fprintf (file, " %s", cgraph_node_name (node)); - cgraph_node_remove_callees (node); - ipa_remove_all_references (&node->symbol.ref_list); + cgraph_reset_node (node); changed = true; } - if (!pointer_set_contains (body_needed_for_clonning, node->symbol.decl) - && (node->local.finalized || !DECL_ARTIFICIAL (node->symbol.decl))) - cgraph_release_function_body (node); - node->analyzed = false; } } @@ -406,14 +397,20 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) } else if (!pointer_set_contains (reachable, vnode)) { - if (vnode->analyzed) + if (vnode->symbol.definition) { if (file) fprintf (file, " %s", varpool_node_name (vnode)); changed = true; } - vnode->analyzed = false; + vnode->symbol.definition = false; + vnode->symbol.analyzed = false; vnode->symbol.aux = NULL; + + /* Keep body if it may be useful for constant folding. */ + if (!const_value_known_p (vnode->symbol.decl)) + varpool_remove_initializer (vnode); + ipa_remove_all_references (&vnode->symbol.ref_list); } else vnode->symbol.aux = NULL; @@ -474,7 +471,7 @@ ipa_discover_readonly_nonaddressable_vars (void) if (dump_file) fprintf (dump_file, "Clearing variable flags:"); FOR_EACH_VARIABLE (vnode) - if (vnode->finalized && varpool_all_refs_explicit_p (vnode) + if (vnode->symbol.definition && varpool_all_refs_explicit_p (vnode) && (TREE_ADDRESSABLE (vnode->symbol.decl) || !TREE_READONLY (vnode->symbol.decl))) { @@ -546,12 +543,12 @@ cgraph_address_taken_from_non_vtable_p (struct cgraph_node *node) Virtual functions do have their addresses taken from the vtables, but in C++ there is no way to compare their addresses for equality. */ -bool +static bool cgraph_comdat_can_be_unshared_p (struct cgraph_node *node) { if ((cgraph_address_taken_from_non_vtable_p (node) && !DECL_VIRTUAL_P (node->symbol.decl)) - || !node->analyzed) + || !node->symbol.definition) return false; if (node->symbol.same_comdat_group) { @@ -575,7 +572,7 @@ static bool cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program) { - if (!node->local.finalized) + if (!node->symbol.definition) return false; if (!DECL_COMDAT (node->symbol.decl) && (!TREE_PUBLIC (node->symbol.decl) @@ -619,7 +616,7 @@ cgraph_externally_visible_p (struct cgraph_node *node, || DECL_VISIBILITY (node->symbol.decl) == VISIBILITY_INTERNAL) /* Be sure that node is defined in IR file, not in other object file. In that case we don't set used_from_other_object_file. */ - && node->analyzed) + && node->symbol.definition) ; else if (!whole_program) return true; @@ -638,7 +635,7 @@ varpool_externally_visible_p (struct varpool_node *vnode) /* Do not touch weakrefs; while they are not externally visible, dropping their DECL_EXTERNAL flags confuse most of code handling them. */ - if (vnode->alias && DECL_EXTERNAL (vnode->symbol.decl)) + if (vnode->symbol.alias && DECL_EXTERNAL (vnode->symbol.decl)) return true; if (DECL_EXTERNAL (vnode->symbol.decl)) @@ -690,7 +687,7 @@ varpool_externally_visible_p (struct varpool_node *vnode) || DECL_VISIBILITY (vnode->symbol.decl) == VISIBILITY_INTERNAL) /* Be sure that node is defined in IR file, not in other object file. In that case we don't set used_from_other_object_file. */ - && vnode->finalized) + && vnode->symbol.definition) ; else if (!flag_whole_program) return true; @@ -744,7 +741,7 @@ function_and_variable_visibility (bool whole_program) We may end up marking as node external nodes where this flag is meaningless strip it. */ if (node->symbol.force_output - && (DECL_EXTERNAL (node->symbol.decl) || !node->analyzed)) + && (DECL_EXTERNAL (node->symbol.decl) || !node->symbol.definition)) node->symbol.force_output = 0; /* C++ FE on lack of COMDAT support create local COMDAT functions @@ -781,7 +778,7 @@ function_and_variable_visibility (bool whole_program) } else node->symbol.externally_visible = false; - if (!node->symbol.externally_visible && node->analyzed + if (!node->symbol.externally_visible && node->symbol.definition && !DECL_EXTERNAL (node->symbol.decl)) { gcc_assert (whole_program || in_lto_p @@ -854,7 +851,7 @@ function_and_variable_visibility (bool whole_program) } FOR_EACH_DEFINED_VARIABLE (vnode) { - if (!vnode->finalized) + if (!vnode->symbol.definition) continue; if (varpool_externally_visible_p (vnode)) vnode->symbol.externally_visible = true; diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 2857b06..82cc49f 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,7 @@ +2013-05-29 Jan Hubicka <jh@suse.cz> + + * decl.c (java_mark_decl_local): Update for new symtab flags. + 2013-05-22 Matthias Klose <doko@ubuntu.com> * jvspec.c (jvgenmain_spec): Add %I to cc1 call. diff --git a/gcc/java/decl.c b/gcc/java/decl.c index 566435f..c5a654d 100644 --- a/gcc/java/decl.c +++ b/gcc/java/decl.c @@ -1904,7 +1904,7 @@ java_mark_decl_local (tree decl) if (TREE_CODE (decl) == FUNCTION_DECL) { struct cgraph_node *node = cgraph_get_node (decl); - gcc_assert (!node || !node->local.finalized); + gcc_assert (!node || !node->symbol.definition); } #endif gcc_assert (!DECL_RTL_SET_P (decl)); diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 34188cb..2268f24 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -320,7 +320,7 @@ bool reachable_from_other_partition_p (struct cgraph_node *node, lto_symtab_encoder_t encoder) { struct cgraph_edge *e; - if (!node->analyzed) + if (!node->symbol.definition) return false; if (node->global.inlined_to) return false; @@ -380,7 +380,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, boundary_p = !lto_symtab_encoder_in_partition_p (encoder, (symtab_node)node); - if (node->analyzed && !boundary_p) + if (node->symbol.analyzed && !boundary_p) tag = LTO_symtab_analyzed_node; else tag = LTO_symtab_unavail_node; @@ -399,7 +399,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, Cherry-picked nodes: These are nodes we pulled from other translation units into SET during IPA-inlining. We make them as local static nodes to prevent clashes with other local statics. */ - if (boundary_p && node->analyzed && !DECL_EXTERNAL (node->symbol.decl)) + if (boundary_p && node->symbol.analyzed && !DECL_EXTERNAL (node->symbol.decl)) { /* Inline clones can not be part of boundary. gcc_assert (!node->global.inlined_to); @@ -463,7 +463,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, bp = bitpack_create (ob->main_stream); bp_pack_value (&bp, node->local.local, 1); bp_pack_value (&bp, node->symbol.externally_visible, 1); - bp_pack_value (&bp, node->local.finalized, 1); + bp_pack_value (&bp, node->symbol.definition, 1); bp_pack_value (&bp, node->local.versionable, 1); bp_pack_value (&bp, node->local.can_change_signature, 1); bp_pack_value (&bp, node->local.redefined_extern_inline, 1); @@ -485,7 +485,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, defined in other unit, we may use the info on aliases to resolve symbol1 != symbol2 type tests that we can do only for locally defined objects otherwise. */ - bp_pack_value (&bp, node->alias && (!boundary_p || DECL_EXTERNAL (node->symbol.decl)), 1); + bp_pack_value (&bp, node->symbol.alias && (!boundary_p || DECL_EXTERNAL (node->symbol.decl)), 1); bp_pack_value (&bp, node->frequency, 2); bp_pack_value (&bp, node->only_called_at_startup, 1); bp_pack_value (&bp, node->only_called_at_exit, 1); @@ -504,8 +504,8 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, streamer_write_uhwi_stream (ob->main_stream, node->thunk.fixed_offset); streamer_write_uhwi_stream (ob->main_stream, node->thunk.virtual_value); } - if ((node->alias || node->thunk.thunk_p) - && (!boundary_p || (node->alias && DECL_EXTERNAL (node->symbol.decl)))) + if ((node->symbol.alias || node->thunk.thunk_p) + && (!boundary_p || (node->symbol.alias && DECL_EXTERNAL (node->symbol.decl)))) { streamer_write_hwi_in_range (ob->main_stream, 0, 1, node->thunk.alias != NULL); @@ -522,7 +522,7 @@ static void lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node *node, lto_symtab_encoder_t encoder) { - bool boundary_p = (node->analyzed + bool boundary_p = (node->symbol.definition && !lto_symtab_encoder_in_partition_p (encoder, (symtab_node)node)); struct bitpack_d bp; int ref; @@ -535,10 +535,10 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node bp_pack_value (&bp, node->symbol.externally_visible, 1); bp_pack_value (&bp, node->symbol.force_output, 1); bp_pack_value (&bp, node->symbol.unique_name, 1); - bp_pack_value (&bp, node->finalized, 1); - bp_pack_value (&bp, node->alias, 1); + bp_pack_value (&bp, node->symbol.definition, 1); + bp_pack_value (&bp, node->symbol.alias, 1); bp_pack_value (&bp, node->alias_of != NULL, 1); - gcc_assert (node->finalized || !node->analyzed); + gcc_assert (node->symbol.definition || !node->symbol.analyzed); /* Constant pool initializers can be de-unified into individual ltrans units. FIXME: Alternatively at -Os we may want to avoid generating for them the local labels and share them across LTRANS partitions. */ @@ -551,7 +551,7 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node } else { - bp_pack_value (&bp, node->analyzed + bp_pack_value (&bp, node->symbol.definition && referenced_from_other_partition_p (&node->symbol.ref_list, encoder), 1); bp_pack_value (&bp, boundary_p && !DECL_EXTERNAL (node->symbol.decl), 1); @@ -756,7 +756,7 @@ compute_ltrans_boundary (lto_symtab_encoder_t in_encoder) !lsei_end_p (lsei); lsei_next_variable_in_partition (&lsei)) { struct varpool_node *vnode = lsei_varpool_node (lsei); - gcc_assert (!vnode->alias || vnode->alias_of); + gcc_assert (!vnode->symbol.alias || vnode->alias_of); lto_set_symtab_encoder_in_partition (encoder, (symtab_node)vnode); lto_set_symtab_encoder_encode_initializer (encoder, vnode); add_references (encoder, &vnode->symbol.ref_list); @@ -883,7 +883,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data, node->local.local = bp_unpack_value (bp, 1); node->symbol.externally_visible = bp_unpack_value (bp, 1); - node->local.finalized = bp_unpack_value (bp, 1); + node->symbol.definition = bp_unpack_value (bp, 1); node->local.versionable = bp_unpack_value (bp, 1); node->local.can_change_signature = bp_unpack_value (bp, 1); node->local.redefined_extern_inline = bp_unpack_value (bp, 1); @@ -893,7 +893,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data, node->abstract_and_needed = bp_unpack_value (bp, 1); node->symbol.used_from_other_partition = bp_unpack_value (bp, 1); node->lowered = bp_unpack_value (bp, 1); - node->analyzed = tag == LTO_symtab_analyzed_node; + node->symbol.analyzed = tag == LTO_symtab_analyzed_node; node->symbol.in_other_partition = bp_unpack_value (bp, 1); if (node->symbol.in_other_partition /* Avoid updating decl when we are seeing just inline clone. @@ -909,7 +909,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data, DECL_EXTERNAL (node->symbol.decl) = 1; TREE_STATIC (node->symbol.decl) = 0; } - node->alias = bp_unpack_value (bp, 1); + node->symbol.alias = bp_unpack_value (bp, 1); node->frequency = (enum node_frequency)bp_unpack_value (bp, 2); node->only_called_at_startup = bp_unpack_value (bp, 1); node->only_called_at_exit = bp_unpack_value (bp, 1); @@ -1004,7 +1004,7 @@ input_node (struct lto_file_decl_data *file_data, node->thunk.virtual_value = virtual_value; node->thunk.virtual_offset_p = (type & 4); } - if (node->thunk.thunk_p || node->alias) + if (node->thunk.thunk_p || node->symbol.alias) { if (streamer_read_hwi_in_range (ib, "alias nonzero flag", 0, 1)) { @@ -1044,12 +1044,12 @@ input_varpool_node (struct lto_file_decl_data *file_data, node->symbol.externally_visible = bp_unpack_value (&bp, 1); node->symbol.force_output = bp_unpack_value (&bp, 1); node->symbol.unique_name = bp_unpack_value (&bp, 1); - node->finalized = bp_unpack_value (&bp, 1); - node->alias = bp_unpack_value (&bp, 1); + node->symbol.definition = bp_unpack_value (&bp, 1); + node->symbol.alias = bp_unpack_value (&bp, 1); non_null_aliasof = bp_unpack_value (&bp, 1); node->symbol.used_from_other_partition = bp_unpack_value (&bp, 1); node->symbol.in_other_partition = bp_unpack_value (&bp, 1); - node->analyzed = (node->finalized && (!node->alias || !node->symbol.in_other_partition)); + node->symbol.analyzed = (node->symbol.definition && (!node->symbol.alias || !node->symbol.in_other_partition)); if (node->symbol.in_other_partition) { DECL_EXTERNAL (node->symbol.decl) = 1; diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index dfaf280..5e1a332 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -1013,7 +1013,7 @@ lto_output (void) cgraph_node *node = dyn_cast <cgraph_node> (snode); if (node && lto_symtab_encoder_encode_body_p (encoder, node) - && !node->alias + && !node->symbol.alias && !node->thunk.thunk_p) { #ifdef ENABLE_CHECKING @@ -1243,10 +1243,10 @@ write_symbol (struct streamer_tree_cache_d *cache, /* When something is defined, it should have node attached. */ gcc_assert (alias || TREE_CODE (t) != VAR_DECL - || varpool_get_node (t)->finalized); + || varpool_get_node (t)->symbol.definition); gcc_assert (alias || TREE_CODE (t) != FUNCTION_DECL || (cgraph_get_node (t) - && cgraph_get_node (t)->analyzed)); + && cgraph_get_node (t)->symbol.definition)); } /* Imitate what default_elf_asm_output_external do. diff --git a/gcc/lto-symtab.c b/gcc/lto-symtab.c index 8091d36..6c433f4 100644 --- a/gcc/lto-symtab.c +++ b/gcc/lto-symtab.c @@ -91,8 +91,8 @@ static void lto_varpool_replace_node (struct varpool_node *vnode, struct varpool_node *prevailing_node) { - gcc_assert (!vnode->finalized || prevailing_node->finalized); - gcc_assert (!vnode->analyzed || prevailing_node->analyzed); + gcc_assert (!vnode->symbol.definition || prevailing_node->symbol.definition); + gcc_assert (!vnode->symbol.analyzed || prevailing_node->symbol.analyzed); ipa_clone_referring ((symtab_node)prevailing_node, &vnode->symbol.ref_list); @@ -255,14 +255,7 @@ lto_symtab_resolve_can_prevail_p (symtab_node e) if (DECL_EXTERNAL (e->symbol.decl)) return false; - /* For functions we need a non-discarded body. */ - if (TREE_CODE (e->symbol.decl) == FUNCTION_DECL) - return (cgraph (e)->analyzed); - - else if (TREE_CODE (e->symbol.decl) == VAR_DECL) - return varpool (e)->finalized; - - gcc_unreachable (); + return e->symbol.definition; } /* Resolve the symbol with the candidates in the chain *SLOT and store @@ -594,33 +587,33 @@ lto_symtab_merge_cgraph_nodes (void) FOR_EACH_FUNCTION (cnode) { /* Resolve weakrefs to symbol defined in other unit. */ - if (!cnode->analyzed && cnode->thunk.alias && !DECL_P (cnode->thunk.alias)) + if (!cnode->symbol.analyzed && cnode->thunk.alias && !DECL_P (cnode->thunk.alias)) { symtab_node node = symtab_node_for_asm (cnode->thunk.alias); if (node && is_a <cgraph_node> (node)) { struct cgraph_node *n; - for (n = cgraph (node); n && n->alias; - n = n->analyzed ? cgraph_alias_aliased_node (n) : NULL) + for (n = cgraph (node); n && n->symbol.alias; + n = n->symbol.analyzed ? cgraph_alias_target (n) : NULL) if (n == cnode) { error ("function %q+D part of alias cycle", cnode->symbol.decl); - cnode->alias = false; + cnode->symbol.alias = false; break; } - if (cnode->alias) + if (cnode->symbol.alias) { cgraph_create_function_alias (cnode->symbol.decl, node->symbol.decl); ipa_record_reference ((symtab_node)cnode, (symtab_node)node, IPA_REF_ALIAS, NULL); - cnode->analyzed = true; + cnode->symbol.analyzed = true; } } else if (node) error ("%q+D alias in between function and variable is not supported", cnode->symbol.decl); } - if ((cnode->thunk.thunk_p || cnode->alias) + if ((cnode->thunk.thunk_p || cnode->symbol.alias) && cnode->thunk.alias && DECL_P (cnode->thunk.alias)) cnode->thunk.alias = lto_symtab_prevailing_decl (cnode->thunk.alias); cnode->symbol.aux = NULL; @@ -628,33 +621,33 @@ lto_symtab_merge_cgraph_nodes (void) FOR_EACH_VARIABLE (vnode) { /* Resolve weakrefs to symbol defined in other unit. */ - if (!vnode->analyzed && vnode->alias_of && !DECL_P (vnode->alias_of)) + if (!vnode->symbol.analyzed && vnode->alias_of && !DECL_P (vnode->alias_of)) { symtab_node node = symtab_node_for_asm (vnode->alias_of); if (node && is_a <cgraph_node> (node)) { struct varpool_node *n; - for (n = varpool (node); n && n->alias; - n = n->analyzed ? varpool_alias_aliased_node (n) : NULL) + for (n = varpool (node); n && n->symbol.alias; + n = n->symbol.analyzed ? varpool_alias_target (n) : NULL) if (n == vnode) { error ("function %q+D part of alias cycle", vnode->symbol.decl); - vnode->alias = false; + vnode->symbol.alias = false; break; } - if (vnode->alias) + if (vnode->symbol.alias) { varpool_create_variable_alias (vnode->symbol.decl, node->symbol.decl); ipa_record_reference ((symtab_node)vnode, (symtab_node)node, IPA_REF_ALIAS, NULL); - vnode->analyzed = true; + vnode->symbol.analyzed = true; } } else if (node) error ("%q+D alias in between function and variable is not supported", vnode->symbol.decl); } - if (vnode->alias_of) + if (vnode->symbol.alias && DECL_P (vnode->alias_of)) vnode->alias_of = lto_symtab_prevailing_decl (vnode->alias_of); vnode->symbol.aux = NULL; } diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 3ea106b..ded1056 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,9 @@ +2013-05-29 Jan Hubicka <jh@suse.cz> + + * lto.c (has_analyzed_clone_p, lto_materialize_function): Update for new symtab + flags. + * lto-partition.c (get_symbol_class, lto_balanced_map): Likewise. + 2013-05-15 Jan Hubicka <jh@suse.cz> * lto-partition.c (privatize_symbol_name): Return true when diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c index 62341c1..921b4e2 100644 --- a/gcc/lto/lto-partition.c +++ b/gcc/lto/lto-partition.c @@ -74,13 +74,13 @@ get_symbol_class (symtab_node node) objects that can not be duplicated across partitions. */ if (DECL_IN_CONSTANT_POOL (node->symbol.decl)) return SYMBOL_DUPLICATE; - gcc_checking_assert (vnode->analyzed); + gcc_checking_assert (vnode->symbol.definition); } /* Functions that are cloned may stay in callgraph even if they are unused. Handle them as external; compute_ltrans_boundary take care to make proper things to happen (i.e. to make them appear in the boundary but with body streamed, so clone can me materialized). */ - else if (!cgraph (node)->analyzed) + else if (!cgraph (node)->symbol.definition) return SYMBOL_EXTERNAL; /* Comdats are duplicated to every use unless they are keyed. @@ -561,12 +561,12 @@ lto_balanced_map (void) last_visited_node++; - gcc_assert (node->analyzed + gcc_assert (node->symbol.definition || lookup_attribute ("weakref", DECL_ATTRIBUTES (node->symbol.decl))); /* Compute boundary cost of callgraph edges. */ for (edge = node->callees; edge; edge = edge->next_callee) - if (edge->callee->analyzed) + if (edge->callee->symbol.definition) { int edge_cost = edge->frequency; int index; @@ -587,7 +587,7 @@ lto_balanced_map (void) int edge_cost = edge->frequency; int index; - gcc_assert (edge->caller->analyzed); + gcc_assert (edge->caller->symbol.definition); if (!edge_cost) edge_cost = 1; gcc_assert (edge_cost > 0); @@ -614,7 +614,7 @@ lto_balanced_map (void) int index; vnode = ipa_ref_varpool_node (ref); - if (!vnode->finalized) + if (!vnode->symbol.definition) continue; if (!symbol_partitioned_p ((symtab_node) vnode) && flag_toplevel_reorder && get_symbol_class ((symtab_node) vnode) == SYMBOL_PARTITION) @@ -632,7 +632,7 @@ lto_balanced_map (void) int index; node = ipa_ref_node (ref); - if (!node->analyzed) + if (!node->symbol.definition) continue; index = lto_symtab_encoder_lookup (partition->encoder, (symtab_node)node); @@ -648,7 +648,7 @@ lto_balanced_map (void) int index; vnode = ipa_ref_referring_varpool_node (ref); - gcc_assert (vnode->finalized); + gcc_assert (vnode->symbol.definition); if (!symbol_partitioned_p ((symtab_node) vnode) && flag_toplevel_reorder && get_symbol_class ((symtab_node) vnode) == SYMBOL_PARTITION) add_symbol_to_partition (partition, (symtab_node) vnode); @@ -665,7 +665,7 @@ lto_balanced_map (void) int index; node = ipa_ref_referring_node (ref); - gcc_assert (node->analyzed); + gcc_assert (node->symbol.definition); index = lto_symtab_encoder_lookup (partition->encoder, (symtab_node)node); if (index != LCC_NOT_FOUND diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 0943335..f2a59d3 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -166,7 +166,7 @@ has_analyzed_clone_p (struct cgraph_node *node) if (node) while (node != orig) { - if (node->analyzed) + if (node->symbol.analyzed) return true; if (node->clones) node = node->clones; @@ -196,7 +196,8 @@ lto_materialize_function (struct cgraph_node *node) decl = node->symbol.decl; /* Read in functions with body (analyzed nodes) and also functions that are needed to produce virtual clones. */ - if (cgraph_function_with_gimple_body_p (node) || has_analyzed_clone_p (node)) + if ((cgraph_function_with_gimple_body_p (node) && node->symbol.analyzed) + || has_analyzed_clone_p (node)) { /* Clones don't need to be read. */ if (node->clone_of) diff --git a/gcc/passes.c b/gcc/passes.c index eccf0b5..656cf71 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -2492,12 +2492,12 @@ ipa_write_summaries (void) renumber_gimple_stmt_uids (); pop_cfun (); } - if (node->analyzed) + if (node->symbol.definition) lto_set_symtab_encoder_in_partition (encoder, (symtab_node)node); } FOR_EACH_DEFINED_VARIABLE (vnode) - if ((!vnode->alias || vnode->alias_of)) + if ((!vnode->symbol.alias || vnode->alias_of)) lto_set_symtab_encoder_in_partition (encoder, (symtab_node)vnode); ipa_write_summaries_1 (compute_ltrans_boundary (encoder)); @@ -2564,7 +2564,7 @@ ipa_write_optimization_summaries (lto_symtab_encoder_t encoder) For functions newly born at WPA stage we need to initialize the uids here. */ - if (node->analyzed + if (node->symbol.definition && gimple_has_body_p (node->symbol.decl)) { push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl)); diff --git a/gcc/symtab.c b/gcc/symtab.c index 56f0de9..1a7f826 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -473,9 +473,15 @@ dump_symtab_base (FILE *f, symtab_node node) node->symbol.order, symtab_node_name (node)); dump_addr (f, " @", (void *)node); - fprintf (f, "\n Type: %s\n", symtab_type_names[node->symbol.type]); - fprintf (f, " Visibility:"); - + fprintf (f, "\n Type: %s", symtab_type_names[node->symbol.type]); + + if (node->symbol.definition) + fprintf (f, " definition"); + if (node->symbol.analyzed) + fprintf (f, " analyzed"); + if (node->symbol.alias) + fprintf (f, " alias"); + fprintf (f, "\n Visibility:"); if (node->symbol.in_other_partition) fprintf (f, " in_other_partition"); if (node->symbol.used_from_other_partition) @@ -653,6 +659,12 @@ verify_symtab_base (symtab_node node) && node->symbol.previous_sharing_asm_name->symbol.next_sharing_asm_name != node) { error ("double linked list of assembler names corrupted"); + error_found = true; + } + if (node->symbol.analyzed && !node->symbol.definition) + { + error ("node is analyzed byt it is not a definition"); + error_found = true; } if (node->symbol.same_comdat_group) { @@ -783,4 +795,40 @@ symtab_make_decl_local (tree decl) SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); } + +/* Given NODE, walk the alias chain to return the symbol NODE is alias of. + If NODE is not an alias, return NODE. + When AVAILABILITY is non-NULL, get minimal availability in the chain. */ + +symtab_node +symtab_alias_ultimate_target (symtab_node node, enum availability *availability) +{ + if (availability) + { + if (is_a <cgraph_node> (node)) + *availability = cgraph_function_body_availability (cgraph (node)); + else + *availability = cgraph_variable_initializer_availability (varpool (node)); + } + while (node) + { + if (node->symbol.alias && node->symbol.analyzed) + node = symtab_alias_target (node); + else + return node; + if (node && availability) + { + enum availability a; + if (is_a <cgraph_node> (node)) + a = cgraph_function_body_availability (cgraph (node)); + else + a = cgraph_variable_initializer_availability (varpool (node)); + if (a < *availability) + *availability = a; + } + } + if (availability) + *availability = AVAIL_NOT_AVAILABLE; + return NULL; +} #include "gt-symtab.h" diff --git a/gcc/toplev.c b/gcc/toplev.c index d41283d..a2ee491 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -393,15 +393,15 @@ wrapup_global_declaration_2 (tree decl) if (!node && flag_ltrans) needed = false; - else if (node && node->finalized) + else if (node && node->symbol.definition) needed = false; - else if (node && node->alias) + else if (node && node->symbol.alias) needed = false; else if (!cgraph_global_info_ready && (TREE_USED (decl) || TREE_USED (DECL_ASSEMBLER_NAME (decl)))) /* needed */; - else if (node && node->analyzed) + else if (node && node->symbol.analyzed) /* needed */; else if (DECL_COMDAT (decl)) needed = false; diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c index c66278c..d7e5a40 100644 --- a/gcc/trans-mem.c +++ b/gcc/trans-mem.c @@ -3932,7 +3932,7 @@ get_cg_data (struct cgraph_node **node, bool traverse_aliases) { struct tm_ipa_cg_data *d; - if (traverse_aliases && (*node)->alias) + if (traverse_aliases && (*node)->symbol.alias) *node = cgraph_get_node ((*node)->thunk.alias); d = (struct tm_ipa_cg_data *) (*node)->symbol.aux; @@ -4518,7 +4518,7 @@ ipa_tm_mayenterirr_function (struct cgraph_node *node) /* Recurse on the main body for aliases. In general, this will result in one of the bits above being set so that we will not have to recurse next time. */ - if (node->alias) + if (node->symbol.alias) return ipa_tm_mayenterirr_function (cgraph_get_node (node->thunk.alias)); /* What remains is unmarked local functions without items that force @@ -4678,9 +4678,7 @@ static inline void ipa_tm_mark_force_output_node (struct cgraph_node *node) { cgraph_mark_force_output_node (node); - /* ??? function_and_variable_visibility will reset - the needed bit, without actually checking. */ - node->analyzed = 1; + node->symbol.analyzed = true; } /* Callback data for ipa_tm_create_version_alias. */ @@ -5250,7 +5248,7 @@ ipa_tm_execute (void) { /* If this is an alias, make sure its base is queued as well. we need not scan the callees now, as the base will do. */ - if (node->alias) + if (node->symbol.alias) { node = cgraph_get_node (node->thunk.alias); d = get_cg_data (&node, true); @@ -5393,7 +5391,7 @@ ipa_tm_execute (void) for (i = 0; i < tm_callees.length (); ++i) { node = tm_callees[i]; - if (node->analyzed) + if (node->symbol.analyzed) { d = get_cg_data (&node, true); if (d->clone) diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index fc350bd..fb80b30 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -2580,7 +2580,7 @@ tree_could_trap_p (tree expr) /* Assume that accesses to weak functions may trap, unless we know they are certainly defined in current TU or in some other LTO partition. */ - if (DECL_WEAK (expr)) + if (DECL_WEAK (expr) && !DECL_COMDAT (expr)) { struct cgraph_node *node; if (!DECL_EXTERNAL (expr)) @@ -2596,7 +2596,7 @@ tree_could_trap_p (tree expr) /* Assume that accesses to weak vars may trap, unless we know they are certainly defined in current TU or in some other LTO partition. */ - if (DECL_WEAK (expr)) + if (DECL_WEAK (expr) && !DECL_COMDAT (expr)) { struct varpool_node *node; if (!DECL_EXTERNAL (expr)) diff --git a/gcc/tree-emutls.c b/gcc/tree-emutls.c index fc75b31..9fecb6c 100644 --- a/gcc/tree-emutls.c +++ b/gcc/tree-emutls.c @@ -704,15 +704,15 @@ create_emultls_var (struct varpool_node *var, void *data) cvar = varpool_get_node (cdecl); control_vars.quick_push (cvar); - if (!var->alias) + if (!var->symbol.alias) { /* Make sure the COMMON block control variable gets initialized. Note that there's no point in doing this for aliases; we only need to do this once for the main variable. */ emutls_common_1 (var->symbol.decl, cdecl, (tree *)data); } - if (var->alias && !var->alias_of) - cvar->alias = true; + if (var->symbol.alias && !var->alias_of) + cvar->symbol.alias = true; /* Indicate that the value of the TLS variable may be found elsewhere, preventing the variable from re-appearing in the GIMPLE. We cheat @@ -743,7 +743,7 @@ ipa_lower_emutls (void) gcc_checking_assert (TREE_STATIC (var->symbol.decl) || DECL_EXTERNAL (var->symbol.decl)); varpool_node_set_add (tls_vars, var); - if (var->alias && var->analyzed) + if (var->symbol.alias && var->symbol.definition) varpool_node_set_add (tls_vars, varpool_variable_node (var, NULL)); } @@ -767,9 +767,9 @@ ipa_lower_emutls (void) { var = tls_vars->nodes[i]; - if (var->alias && !var->alias_of) + if (var->symbol.alias && !var->alias_of) any_aliases = true; - else if (!var->alias) + else if (!var->symbol.alias) varpool_for_node_and_aliases (var, create_emultls_var, &ctor_body, true); } diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 57af7de..bee7766 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1726,7 +1726,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, if ((!edge || (edge->indirect_inlining_edge && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)) - && id->dst_node->analyzed + && id->dst_node->symbol.definition && (fn = gimple_call_fndecl (stmt)) != NULL) { struct cgraph_node *dest = cgraph_get_node (fn); @@ -1737,10 +1737,10 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, producing dead clone (for further cloning). In all other cases we hit a bug (incorrect node sharing is the most common reason for missing edges). */ - gcc_assert (!dest->analyzed + gcc_assert (!dest->symbol.definition || dest->symbol.address_taken - || !id->src_node->analyzed - || !id->dst_node->analyzed); + || !id->src_node->symbol.definition + || !id->dst_node->symbol.definition); if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES) cgraph_create_edge_including_clones (id->dst_node, dest, orig_stmt, stmt, bb->count, @@ -3611,7 +3611,7 @@ estimate_num_insns (gimple stmt, eni_weights *weights) /* Do not special case builtins where we see the body. This just confuse inliner. */ - if (!decl || !(node = cgraph_get_node (decl)) || node->analyzed) + if (!decl || !(node = cgraph_get_node (decl)) || node->symbol.definition) ; /* For buitins that are likely expanded to nothing or inlined do not account operand costs. */ @@ -4344,7 +4344,7 @@ optimize_inline_calls (tree fn) memset (&id, 0, sizeof (id)); id.src_node = id.dst_node = cgraph_get_node (fn); - gcc_assert (id.dst_node->analyzed); + gcc_assert (id.dst_node->symbol.definition); id.dst_fn = fn; /* Or any functions that aren't finished yet. */ if (current_function_decl) @@ -5238,7 +5238,7 @@ tree_function_versioning (tree old_decl, tree new_decl, pointer_set_destroy (id.statements_to_fold); fold_cond_expr_cond (); delete_unreachable_blocks_update_callgraph (&id); - if (id.dst_node->analyzed) + if (id.dst_node->symbol.definition) cgraph_rebuild_references (); update_ssa (TODO_update_ssa); diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 9eb06f6..1bfe2b2 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -2874,7 +2874,7 @@ get_constraint_for_ssa_var (tree t, vec<ce_s> *results, bool address_p) && (TREE_STATIC (t) || DECL_EXTERNAL (t))) { struct varpool_node *node = varpool_get_node (t); - if (node && node->alias) + if (node && node->symbol.alias && node->symbol.analyzed) { node = varpool_variable_node (node, NULL); t = node->symbol.decl; @@ -5751,7 +5751,7 @@ create_variable_info_for (tree decl, const char *name) /* If this is a global variable with an initializer and we are in IPA mode generate constraints for it. */ if (DECL_INITIAL (decl) - && vnode->analyzed) + && vnode->symbol.definition) { vec<ce_s> rhsc = vNULL; struct constraint_expr lhs, *rhsp; @@ -7023,7 +7023,8 @@ struct pt_solution ipa_escaped_pt static bool associate_varinfo_to_alias (struct cgraph_node *node, void *data) { - if (node->alias || node->thunk.thunk_p) + if ((node->symbol.alias || node->thunk.thunk_p) + && node->symbol.analyzed) insert_vi_for_tree (node->symbol.decl, (varinfo_t)data); return false; } @@ -7066,7 +7067,7 @@ ipa_pta_execute (void) /* Create constraints for global variables and their initializers. */ FOR_EACH_VARIABLE (var) { - if (var->alias) + if (var->symbol.alias && var->symbol.analyzed) continue; get_vi_for_tree (var->symbol.decl); diff --git a/gcc/varasm.c b/gcc/varasm.c index 5f62677..72bff5a 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -2256,7 +2256,7 @@ mark_decl_referenced (tree decl) definition. */ struct cgraph_node *node = cgraph_get_create_node (decl); if (!DECL_EXTERNAL (decl) - && !node->local.finalized) + && !node->symbol.definition) cgraph_mark_force_output_node (node); } else if (TREE_CODE (decl) == VAR_DECL) @@ -5595,9 +5595,9 @@ assemble_alias (tree decl, tree target) /* Allow aliases to aliases. */ if (TREE_CODE (decl) == FUNCTION_DECL) - cgraph_get_create_node (decl)->alias = true; + cgraph_get_create_node (decl)->symbol.alias = true; else - varpool_node_for_decl (decl)->alias = true; + varpool_node_for_decl (decl)->symbol.alias = true; /* If the target has already been emitted, we don't have to queue the alias. This saves a tad of memory. */ @@ -5700,12 +5700,12 @@ dump_tm_clone_pairs (vec<tm_alias_pair> tm_alias_pairs) TM_GETTMCLONE. If neither of these are true, we didn't generate a clone, and we didn't call it indirectly... no sense keeping it in the clone table. */ - if (!dst_n || !dst_n->analyzed) + if (!dst_n || !dst_n->symbol.definition) continue; /* This covers the case where we have optimized the original function away, and only access the transactional clone. */ - if (!src_n || !src_n->analyzed) + if (!src_n || !src_n->symbol.definition) continue; if (!switched) diff --git a/gcc/varpool.c b/gcc/varpool.c index e3ad22b..1916b76 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -58,6 +58,19 @@ void varpool_remove_node (struct varpool_node *node) { symtab_unregister_node ((symtab_node)node); + + /* Because we remove references from external functions before final compilation, + we may end up removing useful constructors. + FIXME: We probably want to trace boundaries better. */ + if (!const_value_known_p (node->symbol.decl)) + varpool_remove_initializer (node); + ggc_free (node); +} + +/* Renove node initializer when it is no longer needed. */ +void +varpool_remove_initializer (struct varpool_node *node) +{ if (DECL_INITIAL (node->symbol.decl) && !DECL_IN_CONSTANT_POOL (node->symbol.decl) /* Keep vtables for BINFO folding. */ @@ -65,7 +78,6 @@ varpool_remove_node (struct varpool_node *node) /* FIXME: http://gcc.gnu.org/PR55395 */ && debug_info_level == DINFO_LEVEL_NONE) DECL_INITIAL (node->symbol.decl) = error_mark_node; - ggc_free (node); } /* Dump given cgraph node. */ @@ -80,10 +92,6 @@ dump_varpool_node (FILE *f, struct varpool_node *node) fprintf (f, " Varpool flags:"); if (DECL_INITIAL (node->symbol.decl)) fprintf (f, " initialized"); - if (node->analyzed) - fprintf (f, " analyzed"); - if (node->finalized) - fprintf (f, " finalized"); if (node->output) fprintf (f, " output"); if (TREE_READONLY (node->symbol.decl)) @@ -117,9 +125,9 @@ struct varpool_node * varpool_node_for_asm (tree asmname) { if (symtab_node node = symtab_node_for_asm (asmname)) - if (varpool_node *vnode = dyn_cast <varpool_node> (node)) - return vnode; - return NULL; + return dyn_cast <varpool_node> (node); + else + return NULL; } /* Determine if variable DECL is needed. That is, visible to something @@ -205,12 +213,12 @@ enum availability cgraph_variable_initializer_availability (struct varpool_node *node) { gcc_assert (cgraph_function_flags_ready); - if (!node->finalized) + if (!node->symbol.definition) return AVAIL_NOT_AVAILABLE; if (!TREE_PUBLIC (node->symbol.decl)) return AVAIL_AVAILABLE; /* If the variable can be overwritten, return OVERWRITABLE. Takes - care of at least two notable extensions - the COMDAT variables + care of at least one notable extension - the COMDAT variables used to share template instantiations in C++. */ if (!decl_replaceable_p (node->symbol.decl)) return AVAIL_OVERWRITABLE; @@ -225,24 +233,24 @@ varpool_analyze_node (struct varpool_node *node) /* When reading back varpool at LTO time, we re-construct the queue in order to have "needed" list right by inserting all needed nodes into varpool. We however don't want to re-analyze already analyzed nodes. */ - if (!node->analyzed) + if (!node->symbol.analyzed) { gcc_assert (!in_lto_p || cgraph_function_flags_ready); /* Compute the alignment early so function body expanders are already informed about increased alignment. */ align_variable (decl, 0); } - if (node->alias && node->alias_of) + if (node->symbol.alias && node->alias_of) { struct varpool_node *tgt = varpool_node_for_decl (node->alias_of); struct varpool_node *n; - for (n = tgt; n && n->alias; - n = n->analyzed ? varpool_alias_aliased_node (n) : NULL) + for (n = tgt; n && n->symbol.alias; + n = n->symbol.analyzed ? varpool_alias_target (n) : NULL) if (n == node) { error ("variable %q+D part of alias cycle", node->symbol.decl); - node->alias = false; + node->symbol.alias = false; continue; } if (!vec_safe_length (node->symbol.ref_list.references)) @@ -257,8 +265,8 @@ varpool_analyze_node (struct varpool_node *node) } } else if (DECL_INITIAL (decl)) - record_references_in_initializer (decl, node->analyzed); - node->analyzed = true; + record_references_in_initializer (decl, node->symbol.analyzed); + node->symbol.analyzed = true; } /* Assemble thunks and aliases associated to NODE. */ @@ -287,7 +295,7 @@ varpool_assemble_decl (struct varpool_node *node) /* Aliases are outout when their target is produced or by output_weakrefs. */ - if (node->alias) + if (node->symbol.alias) return false; /* Constant pool is output from RTL land when the reference @@ -316,7 +324,7 @@ varpool_assemble_decl (struct varpool_node *node) { assemble_variable (decl, 0, 1, 0); gcc_assert (TREE_ASM_WRITTEN (decl)); - node->finalized = 1; + node->symbol.definition = true; assemble_aliases (node); return true; } @@ -357,7 +365,7 @@ varpool_remove_unreferenced_decls (void) fprintf (cgraph_dump_file, "Trivially needed variables:"); FOR_EACH_DEFINED_VARIABLE (node) { - if (node->analyzed + if (node->symbol.analyzed && (!varpool_can_remove_if_no_refs (node) /* We just expanded all function bodies. See if any of them needed the variable. */ @@ -381,7 +389,7 @@ varpool_remove_unreferenced_decls (void) next = next->symbol.same_comdat_group) { varpool_node *vnext = dyn_cast <varpool_node> (next); - if (vnext && vnext->analyzed) + if (vnext && vnext->symbol.analyzed) enqueue_node (vnext, &first); } } @@ -390,8 +398,8 @@ varpool_remove_unreferenced_decls (void) varpool_node *vnode = dyn_cast <varpool_node> (ref->referred); if (vnode && (!DECL_EXTERNAL (ref->referred->symbol.decl) - || vnode->alias) - && vnode->analyzed) + || vnode->symbol.alias) + && vnode->symbol.analyzed) enqueue_node (vnode, &first); } } @@ -419,7 +427,7 @@ void varpool_finalize_named_section_flags (struct varpool_node *node) { if (!TREE_ASM_WRITTEN (node->symbol.decl) - && !node->alias + && !node->symbol.alias && !node->symbol.in_other_partition && !DECL_EXTERNAL (node->symbol.decl) && TREE_CODE (node->symbol.decl) == VAR_DECL @@ -484,8 +492,8 @@ varpool_create_variable_alias (tree alias, tree decl) gcc_assert (TREE_CODE (decl) == VAR_DECL); gcc_assert (TREE_CODE (alias) == VAR_DECL); alias_node = varpool_node_for_decl (alias); - alias_node->alias = 1; - alias_node->finalized = 1; + alias_node->symbol.alias = true; + alias_node->symbol.definition = true; alias_node->alias_of = decl; /* Extra name alias mechanizm creates aliases really late |