void symtab_node::fixup_same_cpp_alias_visibility (symtab_node *target) { if (is_a <cgraph_node *> (this)) { DECL_DECLARED_INLINE_P (decl) = DECL_DECLARED_INLINE_P (target->decl); DECL_DISREGARD_INLINE_LIMITS (decl) = DECL_DISREGARD_INLINE_LIMITS (target->decl); } /* FIXME: It is not really clear why those flags should not be copied for functions, too. */ else { DECL_WEAK (decl) = DECL_WEAK (target->decl); DECL_EXTERNAL (decl) = DECL_EXTERNAL (target->decl); DECL_VISIBILITY (decl) = DECL_VISIBILITY (target->decl); } DECL_VIRTUAL_P (decl) = DECL_VIRTUAL_P (target->decl); if (TREE_PUBLIC (decl)) { tree group; DECL_EXTERNAL (decl) = DECL_EXTERNAL (target->decl); DECL_COMDAT (decl) = DECL_COMDAT (target->decl); group = target->get_comdat_group (); set_comdat_group (group); if (group && !same_comdat_group) add_to_same_comdat_group (target); } externally_visible = target->externally_visible; }
void fixup_same_cpp_alias_visibility (symtab_node node, symtab_node target) { if (is_a <cgraph_node> (node)) { DECL_DECLARED_INLINE_P (node->symbol.decl) = DECL_DECLARED_INLINE_P (target->symbol.decl); DECL_DISREGARD_INLINE_LIMITS (node->symbol.decl) = DECL_DISREGARD_INLINE_LIMITS (target->symbol.decl); } /* FIXME: It is not really clear why those flags should not be copied for functions, too. */ else { DECL_WEAK (node->symbol.decl) = DECL_WEAK (target->symbol.decl); DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (target->symbol.decl); DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (target->symbol.decl); } DECL_VIRTUAL_P (node->symbol.decl) = DECL_VIRTUAL_P (target->symbol.decl); if (TREE_PUBLIC (node->symbol.decl)) { DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (target->symbol.decl); DECL_COMDAT (node->symbol.decl) = DECL_COMDAT (target->symbol.decl); DECL_COMDAT_GROUP (node->symbol.decl) = DECL_COMDAT_GROUP (target->symbol.decl); if (DECL_ONE_ONLY (target->symbol.decl) && !node->symbol.same_comdat_group) symtab_add_to_same_comdat_group ((symtab_node)node, (symtab_node)target); } node->symbol.externally_visible = target->symbol.externally_visible; }
static unsigned int function_and_variable_visibility (void) { struct cgraph_node *node; struct varpool_node *vnode; for (node = cgraph_nodes; node; node = node->next) { if (node->reachable && (DECL_COMDAT (node->decl) || (!flag_whole_program && TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl)))) node->local.externally_visible = true; if (!node->local.externally_visible && node->analyzed && !DECL_EXTERNAL (node->decl)) { gcc_assert (flag_whole_program || !TREE_PUBLIC (node->decl)); TREE_PUBLIC (node->decl) = 0; } node->local.local = (!node->needed && node->analyzed && !DECL_EXTERNAL (node->decl) && !node->local.externally_visible); } for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) { if (vnode->needed && !flag_whole_program && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))) vnode->externally_visible = 1; if (!vnode->externally_visible) { gcc_assert (flag_whole_program || !TREE_PUBLIC (vnode->decl)); TREE_PUBLIC (vnode->decl) = 0; } /* Static variables defined in auxiliary modules are externalized to allow cross module inlining. */ gcc_assert (TREE_STATIC (vnode->decl) || varpool_is_auxiliary (vnode)); } if (dump_file) { fprintf (dump_file, "\nMarking local functions:"); for (node = cgraph_nodes; node; node = node->next) if (node->local.local) fprintf (dump_file, " %s", cgraph_node_name (node)); fprintf (dump_file, "\n\n"); fprintf (dump_file, "\nMarking externally visible functions:"); for (node = cgraph_nodes; node; node = node->next) if (node->local.externally_visible) fprintf (dump_file, " %s", cgraph_node_name (node)); fprintf (dump_file, "\n\n"); } cgraph_function_flags_ready = true; return 0; }
/* Make DECL local. FIXME: We shouldn't need to mess with rtl this early, but other code such as notice_global_symbol generates rtl. */ void symtab_make_decl_local (tree decl) { rtx rtl, symbol; if (TREE_CODE (decl) == VAR_DECL) DECL_COMMON (decl) = 0; else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); if (DECL_ONE_ONLY (decl) || DECL_COMDAT (decl)) { /* It is possible that we are linking against library defining same COMDAT function. To avoid conflict we need to rename our local name of the function just in the case WHOPR partitioning decide to make it hidden to avoid cross partition references. */ if (flag_wpa) { const char *old_name; symtab_node node = symtab_get_node (decl); old_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); change_decl_assembler_name (decl, clone_function_name (decl, "local")); if (node->symbol.lto_file_data) lto_record_renamed_decl (node->symbol.lto_file_data, old_name, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); } DECL_SECTION_NAME (decl) = 0; DECL_COMDAT (decl) = 0; } DECL_COMDAT_GROUP (decl) = 0; DECL_WEAK (decl) = 0; DECL_EXTERNAL (decl) = 0; TREE_PUBLIC (decl) = 0; if (!DECL_RTL_SET_P (decl)) return; /* Update rtl flags. */ make_decl_rtl (decl); rtl = DECL_RTL (decl); if (!MEM_P (rtl)) return; symbol = XEXP (rtl, 0); if (GET_CODE (symbol) != SYMBOL_REF) return; SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); }
static void pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr) { bp_pack_value (bp, DECL_COMMON (expr), 1); bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1); bp_pack_value (bp, DECL_WEAK (expr), 1); bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr), 1); bp_pack_value (bp, DECL_COMDAT (expr), 1); bp_pack_value (bp, DECL_VISIBILITY (expr), 2); bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr), 1); if (TREE_CODE (expr) == VAR_DECL) { bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1); /* DECL_IN_TEXT_SECTION is set during final asm output only. */ bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1); } if (TREE_CODE (expr) == FUNCTION_DECL) { bp_pack_value (bp, DECL_FINAL_P (expr), 1); bp_pack_value (bp, DECL_CXX_CONSTRUCTOR_P (expr), 1); bp_pack_value (bp, DECL_CXX_DESTRUCTOR_P (expr), 1); } }
static void unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr) { DECL_DEFER_OUTPUT (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp, 2); DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp, 1); if (TREE_CODE (expr) == VAR_DECL) { DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp, 3); } if (VAR_OR_FUNCTION_DECL_P (expr)) { priority_type p; p = (priority_type) bp_unpack_var_len_unsigned (bp); SET_DECL_INIT_PRIORITY (expr, p); } }
void symtab_node::make_decl_local (void) { rtx rtl, symbol; /* Avoid clearing comdat_groups on comdat-local decls. */ if (TREE_PUBLIC (decl) == 0) return; if (TREE_CODE (decl) == VAR_DECL) DECL_COMMON (decl) = 0; else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); DECL_COMDAT (decl) = 0; DECL_WEAK (decl) = 0; DECL_EXTERNAL (decl) = 0; DECL_VISIBILITY_SPECIFIED (decl) = 0; DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; TREE_PUBLIC (decl) = 0; if (!DECL_RTL_SET_P (decl)) return; /* Update rtl flags. */ make_decl_rtl (decl); rtl = DECL_RTL (decl); if (!MEM_P (rtl)) return; symbol = XEXP (rtl, 0); if (GET_CODE (symbol) != SYMBOL_REF) return; SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); }
/* Mark DECL as finalized. By finalizing the declaration, frontend instruct the middle end to output the variable to asm file, if needed or externally visible. */ void varpool_finalize_decl (tree decl) { struct varpool_node *node = varpool_node (decl); gcc_assert (TREE_STATIC (decl)); /* The first declaration of a variable that comes through this function decides whether it is global (in C, has external linkage) or local (in C, has internal linkage). So do nothing more if this function has already run. */ if (node->finalized) { if (cgraph_global_info_ready) varpool_assemble_pending_decls (); return; } if (node->needed) varpool_enqueue_needed_node (node); node->finalized = 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. */ || (!flag_toplevel_reorder && !DECL_COMDAT (node->symbol.decl) && !DECL_ARTIFICIAL (node->symbol.decl))) node->symbol.force_output = true; if (decide_is_variable_needed (node, decl)) varpool_mark_needed_node (node); if (cgraph_global_info_ready) varpool_assemble_pending_decls (); }
/* Mark DECL as finalized. By finalizing the declaration, frontend instruct the middle end to output the variable to asm file, if needed or externally visible. */ void varpool_finalize_decl (tree decl) { struct varpool_node *node = varpool_node (decl); /* The first declaration of a variable that comes through this function decides whether it is global (in C, has external linkage) or local (in C, has internal linkage). So do nothing more if this function has already run. */ if (node->finalized) { if (cgraph_global_info_ready) varpool_assemble_pending_decls (); return; } if (node->needed) varpool_enqueue_needed_node (node); node->finalized = true; if (decide_is_variable_needed (node, decl)) varpool_mark_needed_node (node); /* Since we reclaim unreachable nodes at the end of every language level unit, we need to be conservative about possible entry points there. */ else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) varpool_mark_needed_node (node); if (cgraph_global_info_ready) varpool_assemble_pending_decls (); }
/* Determine if variable DECL is needed. That is, visible to something either outside this translation unit, something magic in the system configury */ bool decide_is_variable_needed (struct varpool_node *node, tree decl) { /* If the user told us it is used, then it must be so. */ if ((node->externally_visible && !DECL_COMDAT (decl)) || node->force_output) return true; /* ??? If the assembler name is set by hand, it is possible to assemble the name later after finalizing the function and the fact is noticed in assemble_name then. This is arguably a bug. */ if (DECL_ASSEMBLER_NAME_SET_P (decl) && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) return true; /* Externally visible variables must be output. The exception is COMDAT variables that must be output only when they are needed. */ if (TREE_PUBLIC (decl) && !flag_whole_program && !flag_lto && !flag_whopr && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) return true; /* When emulating tls, we actually see references to the control variable, rather than the user-level variable. */ if (!targetm.have_tls && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl)) { tree control = emutls_decl (decl); if (decide_is_variable_needed (varpool_node (control), control)) return true; } /* When not reordering top level variables, we have to assume that we are going to keep everything. */ if (flag_toplevel_reorder) return false; /* We want to emit COMDAT variables only when absolutely necessary. */ if (DECL_COMDAT (decl)) return false; return true; }
static bool decide_is_function_needed (struct cgraph_node *node, tree decl) { if (MAIN_NAME_P (DECL_NAME (decl)) && TREE_PUBLIC (decl)) { node->local.externally_visible = true; return true; } /* If the user told us it is used, then it must be so. */ if (node->local.externally_visible) return true; /* ??? If the assembler name is set by hand, it is possible to assemble the name later after finalizing the function and the fact is noticed in assemble_name then. This is arguably a bug. */ if (DECL_ASSEMBLER_NAME_SET_P (decl) && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) return true; /* With -fkeep-inline-functions we are keeping all inline functions except for extern inline ones. */ if (flag_keep_inline_functions && DECL_DECLARED_INLINE_P (decl) && !DECL_EXTERNAL (decl) && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (decl))) return true; /* If we decided it was needed before, but at the time we didn't have the body of the function available, then it's still needed. We have to go back and re-check its dependencies now. */ if (node->needed) return true; /* Externally visible functions must be output. The exception is COMDAT functions that must be output only when they are needed. When not optimizing, also output the static functions. (see PR24561), but don't do so for always_inline functions, functions declared inline and nested functions. These was optimized out in the original implementation and it is unclear whether we want to change the behavior here. */ if (((TREE_PUBLIC (decl) || (!optimize && !node->local.disregard_inline_limits && !DECL_DECLARED_INLINE_P (decl) && !node->origin)) && !flag_whole_program) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) return true; /* Constructors and destructors are reachable from the runtime by some mechanism. */ if (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl)) return true; return false; }
void symtab_make_decl_local (tree decl) { rtx rtl, symbol; /* Avoid clearing DECL_COMDAT_GROUP on comdat-local decls. */ if (TREE_PUBLIC (decl) == 0) return; if (TREE_CODE (decl) == VAR_DECL) DECL_COMMON (decl) = 0; else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); if (DECL_ONE_ONLY (decl) || DECL_COMDAT (decl)) { DECL_SECTION_NAME (decl) = 0; DECL_COMDAT (decl) = 0; } DECL_COMDAT_GROUP (decl) = 0; DECL_WEAK (decl) = 0; DECL_EXTERNAL (decl) = 0; DECL_VISIBILITY_SPECIFIED (decl) = 0; DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; TREE_PUBLIC (decl) = 0; DECL_DLLIMPORT_P (decl) = 0; if (!DECL_RTL_SET_P (decl)) return; /* Update rtl flags. */ make_decl_rtl (decl); rtl = DECL_RTL (decl); if (!MEM_P (rtl)) return; symbol = XEXP (rtl, 0); if (GET_CODE (symbol) != SYMBOL_REF) return; SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); }
symtab_node * symtab_nonoverwritable_alias (symtab_node *node) { tree new_decl; symtab_node *new_node = NULL; /* First try to look up existing alias or base object (if that is already non-overwritable). */ node = symtab_alias_ultimate_target (node, NULL); gcc_assert (!node->alias && !node->weakref); symtab_for_node_and_aliases (node, symtab_nonoverwritable_alias_1, (void *)&new_node, true); if (new_node) return new_node; #ifndef ASM_OUTPUT_DEF /* If aliases aren't supported by the assembler, fail. */ return NULL; #endif /* Otherwise create a new one. */ new_decl = copy_node (node->decl); DECL_DLLIMPORT_P (new_decl) = 0; DECL_NAME (new_decl) = clone_function_name (node->decl, "localalias"); if (TREE_CODE (new_decl) == FUNCTION_DECL) DECL_STRUCT_FUNCTION (new_decl) = NULL; DECL_INITIAL (new_decl) = NULL; SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl)); SET_DECL_RTL (new_decl, NULL); /* Update the properties. */ DECL_EXTERNAL (new_decl) = 0; if (DECL_ONE_ONLY (node->decl)) DECL_SECTION_NAME (new_decl) = NULL; DECL_COMDAT_GROUP (new_decl) = 0; TREE_PUBLIC (new_decl) = 0; DECL_COMDAT (new_decl) = 0; DECL_WEAK (new_decl) = 0; DECL_VIRTUAL_P (new_decl) = 0; if (TREE_CODE (new_decl) == FUNCTION_DECL) { DECL_STATIC_CONSTRUCTOR (new_decl) = 0; DECL_STATIC_DESTRUCTOR (new_decl) = 0; new_node = cgraph_create_function_alias (new_decl, node->decl); } else new_node = varpool_create_variable_alias (new_decl, node->decl); symtab_resolve_alias (new_node, node); gcc_assert (decl_binds_to_current_def_p (new_decl)); return new_node; }
static bool lto_symtab_resolve_replaceable_p (symtab_node e) { if (DECL_EXTERNAL (e->symbol.decl) || DECL_COMDAT (e->symbol.decl) || DECL_ONE_ONLY (e->symbol.decl) || DECL_WEAK (e->symbol.decl)) return true; if (TREE_CODE (e->symbol.decl) == VAR_DECL) return (DECL_COMMON (e->symbol.decl) || (!flag_no_common && !DECL_INITIAL (e->symbol.decl))); return false; }
/* Return variable availability. See cgraph.h for description of individual return values. */ enum availability cgraph_variable_initializer_availability (struct varpool_node *node) { gcc_assert (cgraph_function_flags_ready); if (!node->finalized) return AVAIL_NOT_AVAILABLE; if (!TREE_PUBLIC (node->decl)) return AVAIL_AVAILABLE; /* If the variable can be overwritten, return OVERWRITABLE. Takes care of at least two notable extensions - the COMDAT variables used to share template instantiations in C++. */ if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl)) return AVAIL_OVERWRITABLE; return AVAIL_AVAILABLE; }
enum symbol_class get_symbol_class (symtab_node *node) { /* Inline clones are always duplicated. This include external delcarations. */ cgraph_node *cnode = dyn_cast <cgraph_node> (node); if (DECL_ABSTRACT (node->decl)) return SYMBOL_EXTERNAL; if (cnode && cnode->global.inlined_to) return SYMBOL_DUPLICATE; /* Weakref aliases are always duplicated. */ if (node->weakref) return SYMBOL_DUPLICATE; /* External declarations are external. */ if (DECL_EXTERNAL (node->decl)) return SYMBOL_EXTERNAL; if (varpool_node *vnode = dyn_cast <varpool_node> (node)) { /* Constant pool references use local symbol names that can not be promoted global. We should never put into a constant pool objects that can not be duplicated across partitions. */ if (DECL_IN_CONSTANT_POOL (node->decl)) return SYMBOL_DUPLICATE; gcc_checking_assert (vnode->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)->definition) return SYMBOL_EXTERNAL; /* Comdats are duplicated to every use unless they are keyed. Those do not need duplication. */ if (DECL_COMDAT (node->decl) && !node->force_output && !symtab_used_from_object_file_p (node)) return SYMBOL_DUPLICATE; return SYMBOL_PARTITION; }
/* Determine if variable DECL is needed. That is, visible to something either outside this translation unit, something magic in the system configury */ bool decide_is_variable_needed (struct varpool_node *node, tree decl) { /* If the user told us it is used, then it must be so. */ if (node->symbol.force_output) return true; gcc_assert (!DECL_EXTERNAL (decl)); /* Externally visible variables must be output. The exception is COMDAT variables that must be output only when they are needed. */ if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) return true; return false; }
static bool can_remove_node_now_p_1 (struct cgraph_node *node) { /* FIXME: When address is taken of DECL_EXTERNAL function we still can remove its offline copy, but we would need to keep unanalyzed node in the callgraph so references can point to it. */ return (!node->symbol.address_taken && !ipa_ref_has_aliases_p (&node->symbol.ref_list) && cgraph_can_remove_if_no_direct_calls_p (node) /* Inlining might enable more devirtualizing, so we want to remove those only after all devirtualizable virtual calls are processed. Lacking may edges in callgraph we just preserve them post inlining. */ && (!DECL_VIRTUAL_P (node->symbol.decl) || (!DECL_COMDAT (node->symbol.decl) && !DECL_EXTERNAL (node->symbol.decl))) /* During early inlining some unanalyzed cgraph nodes might be in the callgraph and they might reffer the function in question. */ && !cgraph_new_nodes); }
/* Mark DECL as finalized. By finalizing the declaration, frontend instruct the middle end to output the variable to asm file, if needed or externally visible. */ void varpool_finalize_decl (tree decl) { struct varpool_node *node = varpool_node (decl); /* FIXME: We don't really stream varpool datastructure and instead rebuild it by varpool_finalize_decl. This is not quite correct since this way we can't attach any info to varpool. Eventually we will want to stream varpool nodes and the flags. For the moment just prevent analysis of varpool nodes to happen again, so we will re-try to compute "address_taken" flag of varpool that breaks in presence of clones. */ if (in_lto_p) node->analyzed = true; /* The first declaration of a variable that comes through this function decides whether it is global (in C, has external linkage) or local (in C, has internal linkage). So do nothing more if this function has already run. */ if (node->finalized) { if (cgraph_global_info_ready) varpool_assemble_pending_decls (); return; } if (node->needed) varpool_enqueue_needed_node (node); node->finalized = true; if (decide_is_variable_needed (node, decl)) varpool_mark_needed_node (node); /* Since we reclaim unreachable nodes at the end of every language level unit, we need to be conservative about possible entry points there. */ else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) varpool_mark_needed_node (node); if (cgraph_global_info_ready) varpool_assemble_pending_decls (); }
static tree associated_type (tree decl) { tree t = NULL_TREE; /* In the C++ frontend, DECL_CONTEXT for a method doesn't actually refer to the containing class. So we look at the 'this' arg. */ if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) { /* Artificial methods are not affected by the import/export status of their class unless they are COMDAT. Implicit copy ctor's and dtor's are not affected by class status but virtual and non-virtual thunks are. */ if (!DECL_ARTIFICIAL (decl) || DECL_COMDAT (decl)) t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))))); } else if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))) t = DECL_CONTEXT (decl); return t; }
/* Determine if variable DECL is needed. That is, visible to something either outside this translation unit, something magic in the system configury */ bool decide_is_variable_needed (struct varpool_node *node, tree decl) { /* If the user told us it is used, then it must be so. */ if (node->force_output) return true; gcc_assert (!DECL_EXTERNAL (decl)); /* Externally visible variables must be output. The exception is COMDAT variables that must be output only when they are needed. */ if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) return true; /* When not reordering top level variables, we have to assume that we are going to keep everything. */ if (!flag_toplevel_reorder) return true; return false; }
symtab_node symtab_nonoverwritable_alias (symtab_node node) { tree new_decl; symtab_node new_node = NULL; symtab_for_node_and_aliases (node, symtab_nonoverwritable_alias_1, (void *)&new_node, true); if (new_node) return new_node; new_decl = copy_node (node->symbol.decl); DECL_NAME (new_decl) = clone_function_name (node->symbol.decl, "localalias"); if (TREE_CODE (new_decl) == FUNCTION_DECL) DECL_STRUCT_FUNCTION (new_decl) = NULL; DECL_INITIAL (new_decl) = NULL; SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl)); SET_DECL_RTL (new_decl, NULL); /* Update the properties. */ DECL_EXTERNAL (new_decl) = 0; if (DECL_ONE_ONLY (node->symbol.decl)) DECL_SECTION_NAME (new_decl) = NULL; DECL_COMDAT_GROUP (new_decl) = 0; TREE_PUBLIC (new_decl) = 0; DECL_COMDAT (new_decl) = 0; DECL_WEAK (new_decl) = 0; DECL_VIRTUAL_P (new_decl) = 0; if (TREE_CODE (new_decl) == FUNCTION_DECL) { DECL_STATIC_CONSTRUCTOR (new_decl) = 0; DECL_STATIC_DESTRUCTOR (new_decl) = 0; new_node = (symtab_node) cgraph_create_function_alias (new_decl, node->symbol.decl); } else new_node = (symtab_node) varpool_create_variable_alias (new_decl, node->symbol.decl); symtab_resolve_alias (new_node, node); return new_node; }
static void pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr) { bp_pack_value (bp, DECL_DEFER_OUTPUT (expr), 1); bp_pack_value (bp, DECL_COMMON (expr), 1); bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1); bp_pack_value (bp, DECL_WEAK (expr), 1); bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr), 1); bp_pack_value (bp, DECL_COMDAT (expr), 1); bp_pack_value (bp, DECL_VISIBILITY (expr), 2); bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr), 1); if (TREE_CODE (expr) == VAR_DECL) { bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1); bp_pack_value (bp, DECL_IN_TEXT_SECTION (expr), 1); bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1); bp_pack_value (bp, DECL_TLS_MODEL (expr), 3); } if (VAR_OR_FUNCTION_DECL_P (expr)) bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr)); }
void cgraph_finalize_function (tree decl, bool nested) { struct cgraph_node *node = cgraph_node (decl); if (node->local.finalized) cgraph_reset_node (node); node->pid = cgraph_max_pid ++; notice_global_symbol (decl); node->local.finalized = true; node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL; record_cdtor_fn (node->decl); if (node->nested) lower_nested_functions (decl); gcc_assert (!node->nested); if (decide_is_function_needed (node, decl)) cgraph_mark_needed_node (node); /* Since we reclaim unreachable nodes at the end of every language level unit, we need to be conservative about possible entry points there. */ if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))) cgraph_mark_reachable_node (node); /* If we've not yet emitted decl, tell the debug info about it. */ if (!TREE_ASM_WRITTEN (decl)) (*debug_hooks->deferred_inline_function) (decl); /* Possibly warn about unused parameters. */ if (warn_unused_parameter) do_warn_unused_parameter (decl); if (!nested) ggc_collect (); }
static void unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr) { DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp, 2); DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp, 1); if (TREE_CODE (expr) == VAR_DECL) { DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1); } if (TREE_CODE (expr) == FUNCTION_DECL) { DECL_FINAL_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_CXX_CONSTRUCTOR_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_CXX_DESTRUCTOR_P (expr) = (unsigned) bp_unpack_value (bp, 1); } }
static struct cgraph_node * save_inline_function_body (struct cgraph_node *node) { struct cgraph_node *first_clone, *n; if (dump_file) fprintf (dump_file, "\nSaving body of %s for later reuse\n", cgraph_node_name (node)); gcc_assert (node == cgraph_get_node (node->symbol.decl)); /* first_clone will be turned into real function. */ first_clone = node->clones; first_clone->symbol.decl = copy_node (node->symbol.decl); symtab_insert_node_to_hashtable ((symtab_node) first_clone); gcc_assert (first_clone == cgraph_get_node (first_clone->symbol.decl)); /* Now reshape the clone tree, so all other clones descends from first_clone. */ if (first_clone->next_sibling_clone) { for (n = first_clone->next_sibling_clone; n->next_sibling_clone; n = n->next_sibling_clone) n->clone_of = first_clone; n->clone_of = first_clone; n->next_sibling_clone = first_clone->clones; if (first_clone->clones) first_clone->clones->prev_sibling_clone = n; first_clone->clones = first_clone->next_sibling_clone; first_clone->next_sibling_clone->prev_sibling_clone = NULL; first_clone->next_sibling_clone = NULL; gcc_assert (!first_clone->prev_sibling_clone); } first_clone->clone_of = NULL; /* Now node in question has no clones. */ node->clones = NULL; /* Inline clones share decl with the function they are cloned from. Walk the whole clone tree and redirect them all to the new decl. */ if (first_clone->clones) for (n = first_clone->clones; n != first_clone;) { gcc_assert (n->symbol.decl == node->symbol.decl); n->symbol.decl = first_clone->symbol.decl; if (n->clones) n = n->clones; else if (n->next_sibling_clone) n = n->next_sibling_clone; else { while (n != first_clone && !n->next_sibling_clone) n = n->clone_of; if (n != first_clone) n = n->next_sibling_clone; } } /* Copy the OLD_VERSION_NODE function tree to the new version. */ tree_function_versioning (node->symbol.decl, first_clone->symbol.decl, NULL, true, NULL, false, NULL, NULL); /* The function will be short lived and removed after we inline all the clones, but make it internal so we won't confuse ourself. */ DECL_EXTERNAL (first_clone->symbol.decl) = 0; DECL_COMDAT_GROUP (first_clone->symbol.decl) = NULL_TREE; TREE_PUBLIC (first_clone->symbol.decl) = 0; DECL_COMDAT (first_clone->symbol.decl) = 0; first_clone->ipa_transforms_to_apply.release (); /* When doing recursive inlining, the clone may become unnecessary. This is possible i.e. in the case when the recursive function is proved to be non-throwing and the recursion happens only in the EH landing pad. We can not remove the clone until we are done with saving the body. Remove it now. */ if (!first_clone->callers) { cgraph_remove_node_and_inline_clones (first_clone, NULL); first_clone = NULL; } #ifdef ENABLE_CHECKING else verify_cgraph_node (first_clone); #endif return first_clone; }
static void lto_symtab_merge_decls_2 (symtab_node *first, bool diagnosed_p) { symtab_node *prevailing; symtab_node *e; vec<tree> mismatches = vNULL; unsigned i; tree decl; bool tbaa_p = false; /* Nothing to do for a single entry. */ prevailing = first; if (!prevailing->next_sharing_asm_name) return; /* Try to merge each entry with the prevailing one. */ symtab_node *last_prevailing = prevailing, *next; for (e = prevailing->next_sharing_asm_name; e; e = next) { next = e->next_sharing_asm_name; /* Skip non-LTO symbols and symbols whose declaration we already visited. */ if (lto_symtab_prevailing_decl (e->decl) != e->decl || !lto_symtab_symbol_p (e) || e->decl == prevailing->decl) continue; if (!lto_symtab_merge (prevailing, e) && !diagnosed_p && !DECL_ARTIFICIAL (e->decl)) mismatches.safe_push (e->decl); symtab_node *this_prevailing; for (this_prevailing = prevailing; ; this_prevailing = this_prevailing->next_sharing_asm_name) { if (this_prevailing->decl != e->decl && lto_symtab_merge_p (this_prevailing->decl, e->decl)) break; if (this_prevailing == last_prevailing) { this_prevailing = NULL; break; } } if (this_prevailing) lto_symtab_prevail_decl (this_prevailing->decl, e->decl); /* Maintain LRU list: relink the new prevaililng symbol just after previaling node in the chain and update last_prevailing. Since the number of possible declarations of a given symbol is small, this should be faster than building a hash. */ else if (e == prevailing->next_sharing_asm_name) last_prevailing = e; else { if (e->next_sharing_asm_name) e->next_sharing_asm_name->previous_sharing_asm_name = e->previous_sharing_asm_name; e->previous_sharing_asm_name->next_sharing_asm_name = e->next_sharing_asm_name; e->previous_sharing_asm_name = prevailing; e->next_sharing_asm_name = prevailing->next_sharing_asm_name; prevailing->next_sharing_asm_name->previous_sharing_asm_name = e; prevailing->next_sharing_asm_name = e; if (last_prevailing == prevailing) last_prevailing = e; } } if (mismatches.is_empty ()) return; /* Diagnose all mismatched re-declarations. */ FOR_EACH_VEC_ELT (mismatches, i, decl) { int level = warn_type_compatibility_p (TREE_TYPE (prevailing->decl), TREE_TYPE (decl), DECL_COMDAT (decl)); if (level) { bool diag = false; if (level & 2) diag = warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wodr, "%qD violates the C++ One Definition Rule ", decl); if (!diag && (level & 1)) diag = warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wlto_type_mismatch, "type of %qD does not match original " "declaration", decl); if (diag) { warn_types_mismatch (TREE_TYPE (prevailing->decl), TREE_TYPE (decl), DECL_SOURCE_LOCATION (prevailing->decl), DECL_SOURCE_LOCATION (decl)); if ((level & 4) && !TREE_READONLY (prevailing->decl)) tbaa_p = true; } diagnosed_p |= diag; } else if ((DECL_USER_ALIGN (prevailing->decl) && DECL_USER_ALIGN (decl)) && DECL_ALIGN (prevailing->decl) < DECL_ALIGN (decl)) { diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wlto_type_mismatch, "alignment of %qD is bigger than " "original declaration", decl); } else diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wlto_type_mismatch, "size of %qD differ from the size of " "original declaration", decl); }
/* Walk the decls we marked as necessary and see if they reference new variables or functions and add them into the worklists. */ bool varpool_analyze_pending_decls (void) { bool changed = false; timevar_push (TV_VARPOOL); while (varpool_first_unanalyzed_node) { struct varpool_node *node = varpool_first_unanalyzed_node, *next; tree decl = node->decl; bool analyzed = node->analyzed; varpool_first_unanalyzed_node->analyzed = true; varpool_first_unanalyzed_node = varpool_first_unanalyzed_node->next_needed; /* 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 (!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) { struct varpool_node *tgt = varpool_node (node->alias_of); struct varpool_node *n; for (n = tgt; n && n->alias; n = n->analyzed ? varpool_alias_aliased_node (n) : NULL) if (n == node) { error ("variable %q+D part of alias cycle", node->decl); node->alias = false; continue; } if (!VEC_length (ipa_ref_t, node->ref_list.references)) ipa_record_reference (NULL, node, NULL, tgt, IPA_REF_ALIAS, NULL); /* C++ FE sometimes change linkage flags after producing same body aliases. */ if (node->extra_name_alias) { DECL_WEAK (node->decl) = DECL_WEAK (node->alias_of); TREE_PUBLIC (node->decl) = TREE_PUBLIC (node->alias_of); DECL_EXTERNAL (node->decl) = DECL_EXTERNAL (node->alias_of); DECL_VISIBILITY (node->decl) = DECL_VISIBILITY (node->alias_of); if (TREE_PUBLIC (node->decl)) { DECL_COMDAT (node->decl) = DECL_COMDAT (node->alias_of); DECL_COMDAT_GROUP (node->decl) = DECL_COMDAT_GROUP (node->alias_of); if (DECL_ONE_ONLY (node->alias_of) && !node->same_comdat_group) { node->same_comdat_group = tgt; if (!tgt->same_comdat_group) tgt->same_comdat_group = node; else { struct varpool_node *n; for (n = tgt->same_comdat_group; n->same_comdat_group != tgt; n = n->same_comdat_group) ; n->same_comdat_group = node; } } } } } else if (DECL_INITIAL (decl)) record_references_in_initializer (decl, analyzed); if (node->same_comdat_group) { for (next = node->same_comdat_group; next != node; next = next->same_comdat_group) varpool_mark_needed_node (next); } changed = true; } timevar_pop (TV_VARPOOL); return changed; }
void emit_support_tinfos (void) { static tree *const fundamentals[] = { &void_type_node, &boolean_type_node, &wchar_type_node, &char_type_node, &signed_char_type_node, &unsigned_char_type_node, &short_integer_type_node, &short_unsigned_type_node, &integer_type_node, &unsigned_type_node, &long_integer_type_node, &long_unsigned_type_node, &long_long_integer_type_node, &long_long_unsigned_type_node, &float_type_node, &double_type_node, &long_double_type_node, 0 }; int ix; tree bltn_type, dtor; push_nested_namespace (abi_node); bltn_type = xref_tag (class_type, get_identifier ("__fundamental_type_info"), /* APPLE LOCAL 4184203 */ /*tag_scope=*/ts_global, false); pop_nested_namespace (abi_node); if (!COMPLETE_TYPE_P (bltn_type)) return; dtor = CLASSTYPE_DESTRUCTORS (bltn_type); if (!dtor || DECL_EXTERNAL (dtor)) return; doing_runtime = 1; for (ix = 0; fundamentals[ix]; ix++) { tree bltn = *fundamentals[ix]; tree types[3]; int i; types[0] = bltn; types[1] = build_pointer_type (bltn); types[2] = build_pointer_type (build_qualified_type (bltn, TYPE_QUAL_CONST)); for (i = 0; i < 3; ++i) { tree tinfo; tinfo = get_tinfo_decl (types[i]); TREE_USED (tinfo) = 1; mark_needed (tinfo); /* APPLE LOCAL begin mainline 4.3 2006-01-10 4871915 */ /* The C++ ABI requires that these objects be COMDAT. But, On systems without weak symbols, initialized COMDAT objects are emitted with internal linkage. (See comdat_linkage for details.) Since we want these objects to have external linkage so that copies do not have to be emitted in code outside the runtime library, we make them non-COMDAT here. It might also not be necessary to follow this detail of the ABI. */ if (!flag_weak || ! targetm.cxx.library_rtti_comdat ()) /* APPLE LOCAL end mainline 4.3 2006-01-10 4871915 */ { gcc_assert (TREE_PUBLIC (tinfo) && !DECL_COMDAT (tinfo)); DECL_INTERFACE_KNOWN (tinfo) = 1; } } } }
void dump_symtab_base (FILE *f, symtab_node node) { static const char * const visibility_types[] = { "default", "protected", "hidden", "internal" }; fprintf (f, "%s/%i (%s)", symtab_node_asm_name (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:"); if (node->symbol.in_other_partition) fprintf (f, " in_other_partition"); if (node->symbol.used_from_other_partition) fprintf (f, " used_from_other_partition"); if (node->symbol.force_output) fprintf (f, " force_output"); if (node->symbol.resolution != LDPR_UNKNOWN) fprintf (f, " %s", ld_plugin_symbol_resolution_names[(int)node->symbol.resolution]); if (TREE_ASM_WRITTEN (node->symbol.decl)) fprintf (f, " asm_written"); if (DECL_EXTERNAL (node->symbol.decl)) fprintf (f, " external"); if (TREE_PUBLIC (node->symbol.decl)) fprintf (f, " public"); if (DECL_COMMON (node->symbol.decl)) fprintf (f, " common"); if (DECL_WEAK (node->symbol.decl)) fprintf (f, " weak"); if (DECL_DLLIMPORT_P (node->symbol.decl)) fprintf (f, " dll_import"); if (DECL_COMDAT (node->symbol.decl)) fprintf (f, " comdat"); if (DECL_COMDAT_GROUP (node->symbol.decl)) fprintf (f, " comdat_group:%s", IDENTIFIER_POINTER (DECL_COMDAT_GROUP (node->symbol.decl))); if (DECL_ONE_ONLY (node->symbol.decl)) fprintf (f, " one_only"); if (DECL_SECTION_NAME (node->symbol.decl)) fprintf (f, " section_name:%s", TREE_STRING_POINTER (DECL_SECTION_NAME (node->symbol.decl))); if (DECL_VISIBILITY_SPECIFIED (node->symbol.decl)) fprintf (f, " visibility_specified"); if (DECL_VISIBILITY (node->symbol.decl)) fprintf (f, " visibility:%s", visibility_types [DECL_VISIBILITY (node->symbol.decl)]); if (DECL_VIRTUAL_P (node->symbol.decl)) fprintf (f, " virtual"); if (DECL_ARTIFICIAL (node->symbol.decl)) fprintf (f, " artificial"); if (TREE_CODE (node->symbol.decl) == FUNCTION_DECL) { if (DECL_STATIC_CONSTRUCTOR (node->symbol.decl)) fprintf (f, " constructor"); if (DECL_STATIC_DESTRUCTOR (node->symbol.decl)) fprintf (f, " destructor"); } fprintf (f, "\n"); if (node->symbol.same_comdat_group) fprintf (f, " Same comdat group as: %s/%i\n", symtab_node_asm_name (node->symbol.same_comdat_group), node->symbol.same_comdat_group->symbol.order); if (node->symbol.next_sharing_asm_name) fprintf (f, " next sharing asm name: %i\n", node->symbol.next_sharing_asm_name->symbol.order); if (node->symbol.previous_sharing_asm_name) fprintf (f, " previous sharing asm name: %i\n", node->symbol.previous_sharing_asm_name->symbol.order); if (node->symbol.address_taken) fprintf (f, " Address is taken.\n"); if (node->symbol.aux) { fprintf (f, " Aux:"); dump_addr (f, " @", (void *)node->symbol.aux); } fprintf (f, " References: "); ipa_dump_references (f, &node->symbol.ref_list); fprintf (f, " Referring: "); ipa_dump_referring (f, &node->symbol.ref_list); }