/* Copyright (C) 2009. Free Software Foundation, Inc. Contributed by Xinliang David Li (davidxl@google.com) and Raksit Ashok (raksit@google.com) This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "tree.h" #include "is-a.h" #include "predict.h" #include "function.h" #include "basic-block.h" #include "stor-layout.h" #include "pointer-set.h" #include "stringpool.h" #include "c-family/c-common.h" #include "toplev.h" #include "langhooks.h" #include "langhooks-def.h" #include "diagnostic.h" #include "debug.h" #include "tree-ssa-alias.h" #include "internal-fn.h" #include "gimple-expr.h" #include "gimple.h" #include "gimple-iterator.h" #include "cgraph.h" #include "l-ipo.h" #include "coverage.h" #include "gcov-io.h" #include "timevar.h" #include "vec.h" #include "params.h" #include "rtl.h" #include "varasm.h" unsigned ggc_total_memory; /* in KB */ struct GTY(()) saved_module_scope { vec *module_decls; unsigned module_id; }; static GTY (()) struct saved_module_scope *current_module_scope; static GTY ((param_is (saved_module_scope))) htab_t saved_module_scope_map; static int primary_module_last_funcdef_no = 0; /* Function id space for each module are qualified by the module id. After all the files are parsed, we need to reset the funcdef_no to the max value from all module so that the function clones do not assigned with ids colliding with some other orignal function in the same module. */ static int max_funcdef_no = 0; static location_t primary_module_last_loc; /* Primary module pending templates. */ /* Referenced asm ids in primary module. */ static GTY (()) vec *referenced_asm_ids = NULL; bool parser_parsing_start = false; /* Nonzero if we're done parsing and into end-of-file activities. */ int at_eof; static int aggr_has_equiv_id (tree t1, tree t2); /* Module scope hash function. */ static hashval_t htab_module_scope_hash (const void *ent) { const struct saved_module_scope *const entry = (const struct saved_module_scope *) ent; return (hashval_t) entry->module_id; } /* Module scope equality function. */ static int htab_module_scope_eq (const void *ent1, const void *ent2) { const struct saved_module_scope *const entry1 = (const struct saved_module_scope *) ent1; const struct saved_module_scope *const entry2 = (const struct saved_module_scope *) ent2; return entry1->module_id == entry2->module_id; } /* Returns the module scope given a module id MOD_ID. */ static struct saved_module_scope * get_module_scope (unsigned mod_id) { struct saved_module_scope **slot, key, *module_scope; gcc_assert (mod_id); if (saved_module_scope_map == NULL) saved_module_scope_map = htab_create_ggc (10, htab_module_scope_hash, htab_module_scope_eq, NULL); key.module_id = mod_id; slot = (struct saved_module_scope **) htab_find_slot (saved_module_scope_map, &key, INSERT); module_scope = *slot; if (!module_scope) { module_scope = ggc_alloc_cleared_saved_module_scope (); module_scope->module_id = mod_id; *slot = module_scope; } return module_scope; } /* Allocate memory for struct lang_decl for tree T. */ static struct lang_decl * alloc_lang_decl (tree t) { size_t size; size = lang_hooks.l_ipo.get_lang_decl_size (t); return ggc_alloc_cleared_lang_decl (size); } /* Return a cloned copy of tree SRC. */ tree lipo_save_decl (tree src) { tree saved = copy_node (src); enum tree_code tc = TREE_CODE (src); if (TREE_CODE_CLASS (tc) == tcc_declaration) { struct lang_decl *ls = NULL; struct function *func = NULL; DECL_CONTEXT (saved) = DECL_CONTEXT (src); if (DECL_LANG_SPECIFIC (src)) { ls = alloc_lang_decl (src); memcpy (ls, DECL_LANG_SPECIFIC (src), lang_hooks.l_ipo.get_lang_decl_size (src)); } DECL_LANG_SPECIFIC (saved) = ls; if (tc == FUNCTION_DECL && DECL_STRUCT_FUNCTION (src)) { func = ggc_alloc_cleared_function (); *func = *(DECL_STRUCT_FUNCTION (src)); DECL_STRUCT_FUNCTION (saved) = func; } } else { gcc_assert (TREE_CODE_CLASS (tc) == tcc_type && TYPE_MAIN_VARIANT (src) == src); TYPE_CONTEXT (saved) = TYPE_CONTEXT (src); lang_hooks.l_ipo.dup_lang_type (src, saved); } return saved; } /* Copy tree SAVED to tree DEST. */ void lipo_restore_decl (tree dest, tree saved) { enum tree_code tc; unsigned old_uid; struct lang_decl *oldls; tc = TREE_CODE (saved); if (TREE_CODE_CLASS (tc) == tcc_declaration) { struct function *oldfunc = NULL; old_uid = DECL_UID (dest); oldls = DECL_LANG_SPECIFIC (dest); oldfunc = (tc == FUNCTION_DECL ? DECL_STRUCT_FUNCTION (dest) : NULL); memcpy ((char *) dest + sizeof (struct tree_common), (char *) saved + sizeof (struct tree_common), sizeof (struct tree_decl_common) - sizeof (struct tree_common)); if (tc == FUNCTION_DECL) memcpy ((char *) dest + sizeof (struct tree_decl_common), (char *) saved + sizeof (struct tree_decl_common), sizeof (struct tree_function_decl) - sizeof (struct tree_decl_common)); DECL_UID (dest) = old_uid; if (DECL_LANG_SPECIFIC (saved)) { if (!oldls) oldls = alloc_lang_decl (dest); memcpy (oldls, DECL_LANG_SPECIFIC (saved), lang_hooks.l_ipo.get_lang_decl_size (saved)); DECL_LANG_SPECIFIC (dest) = oldls; } else DECL_LANG_SPECIFIC (dest) = NULL; if (tc == FUNCTION_DECL) { if (DECL_STRUCT_FUNCTION (saved)) { if (!oldfunc) oldfunc = ggc_alloc_cleared_function (); *oldfunc = *(DECL_STRUCT_FUNCTION (saved)); DECL_STRUCT_FUNCTION (dest) = oldfunc; } else DECL_STRUCT_FUNCTION (dest) = NULL; } } else { gcc_assert (TREE_CODE_CLASS (tc) == tcc_type); lang_hooks.l_ipo.copy_lang_type (saved, dest); } } /* Return the name for tree TD which is either a decl or type. */ tree get_type_or_decl_name (tree td) { tree id; if (DECL_P (td)) id = DECL_NAME (td); else { id = TYPE_NAME (td); if (DECL_P (id)) id = DECL_NAME (id); } return id; } /* For a DECL (a type or a decl) in SCOPE, check to see if it is in global or namespace scope. If yes, add it to the current module scope. */ void add_decl_to_current_module_scope (tree decl, void *scope) { struct saved_module_scope *module_scope; tree id; if (!flag_dyn_ipa) return; if (!parser_parsing_start) { /* The source file may contains only global variable declations -- there is no module grouping data associated with it, so neither primary_module_id nor current_module_id is set. */ lang_hooks.l_ipo.add_built_in_decl (decl); return; } if (!L_IPO_COMP_MODE) return; if (!lang_hooks.l_ipo.has_global_name (decl, scope)) return; /* Unlike C++ where names are attached to type decls, for C, the type name is identifier node. Thus we need to track type names as well. */ id = get_type_or_decl_name (decl); if (!id) return; module_scope = current_module_scope; gcc_assert (module_scope && module_scope->module_id == current_module_id); vec_safe_push (module_scope->module_decls, decl); } /* Clear name bindings for all decls created in MODULE_SCOPE. */ static void clear_module_scope_bindings (struct saved_module_scope *module_scope) { size_t i; tree decl; for (i = 0; vec_safe_iterate (module_scope->module_decls, i, &decl); ++i) { lang_hooks.l_ipo.clear_global_name_bindings ( get_type_or_decl_name (decl)); /* Now force creating assembly name. */ if (VAR_OR_FUNCTION_DECL_P (decl)) { tree assembler_name; if (HAS_DECL_ASSEMBLER_NAME_P (decl) && DECL_ASSEMBLER_NAME_SET_P (decl)) { assembler_name = DECL_ASSEMBLER_NAME (decl); lang_hooks.l_ipo.clear_global_name_bindings (assembler_name); } } } } /* The referenced attribute of a decl is not associated with the decl itself but with the assembler name. Remember the referenced bits before clearing them. */ static void save_assembler_name_reference_bit (void) { varpool_get_referenced_asm_ids (&referenced_asm_ids); } /* Clear the reference bits for assembler names before closing the module scope. */ static void clear_assembler_name_reference_bit (void) { varpool_clear_asm_id_reference_bit (); } /* Restore the reference bits for assembler names. */ static void restore_assembler_name_reference_bit (void) { size_t i; tree nm; for (i = 0; vec_safe_iterate (referenced_asm_ids, i, &nm); ++i) TREE_SYMBOL_REFERENCED (nm) = 1; } /* Set up the module scope before the parsing of the associated source file. */ void push_module_scope (void) { struct saved_module_scope *prev_module_scope; if (!flag_dyn_ipa || !L_IPO_COMP_MODE) { parser_parsing_start = true; return; } prev_module_scope = current_module_scope; if (L_IPO_IS_PRIMARY_MODULE) { gcc_assert (!prev_module_scope); lang_hooks.l_ipo.save_built_in_decl_pre_parsing (); parser_parsing_start = true; } gcc_assert (current_module_id); /* Set up the module scope. */ current_module_scope = get_module_scope (current_module_id); return; } /* Restore the shared decls to their post parsing states. */ static void restore_post_parsing_states (void) { current_module_id = primary_module_id; current_module_scope = get_module_scope (primary_module_id); set_funcdef_no (max_funcdef_no); input_location = primary_module_last_loc; restore_assembler_name_reference_bit (); lang_hooks.l_ipo.restore_built_in_decl_post_module_parsing (); } /* Pop the current module scope (by clearing name bindings etc.) and prepare for parsing of the next module. In particular, built-in decls need to be restored to the state before file parsing starts. */ void pop_module_scope (void) { bool is_last = false; int last_funcdef_no; if (!flag_dyn_ipa || !L_IPO_COMP_MODE) return; gcc_assert (current_module_id && current_module_scope); if (L_IPO_IS_PRIMARY_MODULE) primary_module_last_loc = input_location; at_eof = 1; cgraph_process_same_body_aliases (); lang_hooks.l_ipo.process_pending_decls (input_location); lang_hooks.l_ipo.clear_deferred_fns (); at_eof = 0; is_last = is_last_module (current_module_id); last_funcdef_no = get_last_funcdef_no (); if (last_funcdef_no > max_funcdef_no) max_funcdef_no = last_funcdef_no; lang_hooks.l_ipo.save_built_in_decl_post_module_parsing (); /* Save primary module state if needed (when module group size > 1) */ if (L_IPO_IS_PRIMARY_MODULE && num_in_fnames > 1) { save_assembler_name_reference_bit (); primary_module_last_funcdef_no = last_funcdef_no; } if (!is_last) { /* More aux modules are anticipated, clear the parsing state. */ gcc_assert (num_in_fnames > 1); clear_assembler_name_reference_bit (); clear_module_scope_bindings (current_module_scope); /* Restore symtab bindings for builtins */ lang_hooks.l_ipo.restore_built_in_decl_pre_parsing (); /* The map can not be cleared because the names of operator decls are used to store the information about the conversion target type. This forces the coversion operator ids to be incremented across different modules, and assember id must be used for checksum computation. */ /* cp_clear_conv_type_map (); */ } else if (num_in_fnames > 1) { clear_module_scope_bindings (current_module_scope); restore_post_parsing_states (); } else gcc_assert (L_IPO_IS_PRIMARY_MODULE && num_in_fnames == 1); } /* Type merging support for LIPO */ struct type_ec { tree rep_type; vec *eq_types; }; static vec *pending_types = NULL; static struct pointer_set_t *type_set = NULL; static htab_t type_hash_tab = NULL; /* Hash function for the type table. */ static hashval_t type_hash_hash (const void *ent) { tree type, name; const struct type_ec *const entry = (const struct type_ec *) ent; type = entry->rep_type; name = TYPE_NAME (type); if (DECL_P (name)) name = DECL_NAME (name); return htab_hash_string (IDENTIFIER_POINTER (name)); } /* Equality function for type hash table. */ static int type_hash_eq (const void *ent1, const void *ent2) { tree type1, type2; const struct type_ec *const entry1 = (const struct type_ec *) ent1; const struct type_ec *const entry2 = (const struct type_ec *) ent2; type1 = entry1->rep_type; type2 = entry2->rep_type; return aggr_has_equiv_id (type1, type2); } /* Function to delete type hash entries. */ static void type_hash_del (void *ent) { struct type_ec *const entry = (struct type_ec *) ent; vec_free (entry->eq_types); free (entry); } struct GTY(()) type_ent { tree type; unsigned eq_id; }; static GTY ((param_is (type_ent))) htab_t l_ipo_type_tab = 0; static unsigned l_ipo_eq_id = 0; /* Address hash function for struct type_ent. */ static hashval_t type_addr_hash (const void *ent) { const struct type_ent *const entry = (const struct type_ent *) ent; return (hashval_t) (uintptr_t) entry->type; } /* Address equality function for type_ent. */ static int type_addr_eq (const void *ent1, const void *ent2) { const struct type_ent *const entry1 = (const struct type_ent *) ent1; const struct type_ent *const entry2 = (const struct type_ent *) ent2; return entry1->type == entry2->type; } /* Returns 1 if NS1 and NS2 refer to the same namespace. */ static int is_ns_equiv (tree ns1, tree ns2) { tree n1, n2; if (ns1 == NULL && ns2 == NULL) return 1; if ((!ns1 && ns2) || (ns1 && !ns2)) return 0; gcc_assert (DECL_P (ns1) && DECL_P (ns2)); if (!is_ns_equiv (DECL_CONTEXT (ns1), DECL_CONTEXT (ns2))) return 0; n1 = DECL_NAME (ns1); n2 = DECL_NAME (ns2); if (n1 == 0 && n2 == 0) /* Conservative (which can happen when two NSes are from different modules but with same UID) quivalence is allowed. */ return DECL_UID (ns1) == DECL_UID (ns2); if (!n1 || !n2) return 0; if (!strcmp (IDENTIFIER_POINTER (n1), IDENTIFIER_POINTER (n2))) return 1; return 0; } /* Returns 1 if aggregate type T1 and T2 have equivalent qualified ids. */ static int aggr_has_equiv_id (tree t1, tree t2) { int ctx_match; tree ctx1, ctx2, tn1, tn2; gcc_assert (TYPE_P (t1) && TYPE_P (t2)); ctx1 = TYPE_CONTEXT (t1); ctx2 = TYPE_CONTEXT (t2); if ((ctx1 && !ctx2) || (!ctx1 && ctx2)) return 0; if (ctx1 && TREE_CODE (ctx1) != TREE_CODE (ctx2)) return 0; if (ctx1 && (TREE_CODE (ctx1) == FUNCTION_DECL || TREE_CODE (ctx1) == BLOCK)) return 0; if (!ctx1) { ctx_match = 1; gcc_assert (!ctx2); } else if (TREE_CODE (ctx1) == NAMESPACE_DECL) ctx_match = is_ns_equiv (ctx1, ctx2); else if (TYPE_P (ctx1)) ctx_match = aggr_has_equiv_id (ctx1, ctx2); else { gcc_assert (TREE_CODE (ctx1) == TRANSLATION_UNIT_DECL); ctx_match = 1; } if (!ctx_match) return 0; /* Now compare the name of the types. */ tn1 = TYPE_NAME (t1); tn2 = TYPE_NAME (t2); if ((tn1 && !tn2) || !(tn1 && tn2)) return 0; else if (!tn1 && !tn2) /* Be conservative on unamed types. */ return 1; if (DECL_P (tn1)) tn1 = DECL_NAME (tn1); if (DECL_P (tn2)) tn2 = DECL_NAME (tn2); if (strcmp (IDENTIFIER_POINTER (tn1), IDENTIFIER_POINTER (tn2))) return 0; return lang_hooks.l_ipo.cmp_lang_type (t1, t2); } /* Return the canonical type of the type's main variant. */ static inline tree get_norm_type (const_tree type) { tree cano_type = TYPE_MAIN_VARIANT (type); if (TYPE_CANONICAL (cano_type)) cano_type = TYPE_CANONICAL (cano_type); return cano_type; } /* Return 1 if type T1 and T2 are equivalent. Struct/union/class types are compared using qualified name ids. Alias sets of equivalent types will be merged. Client code may choose to do structural equivalence check for sanity. Note the difference between the types_compatible_p (and its langhooks subroutines) and this interface. The former is mainly used to remove useless type conversion and value numbering computation. It returns 1 only when it is sure and should not be used in contexts where erroneously returning 0 causes problems. This interface lipo_cmp_type behaves differently - it returns 1 when it is not sure -- as the primary purpose of the interface is for alias set computation. */ int lipo_cmp_type (tree t1, tree t2) { if (TREE_CODE (t1) != TREE_CODE (t2)) return 0; if (TYPE_READONLY (t1) != TYPE_READONLY (t2)) return 0; if (TYPE_VOLATILE (t1) != TYPE_VOLATILE (t2)) return 0; t1 = get_norm_type (t1); t2 = get_norm_type (t2); switch (TREE_CODE (t1)) { case RECORD_TYPE: case UNION_TYPE: case QUAL_UNION_TYPE: return aggr_has_equiv_id (t1, t2); case POINTER_TYPE: case REFERENCE_TYPE: case COMPLEX_TYPE: case TYPE_PACK_EXPANSION: return lipo_cmp_type (TREE_TYPE (t1), TREE_TYPE (t2)); case ARRAY_TYPE: return (TYPE_DOMAIN (t1) == NULL || TYPE_DOMAIN (t2) == NULL || (lipo_cmp_type (TYPE_DOMAIN (t1), TYPE_DOMAIN (t2)) && lipo_cmp_type (TREE_TYPE (t1), TREE_TYPE (t2)))); case METHOD_TYPE: return lipo_cmp_type (TYPE_METHOD_BASETYPE (t1), TYPE_METHOD_BASETYPE (t2)); case FUNCTION_TYPE: { tree arg1, arg2; for (arg1 = TYPE_ARG_TYPES (t1), arg2 = TYPE_ARG_TYPES (t2); arg1 && arg2; arg1 = TREE_CHAIN (arg1), arg2 = TREE_CHAIN (arg2)) if (!lipo_cmp_type (TREE_VALUE (arg1), TREE_VALUE (arg2))) return 0; if (arg1 || arg2) return 0; return 1; } case OFFSET_TYPE: return lipo_cmp_type (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2)); case ENUMERAL_TYPE: return lipo_cmp_type (TREE_TYPE (t1), TREE_TYPE (t2)); case REAL_TYPE: case FIXED_POINT_TYPE: case INTEGER_TYPE: return (TYPE_PRECISION (t1) == TYPE_PRECISION (t2) && TYPE_MODE (t1) == TYPE_MODE (t2) && TYPE_MIN_VALUE (t1) == TYPE_MIN_VALUE (t2) && TYPE_MAX_VALUE (t1) == TYPE_MAX_VALUE (t2)); case VECTOR_TYPE: return (TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2) && lipo_cmp_type (TREE_TYPE (t1), TREE_TYPE (t2))); case VOID_TYPE: case BOOLEAN_TYPE: case NULLPTR_TYPE: return 1; case TEMPLATE_TYPE_PARM: return 1; default: gcc_unreachable (); } } #ifndef ANON_AGGRNAME_PREFIX #define ANON_AGGRNAME_PREFIX "__anon_" #endif #ifndef ANON_AGGRNAME_P #define ANON_AGGRNAME_P(ID_NODE) \ (!strncmp (IDENTIFIER_POINTER (ID_NODE), ANON_AGGRNAME_PREFIX, \ sizeof (ANON_AGGRNAME_PREFIX) - 1)) #endif /* Callback function used in tree walk to find referenced struct types. */ static tree find_struct_types (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED) { if (!(*tp)) return NULL_TREE; if (TYPE_P (*tp)) { if (lang_hooks.l_ipo.is_compiler_generated_type (*tp)) return NULL_TREE; switch (TREE_CODE (*tp)) { case RECORD_TYPE: case UNION_TYPE: case QUAL_UNION_TYPE: { tree cano_type, name; tree context; tree field; cano_type = get_norm_type (*tp); name = TYPE_NAME (cano_type); if (!name) { /* the main variant of typedef of unnamed struct has no name, use the orignal type for equivalence. */ cano_type = *tp; name = TYPE_NAME (cano_type); } if (!name) return NULL_TREE; if (DECL_P (name) && (DECL_IGNORED_P (name) || ANON_AGGRNAME_P (DECL_NAME (name)))) return NULL_TREE; if (!pointer_set_insert (type_set, cano_type)) pending_types->safe_push (cano_type); else return NULL_TREE; /* Or use walk tree without dups. */ context = TYPE_CONTEXT (cano_type); if (context && TYPE_P (context)) walk_tree (&context, find_struct_types, NULL, NULL); /* Instantiate a nested work as the tree walker does not get to the fields. */ if (TYPE_BINFO (cano_type)) { int i; tree binfo, base_binfo; for (binfo = TYPE_BINFO (cano_type), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) walk_tree (&BINFO_TYPE (base_binfo), find_struct_types, NULL, NULL); } for (field = TYPE_FIELDS (cano_type); field != 0; field = TREE_CHAIN (field)) walk_tree (&TREE_TYPE (field), find_struct_types, NULL, NULL); return NULL_TREE; } default: return NULL_TREE; } } else if (DECL_P (*tp)) /* walk tree does not walk down decls, so do a nested walk here. */ walk_tree (&(TREE_TYPE (*tp)), find_struct_types, NULL, NULL); return NULL_TREE; } /* Collect referenced struct types. */ static void cgraph_collect_type_referenced (void) { basic_block bb; gimple_stmt_iterator gi; FOR_EACH_BB_FN (bb, cfun) { for (gi = gsi_start_bb (bb); !gsi_end_p (gi); gsi_next (&gi)) { unsigned i; gimple stmt = gsi_stmt (gi); for (i = 0; i < gimple_num_ops (stmt); i++) walk_tree (gimple_op_ptr (stmt, i), find_struct_types, NULL, NULL); } } } /* Check type equivalence. Returns 1 if T1 and T2 are equivalent for tbaa; return 0 if not. -1 is returned if it is unknown. */ int equivalent_struct_types_for_tbaa (const_tree t1, const_tree t2) { struct type_ent key, *tent1, *tent2, **slot; if (!l_ipo_type_tab) return -1; t1 = get_norm_type (t1); t2 = get_norm_type (t2); key.type = (tree) (uintptr_t) t1; slot = (struct type_ent **) htab_find_slot (l_ipo_type_tab, &key, NO_INSERT); if (!slot || !*slot) return -1; tent1 = *slot; key.type = (tree) (uintptr_t) t2; slot = (struct type_ent **) htab_find_slot (l_ipo_type_tab, &key, NO_INSERT); if (!slot || !*slot) return -1; tent2 = *slot; return tent1->eq_id == tent2->eq_id; } /* Build type hash table. */ static void cgraph_build_type_equivalent_classes (void) { unsigned n, i; n = pending_types->length (); for (i = 0; i < n; i++) { struct type_ec **slot; struct type_ec te; te.rep_type = (*pending_types)[i]; te.eq_types = NULL; slot = (struct type_ec **) htab_find_slot (type_hash_tab, &te, INSERT); if (!*slot) { *slot = XCNEW (struct type_ec); (*slot)->rep_type = te.rep_type; vec_alloc ((*slot)->eq_types, 10); } (*slot)->eq_types->safe_push (te.rep_type); } } /* Re-propagate component types's alias set to that of TYPE. PROCESSED is the pointer set of processed types. */ static void re_record_component_aliases (tree type, struct pointer_set_t *processed) { alias_set_type superset = get_alias_set (type); tree field; if (superset == 0) return; if (pointer_set_insert (processed, type)) return; switch (TREE_CODE (type)) { case RECORD_TYPE: case UNION_TYPE: case QUAL_UNION_TYPE: /* Recursively record aliases for the base classes, if there are any. */ if (TYPE_BINFO (type)) { int i; tree binfo, base_binfo; for (binfo = TYPE_BINFO (type), i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) { re_record_component_aliases (BINFO_TYPE (base_binfo), processed); record_alias_subset (superset, get_alias_set (BINFO_TYPE (base_binfo))); } } for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL && !DECL_NONADDRESSABLE_P (field)) { re_record_component_aliases (TREE_TYPE (field), processed); record_alias_subset (superset, get_alias_set (TREE_TYPE (field))); } break; case COMPLEX_TYPE: re_record_component_aliases (TREE_TYPE (type), processed); record_alias_subset (superset, get_alias_set (TREE_TYPE (type))); break; /* VECTOR_TYPE and ARRAY_TYPE share the alias set with their element type. */ default: break; } } /* The callback function to merge alias sets of equivalent types. */ static int type_eq_process (void **slot, void *data ATTRIBUTE_UNUSED) { unsigned i; alias_set_type alias_set, ptr_alias_set = -1; tree rep_type, type; vec *eq_types; struct type_ec ** te = (struct type_ec **)slot; bool zero_set = false, ptr_zero_set = false; struct type_ent **slot2, key, *tent; rep_type = (*te)->rep_type; eq_types = (*te)->eq_types; alias_set = get_alias_set (rep_type); for (i = 0; eq_types->iterate (i, &type); ++i) { alias_set_type als, ptr_als = -1; tree type_ptr = TYPE_POINTER_TO (type);; als = get_alias_set (type); if (als == 0) zero_set = true; if (alias_set && als && alias_set != als) record_alias_subset (alias_set, als); if (type_ptr) { ptr_als = get_alias_set (type_ptr); if (ptr_als == 0) ptr_zero_set = true; if (ptr_alias_set == -1) ptr_alias_set = ptr_als; else { if (!ptr_zero_set && ptr_alias_set != ptr_als) record_alias_subset (ptr_alias_set, ptr_als); } } } /* Now propagate back. */ for (i = 0; eq_types->iterate (i, &type); ++i) { alias_set_type als, ptr_als; tree ptr_type = TYPE_POINTER_TO (type); als = get_alias_set (type); if (zero_set) TYPE_ALIAS_SET (type) = 0; else if (alias_set != als) record_alias_subset (als, alias_set); if (ptr_type) { ptr_als = get_alias_set (ptr_type); if (ptr_zero_set) TYPE_ALIAS_SET (ptr_type) = 0; else if (ptr_alias_set != ptr_als) record_alias_subset (ptr_als, ptr_alias_set); } } /* Now populate the type table. */ l_ipo_eq_id++; for (i = 0; eq_types->iterate (i, &type); ++i) { key.type = type; slot2 = (struct type_ent **) htab_find_slot (l_ipo_type_tab, &key, INSERT); tent = *slot2; gcc_assert (!tent); tent = ggc_alloc_cleared_type_ent (); tent->type = key.type; tent->eq_id = l_ipo_eq_id; *slot2 = tent; } return 1; } /* Regenerate alias set for aggregate types. */ static void record_components_for_parent_types (void) { unsigned n, i; struct pointer_set_t *processed_types; processed_types = pointer_set_create (); n = pending_types->length (); for (i = 0; i < n; i++) { tree type = (*pending_types)[i]; re_record_component_aliases (type, processed_types); } pointer_set_destroy (processed_types); } /* Unify type alias sets for equivalent types. */ void cgraph_unify_type_alias_sets (void) { struct cgraph_node *node; struct varpool_node *pv; /* Only need to do type unification when we are in LIPO mode and have a non-trivial module group (size is >1). However, override the size check under non-zero PARAM_LIPO_RANDOM_GROUP_SIZE, which indicates that we are stress-testing LIPO. In that case try to flush out problems with type unification by always performing it. */ if (!L_IPO_COMP_MODE || (num_in_fnames == 1 && PARAM_VALUE (PARAM_LIPO_RANDOM_GROUP_SIZE) == 0)) return; vec_alloc (pending_types, 100); type_set = pointer_set_create (); type_hash_tab = htab_create (10, type_hash_hash, type_hash_eq, type_hash_del); l_ipo_type_tab = htab_create_ggc (10, type_addr_hash, type_addr_eq, NULL); FOR_EACH_DEFINED_FUNCTION (node) { if (!gimple_has_body_p (node->decl)) continue; push_cfun (DECL_STRUCT_FUNCTION (node->decl)); current_function_decl = node->decl; if (gimple_has_body_p (current_function_decl)) cgraph_collect_type_referenced (); current_function_decl = NULL; set_cfun (NULL); pop_cfun (); } FOR_EACH_VARIABLE (pv) walk_tree (&pv->decl, find_struct_types, NULL, NULL); /* Compute type equivalent classes. */ cgraph_build_type_equivalent_classes (); /* Now unify alias sets of equivelent types. */ htab_traverse (type_hash_tab, type_eq_process, NULL); /* Finally re-populating parent's alias set. */ record_components_for_parent_types (); pointer_set_destroy (type_set); vec_free (pending_types); htab_delete (type_hash_tab); } /* Return true if DECL is an artificial function that we do not want to promote and which may not be available in the primary module. The sole exception is currently __tls_init. */ static bool decl_artificial_nopromote (tree decl) { if (!DECL_ARTIFICIAL (decl)) return false; /* Handle the __tls_init function specially as we do want to promote it and allow the aux module to be resolved to the version in the primary module. We check if it is prefixed by __tls_init to catch it after promotion as well from cgraph_is_aux_decl_external. */ if (!strncmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), "__tls_init", 10)) return false; return true; } /* Return true if NODE->decl from an auxiliary module has external definition (and therefore is not needed for expansion). */ bool cgraph_is_aux_decl_external (struct cgraph_node *node) { tree decl = node->decl; if (!L_IPO_COMP_MODE) return false; if (!cgraph_is_auxiliary (decl)) return false; /* Versioned clones from auxiliary moduels are not external. */ if (node->is_versioned_clone) return false; /* Comdat or weak functions in aux modules are not external -- there is no guarantee that the definitition will be emitted in the primary compilation of this auxiliary module. Functions marked artificial (e.g. an implicitly instantiated virtual destructor) are also not guaranteed to be available in the primary module, as they are not promoted by process_module_scope_static_func. */ if (DECL_COMDAT (decl) || DECL_WEAK (decl) || decl_artificial_nopromote (decl)) return false; /* virtual functions won't be deleted in the primary module. */ if (DECL_VIRTUAL_P (decl)) return true; if (!TREE_PUBLIC (decl)) return false; /* The others from aux modules are external. */ return true; } /* Linked function symbol (cgraph node) table. */ static GTY((param_is (cgraph_sym))) htab_t cgraph_symtab; /* This is true when global linking is needed and performed (for C++). For C, symbol linking is performed on the fly during parsing, and the cgraph_symtab is used only for keeping additional information for any already merged symbol if needed. */ static bool global_link_performed = 0; /* For an external (non-defined) function DECL, return the primary module id (even though when the declaration is declared in an aux module). For a defined function DECL, return the module id in which it is defined. */ unsigned cgraph_get_module_id (tree decl) { struct function *func = DECL_STRUCT_FUNCTION (decl); /* Not defined. */ if (!func) return primary_module_id; return FUNC_DECL_MODULE_ID (func); } /* Return true if function decl is defined in an auxiliary module. */ bool cgraph_is_auxiliary (tree decl) { return (cgraph_get_module_id (decl) != primary_module_id); } /* Return the hash value for cgraph_sym pointed to by P. The hash value is computed using function's assembler name. */ static hashval_t hash_sym_by_assembler_name (const void *p) { const struct cgraph_sym *n = (const struct cgraph_sym *) p; return (hashval_t) decl_assembler_name_hash (n->assembler_name); } /* Return nonzero if P1 and P2 are equal. */ static int eq_assembler_name (const void *p1, const void *p2) { const struct cgraph_sym *n1 = (const struct cgraph_sym *) p1; const_tree name = (const_tree) p2; return (decl_assembler_name_equal (n1->rep_decl, name)); } /* Return the cgraph_sym for function declaration DECL. */ static struct cgraph_sym ** cgraph_sym (tree decl) { struct cgraph_sym **slot; tree name; if (!cgraph_symtab) { gcc_assert (!global_link_performed); return NULL; } name = DECL_ASSEMBLER_NAME (decl); slot = (struct cgraph_sym **) htab_find_slot_with_hash (cgraph_symtab, name, decl_assembler_name_hash (name), NO_INSERT); return slot; } /* Return the representative declaration for assembler name ASM_NAME. */ tree cgraph_find_decl (tree asm_name) { struct cgraph_sym **slot; if (!L_IPO_COMP_MODE) return NULL; if (!cgraph_symtab || !global_link_performed) return NULL; slot = (struct cgraph_sym **) htab_find_slot_with_hash (cgraph_symtab, asm_name, decl_assembler_name_hash (asm_name), NO_INSERT); if (!slot || !*slot) return NULL; return (*slot)->rep_node->decl; } /* Return true if function declaration DECL is originally file scope static, which is promoted to global scope. */ bool cgraph_is_promoted_static_func (tree decl) { struct cgraph_sym ** sym; gcc_assert (L_IPO_COMP_MODE); /* cgraph_symtab will be created when any symbol got promoted. */ if (!cgraph_symtab) return false; sym = cgraph_sym (decl); if (!sym) return false; return (*sym)->is_promoted_static; } /* Hash function for module information table. ENT is a pointer to a cgraph_module_info. */ static hashval_t htab_sym_hash (const void *ent) { const struct cgraph_mod_info * const mi = (const struct cgraph_mod_info * const ) ent; return (hashval_t) mi->module_id; } /* Hash equality function for module information table. */ static int htab_sym_eq (const void *ent1, const void *ent2) { const struct cgraph_mod_info * const mi1 = (const struct cgraph_mod_info * const ) ent1; const struct cgraph_mod_info * const mi2 = (const struct cgraph_mod_info * const ) ent2; return (mi1->module_id == mi2->module_id); } /* cgraph_sym SYM may be defined in more than one source modules. Add declaration DECL's definiting module to SYM. */ static void add_define_module (struct cgraph_sym *sym, tree decl) { unsigned module_id; struct cgraph_mod_info **slot; struct cgraph_mod_info mi; struct function *f = DECL_STRUCT_FUNCTION (decl); if (!f) return; module_id = FUNC_DECL_MODULE_ID (f); if (!sym->def_module_hash) sym->def_module_hash = htab_create_ggc (10, htab_sym_hash, htab_sym_eq, NULL); mi.module_id = module_id; slot = (struct cgraph_mod_info **)htab_find_slot (sym->def_module_hash, &mi, INSERT); if (!*slot) { *slot = ggc_alloc_cleared_cgraph_mod_info (); (*slot)->module_id = module_id; } else gcc_assert ((*slot)->module_id == module_id); } static int add_def_module (void **slot, void *data) { struct cgraph_mod_info **m = (struct cgraph_mod_info **)slot; htab_t mod_set = (htab_t) data; struct cgraph_mod_info **new_slot; new_slot = (struct cgraph_mod_info **)htab_find_slot (mod_set, *m, INSERT); if (!*new_slot) { *new_slot = ggc_alloc_cleared_cgraph_mod_info (); (*new_slot)->module_id = (*m)->module_id; } else gcc_assert ((*new_slot)->module_id == (*m)->module_id); return 1; } /* Clone defined module hash table from ORIG to CLONE. */ void copy_defined_module_set (tree clone, tree orig) { struct cgraph_sym **orig_sym, **clone_sym; orig_sym = cgraph_sym (orig); clone_sym = cgraph_sym (clone); if (!orig_sym || !(*orig_sym)->def_module_hash) return; if (!(*clone_sym)->def_module_hash) (*clone_sym)->def_module_hash = htab_create_ggc (10, htab_sym_hash, htab_sym_eq, NULL); htab_traverse ((*orig_sym)->def_module_hash, add_def_module, (*clone_sym)->def_module_hash); } /* Return true if the symbol associated with DECL is defined in module MODULE_ID. This interface is used by the inliner to make sure profile-gen and profile-use pass (L-IPO mode) make consistent inline decision. */ bool cgraph_is_inline_body_available_in_module (tree decl, unsigned module_id) { struct cgraph_sym **sym; void **slot; struct cgraph_mod_info mi; gcc_assert (L_IPO_COMP_MODE); if (DECL_BUILT_IN (decl)) return true; /* TODO: revisit this. */ if (DECL_IN_SYSTEM_HEADER (decl) && DECL_DECLARED_INLINE_P (decl)) return true; gcc_assert (TREE_STATIC (decl) || DECL_DECLARED_INLINE_P (decl)); if (cgraph_get_module_id (decl) == module_id) return true; sym = cgraph_sym (decl); if (!sym || !(*sym)->def_module_hash) return false; mi.module_id = module_id; slot = htab_find_slot ((*sym)->def_module_hash, &mi, NO_INSERT); if (slot) { gcc_assert (((struct cgraph_mod_info*)*slot)->module_id == module_id); return true; } return false; } /* Return the linked cgraph node using DECL's assembler name. DO_ASSERT is a flag indicating that a non null link target must be returned. */ struct cgraph_node * cgraph_lipo_get_resolved_node_1 (tree decl, bool do_assert) { struct cgraph_sym **slot; /* Handle alias decl. */ slot = cgraph_sym (decl); if (!slot || !*slot) { if (!do_assert) return NULL; else { /* Nodes that are indirectly called are not 'reachable' in the callgraph. If they are not needed (comdat, inline extern etc), they may be removed from the link table before direct calls to them are exposed (via indirect call promtion by const folding etc). When this happens, the node will need to be relinked. A probably better fix is to modify the callgraph so that they are not eliminated in the first place -- this will allow inlining to happen. */ struct cgraph_node *n = cgraph_get_create_node (decl); if (!n->analyzed) { gcc_assert (DECL_EXTERNAL (decl) || cgraph_is_aux_decl_external (n) || DECL_VIRTUAL_P (decl)); gcc_assert (/* This is the case for explicit extern instantiation, when cgraph node is not created before link. */ DECL_EXTERNAL (decl)); cgraph_link_node (n); return n; } else gcc_unreachable (); } } else { struct cgraph_sym *sym = *slot; return sym->rep_node; } } /* Return the cgraph_node of DECL if decl has definition; otherwise return the cgraph node of the representative decl, which is the declaration DECL is resolved to after linking/symbol resolution. */ struct cgraph_node * cgraph_lipo_get_resolved_node (tree decl) { struct cgraph_node *node = NULL; gcc_assert (L_IPO_COMP_MODE && global_link_performed); gcc_assert (cgraph_symtab); /* Never merged. */ if (!TREE_PUBLIC (decl) || DECL_ARTIFICIAL (decl) /* builtin function decls are shared across modules, but 'linking' is still performed for them to keep track of the set of defining modules. Skip the real resolution here to avoid merging '__builtin_xxx' with 'xxx'. */ || DECL_BUILT_IN (decl)) return cgraph_get_create_node (decl); node = cgraph_lipo_get_resolved_node_1 (decl, true); return node; } /* When NODE->decl is dead function eliminated, remove the entry in the link table. */ void cgraph_remove_link_node (struct cgraph_node *node) { tree name, decl; if (!L_IPO_COMP_MODE || !cgraph_symtab) return; decl = node->decl; /* Skip nodes that are not in the link table. */ if (!TREE_PUBLIC (decl) || DECL_ARTIFICIAL (decl)) return; /* Skip if node is an inline clone or if the node has defintion that is not really resolved to the merged node. */ if (cgraph_lipo_get_resolved_node_1 (decl, false) != node) return; name = DECL_ASSEMBLER_NAME (decl); htab_remove_elt_with_hash (cgraph_symtab, name, decl_assembler_name_hash (name)); } /* Return true if the function body for DECL has profile information. */ static bool has_profile_info (tree decl) { gcov_type *ctrs = NULL; unsigned n; struct function* f = DECL_STRUCT_FUNCTION (decl); ctrs = get_coverage_counts_no_warn (f, GCOV_COUNTER_ARCS, &n); if (ctrs) { unsigned i; for (i = 0; i < n; i++) if (ctrs[i]) return true; } return false; } /* Resolve delaration NODE->decl for function symbol *SLOT. */ static void resolve_cgraph_node (struct cgraph_sym **slot, struct cgraph_node *node) { tree decl1, decl2; int decl1_defined = 0; int decl2_defined = 0; decl1 = (*slot)->rep_decl; decl2 = node->decl; decl1_defined = gimple_has_body_p (decl1); decl2_defined = gimple_has_body_p (decl2); if (decl1_defined && !decl2_defined) return; if (!decl1_defined && decl2_defined) { (*slot)->rep_node = node; (*slot)->rep_decl = decl2; add_define_module (*slot, decl2); return; } if (decl2_defined) { bool has_prof1 = false; bool has_prof2 = false; gcc_assert (decl1_defined); add_define_module (*slot, decl2); /* Pick the node that cannot be removed, to avoid a situation where we remove the resolved node and later try to access it for the remaining non-removable copy. E.g. one may be extern and the other weak, only the extern copy can be removed. */ if (cgraph_can_remove_if_no_direct_calls_and_refs_p ((*slot)->rep_node) && !cgraph_can_remove_if_no_direct_calls_and_refs_p (node)) { (*slot)->rep_node = node; (*slot)->rep_decl = decl2; return; } /* Similarly, pick the non-external symbol, since external symbols may be eliminated by symtab_remove_unreachable_nodes after ipa inlining (see process_references). */ if (DECL_EXTERNAL (decl1) && !DECL_EXTERNAL (decl2)) { (*slot)->rep_node = node; (*slot)->rep_decl = decl2; return; } has_prof1 = has_profile_info (decl1); bool is_aux1 = cgraph_is_auxiliary (decl1); bool is_aux2 = cgraph_is_auxiliary (decl2); /* Pick the copy from the primary module if multiple copies have profile. */ if (has_prof1 && (!is_aux1 || is_aux2)) return; has_prof2 = has_profile_info (decl2); if (has_prof2) { (*slot)->rep_node = node; (*slot)->rep_decl = decl2; } return; } /* Handle aliases properly. Make sure the alias symbol resolution is consistent with alias target */ if (node->alias && !node->thunk.thunk_p) { struct cgraph_node *decl2_tgt = cgraph_function_or_thunk_node (node, NULL); if (cgraph_lipo_get_resolved_node_1 (decl2_tgt->decl, false) == decl2_tgt) { (*slot)->rep_node = node; (*slot)->rep_decl = decl2; } } return; } /* Resolve NODE->decl in the function symbol table. */ struct cgraph_sym * cgraph_link_node (struct cgraph_node *node) { void **slot; tree name; if (!L_IPO_COMP_MODE) return NULL; if (!cgraph_symtab) return NULL; /* Skip the cases when the defintion can be locally resolved, and when we do not need to keep track of defining modules. */ if (!TREE_PUBLIC (node->decl) || DECL_ARTIFICIAL (node->decl)) return NULL; name = DECL_ASSEMBLER_NAME (node->decl); slot = htab_find_slot_with_hash (cgraph_symtab, name, decl_assembler_name_hash (name), INSERT); if (*slot) resolve_cgraph_node ((struct cgraph_sym **) slot, node); else { struct cgraph_sym *sym = ggc_alloc_cleared_cgraph_sym (); sym->rep_node = node; sym->rep_decl = node->decl; sym->assembler_name = name; add_define_module (sym, node->decl); *slot = sym; } return (struct cgraph_sym *) *slot; } /* Perform cross module linking of function declarations. */ void cgraph_do_link (void) { struct cgraph_node *node; if (!L_IPO_COMP_MODE) return; global_link_performed = 1; gcc_assert (cgraph_pre_profiling_inlining_done); if (!cgraph_symtab) cgraph_symtab = htab_create_ggc (10, hash_sym_by_assembler_name, eq_assembler_name, NULL); FOR_EACH_FUNCTION (node) { gcc_assert (!node->global.inlined_to); /* Delay aliases */ if (node->alias && !node->thunk.thunk_p) continue; cgraph_link_node (node); } /* Now handle aliases */ FOR_EACH_FUNCTION (node) { if (node->alias && !node->thunk.thunk_p) cgraph_link_node (node); } } struct promo_ent { char* assemb_name; tree decl; int seq; }; /* Hash function for promo_ent table. */ static hashval_t promo_ent_hash (const void *ent) { const struct promo_ent *const entry = (const struct promo_ent *) ent; return htab_hash_string (entry->assemb_name); } /* Hash_eq function for promo_ent table. */ static int promo_ent_eq (const void *ent1, const void *ent2) { const struct promo_ent *const entry1 = (const struct promo_ent *) ent1; const struct promo_ent *const entry2 = (const struct promo_ent *) ent2; if (!strcmp (entry1->assemb_name, entry2->assemb_name)) return 1; return 0; } /* Delete function for promo_ent hash table. */ static void promo_ent_del (void *ent) { struct promo_ent *const entry = (struct promo_ent *) ent; free (entry->assemb_name); free (entry); } static htab_t promo_ent_hash_tab = NULL; /* Make the var decl for weak symbol as extern. */ static inline void externalize_weak_decl (tree decl) { gcc_assert (TREE_CODE (decl) == VAR_DECL && DECL_WEAK (decl)); DECL_EXTERNAL (decl) = 1; TREE_STATIC (decl) = 0; DECL_INITIAL (decl) = NULL; /* Keep the context so that devirt_variable_node_removal_hook can do cleanup properly for vtables. DECL_CONTEXT (decl) = NULL; */ } /* Return a unique sequence number for NAME. This is needed to avoid name conflict -- function scope statics may have identical names. When DECL is NULL, this function returns a zero sequence number if it is called with a particular NAME for the first time, and non-zero otherwise. This fact is used to keep track of unseen weak variables. When DECL is not NULL, this function is supposed to be called by varpool_remove_duplicate_weak_decls. */ static int get_name_seq_num (const char *name, tree decl) { struct promo_ent **slot; struct promo_ent ent; int ret = 0; gcc_assert (!decl || TREE_CODE (decl) == VAR_DECL); ent.assemb_name = xstrdup (name); ent.seq = 0; slot = (struct promo_ent **) htab_find_slot (promo_ent_hash_tab, &ent, INSERT); if (!*slot) { *slot = XCNEW (struct promo_ent); (*slot)->assemb_name = ent.assemb_name; (*slot)->decl = decl; } else { /* During output, the previously selected weak decl may not be referenced by any function that is expanded thus they do not have DECL_RTL_SET_P to be true and therefore can be eliminated by varpool_remove_unreferenced_decls later. To avoid that, logic is added to replace previously selected decl when needed. */ if (decl && DECL_RTL_SET_P (decl) && !DECL_RTL_SET_P ((*slot)->decl)) { externalize_weak_decl ((*slot)->decl); (*slot)->decl = decl; ret = 0; } else ret = ++(*slot)->seq; free (ent.assemb_name); } return ret; } /* Returns a unique assembler name for DECL. */ static tree create_unique_name (tree decl, unsigned module_id) { tree id, assemb_id; char *assembler_name; const char *name; struct function *context = NULL; int seq = 0; if (TREE_CODE (decl) == FUNCTION_DECL) { if (!DECL_CONTEXT (decl) || TREE_CODE (DECL_CONTEXT (decl)) == TRANSLATION_UNIT_DECL) { id = DECL_NAME (decl); /* if (IDENTIFIER_OPNAME_P (id)) */ if (TREE_LANG_FLAG_2 (id)) id = DECL_ASSEMBLER_NAME (decl); } else id = DECL_ASSEMBLER_NAME (decl); } else { if (!DECL_CONTEXT (decl)) id = DECL_NAME (decl); else if (TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL) id = DECL_ASSEMBLER_NAME (decl); else if (TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) { id = DECL_NAME (decl); context = DECL_STRUCT_FUNCTION (DECL_CONTEXT (decl)); } else /* file scope context */ id = DECL_NAME (decl); } name = IDENTIFIER_POINTER (id); if (context) { char *n; unsigned fno = FUNC_DECL_FUNC_ID (context); n = (char *)alloca (strlen (name) + 15); sprintf (n, "%s.%u", name, fno); name = n; } assembler_name = (char*) alloca (strlen (name) + 30); sprintf (assembler_name, "%s.cmo.%u", name, module_id); seq = get_name_seq_num (assembler_name, NULL); if (seq) sprintf (assembler_name, "%s.%d", assembler_name, seq); assemb_id = get_identifier (assembler_name); return assemb_id; } /* Promote DECL to be global. MODULE_ID is the id of the module where DECL is defined. IS_EXTERN is a flag indicating if externalization is needed. */ static void promote_static_var_func (unsigned module_id, tree decl, bool is_extern) { tree assemb_id; tree alias; /* No need to promote symbol alias. */ alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl)); if (alias) return; /* Function decls in C++ may contain characters not taken by assembler. Similarly, function scope static variable has UID as the assembler name suffix which is not consistent across modules. */ assemb_id = create_unique_name (decl, module_id); if (DECL_ASSEMBLER_NAME_SET_P (decl)) { if (TREE_CODE (decl) == FUNCTION_DECL) unlink_from_assembler_name_hash (cgraph_get_create_node (decl), false); else unlink_from_assembler_name_hash (varpool_get_node (decl), false); } SET_DECL_ASSEMBLER_NAME (decl, assemb_id); TREE_PUBLIC (decl) = 1; DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; DECL_VISIBILITY_SPECIFIED (decl) = 1; if (TREE_CODE (decl) == FUNCTION_DECL) { struct cgraph_node *node = cgraph_get_create_node (decl); node->resolution = LDPR_UNKNOWN; insert_to_assembler_name_hash (node, false); } else { struct varpool_node *node = varpool_get_node (decl); node->resolution = LDPR_UNKNOWN; /* Statics from exported primary module are very likely referenced by other modules, so they should be made externally visible (to be avoided to be localized again). Another way to do this is to set force_output bit or change the logic in varpool_externally_visible in ipa.c. */ if (!is_extern) { node->resolution = LDPR_PREVAILING_DEF; node->externally_visible = true; } varpool_link_node (node); insert_to_assembler_name_hash (node, false); /* Possibly update the RTL name as well. */ if (DECL_RTL_SET_P (decl)) XSTR (XEXP (DECL_RTL (decl), 0), 0) = IDENTIFIER_POINTER (assemb_id); } if (is_extern) { if (TREE_CODE (decl) == VAR_DECL) { TREE_STATIC (decl) = 0; DECL_EXTERNAL (decl) = 1; /* Keep the initializer to allow const prop. */ /* DECL_INITIAL (decl) = 0; */ /* Keep the context so that devirt_variable_node_removal_hook can do cleanup properly for vtables. DECL_CONTEXT (decl) = 0; */ } /* else Function body will be deleted later before expansion. */ } else TREE_STATIC (decl) = 1; } /* Externalize global variables from aux modules and promote static variables. WEAK variables are treated especially in varpool_remove_duplicate_weak_decls. */ static void process_module_scope_static_var (struct varpool_node *vnode) { tree decl = vnode->decl; if (varpool_is_auxiliary (vnode)) { gcc_assert (vnode->module_id != primary_module_id); if (TREE_PUBLIC (decl)) { /* Externalize non-weak variables. */ if (!DECL_WEAK (decl)) { DECL_EXTERNAL (decl) = 1; TREE_STATIC (decl) = 0; /* Keep the initializer to allow const prop. */ /* DECL_INITIAL (decl) = NULL; */ if (DECL_CONTEXT (decl)) { DECL_ASSEMBLER_NAME (decl); } /* Keep the context so that devirt_variable_node_removal_hook can do cleanup properly for vtables. DECL_CONTEXT (decl) = NULL; */ } } else { /* Promote static vars to global. */ if (vnode->module_id) promote_static_var_func (vnode->module_id, decl, varpool_is_auxiliary (vnode)); } } else { if (PRIMARY_MODULE_EXPORTED && !TREE_PUBLIC (decl)) promote_static_var_func (vnode->module_id, decl, varpool_is_auxiliary (vnode)); } } /* Promote all aliases of CNODE. */ static void promote_function_aliases (struct cgraph_node *cnode, unsigned mod_id, bool is_extern) { int i; struct ipa_ref *ref; for (i = 0; ipa_ref_list_referring_iterate (&cnode->ref_list, i, ref); i++) { if (ref->use == IPA_REF_ALIAS) { struct cgraph_node *alias = ipa_ref_referring_node (ref); tree alias_decl = alias->decl; /* Should assert */ if (cgraph_get_module_id (alias_decl) == mod_id) promote_static_var_func (mod_id, alias_decl, is_extern); } } } /* Promote static function CNODE->decl to be global. */ static void process_module_scope_static_func (struct cgraph_node *cnode) { tree decl = cnode->decl; bool addr_taken; unsigned mod_id; struct ipa_ref *ref; int i; if (TREE_PUBLIC (decl) || !TREE_STATIC (decl) || DECL_EXTERNAL (decl) || decl_artificial_nopromote (decl)) return; if (flag_ripa_no_promote_always_inline && lookup_attribute ("always_inline", DECL_ATTRIBUTES (decl)) != NULL) return; /* Can be local -- the promotion pass need to be done after callgraph build when address taken bit is set. */ addr_taken = cnode->address_taken; if (!addr_taken) { for (i = 0; ipa_ref_list_referring_iterate (&cnode->ref_list, i, ref); i++) if (ref->use == IPA_REF_ALIAS) { struct cgraph_node *alias = ipa_ref_referring_node (ref); if (alias->address_taken) addr_taken = true; } } if (!addr_taken) { tree assemb_id = create_unique_name (decl, cgraph_get_module_id (decl)); if (DECL_ASSEMBLER_NAME_SET_P (decl)) unlink_from_assembler_name_hash (cnode, false); SET_DECL_ASSEMBLER_NAME (decl, assemb_id); insert_to_assembler_name_hash (cnode, false); return; } mod_id = cgraph_get_module_id (decl); if (cgraph_is_auxiliary (decl)) { gcc_assert (mod_id != primary_module_id); /* Promote static function to global. */ if (mod_id) { promote_static_var_func (mod_id, decl, 1); promote_function_aliases (cnode, mod_id, 1); } } else { if (PRIMARY_MODULE_EXPORTED /* skip static_init routines. */ && !DECL_ARTIFICIAL (decl)) { promote_static_var_func (mod_id, decl, 0); promote_function_aliases (cnode, mod_id, 0); } } } /* Process var_decls, func_decls with static storage. */ void cgraph_process_module_scope_statics (void) { struct cgraph_node *pf; struct varpool_node *pv; if (!L_IPO_COMP_MODE) return; promo_ent_hash_tab = htab_create (10, promo_ent_hash, promo_ent_eq, promo_ent_del); /* Process variable first. */ FOR_EACH_DEFINED_VARIABLE (pv) process_module_scope_static_var (pv); FOR_EACH_FUNCTION (pf) process_module_scope_static_func (pf); htab_delete (promo_ent_hash_tab); } /* There could be duplicate non-extern WEAK decls in the varpool queue, coming from different modules. All but one of these need to be externalized and removed from the varpool queue. Duplicate WEAK decls can be added to varpool queue as late as cgraph_expand_function, when a WEAK decl is marked referenced as assembler is being output. Therefore, a call to this function should be made after cgraph_expand_function. */ void varpool_remove_duplicate_weak_decls (void) { struct varpool_node *node = NULL; if (!L_IPO_COMP_MODE) return; promo_ent_hash_tab = htab_create (10, promo_ent_hash, promo_ent_eq, promo_ent_del); FOR_EACH_VARIABLE (node) { tree decl = node->decl; if (TREE_PUBLIC (decl) && DECL_WEAK (decl) && !DECL_EXTERNAL (decl) && get_name_seq_num (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), decl)) externalize_weak_decl (decl); } htab_delete (promo_ent_hash_tab); } static GTY((param_is (symtab_node))) htab_t varpool_symtab; /* Hash function for varpool node. */ static hashval_t hash_node_by_assembler_name (const void *p) { const struct varpool_node *n = (const struct varpool_node *) p; return (hashval_t) decl_assembler_name_hash ( DECL_ASSEMBLER_NAME (n->decl)); } /* Returns nonzero if P1 and P2 are equal. */ static int eq_node_assembler_name (const void *p1, const void *p2) { const struct varpool_node *n1 = (const struct varpool_node *) p1; const_tree name = (const_tree)p2; return (decl_assembler_name_equal (n1->decl, name)); } /* Return true if NODE's decl is declared in an auxiliary module. */ bool varpool_is_auxiliary (struct varpool_node *node) { return (node->module_id && node->module_id != primary_module_id); } /* Return the varpool_node to which DECL is resolved to during linking. This method can not be used after static to global promotion happens. */ static struct varpool_node * real_varpool_node_1 (tree decl, bool assert) { void **slot; tree name; if (!L_IPO_COMP_MODE || !varpool_symtab) return varpool_get_node (decl); if (!TREE_PUBLIC (decl) || DECL_ARTIFICIAL (decl)) return varpool_get_node (decl); name = DECL_ASSEMBLER_NAME (decl); slot = htab_find_slot_with_hash (varpool_symtab, name, decl_assembler_name_hash (name), NO_INSERT); if (!slot) { gcc_assert (!assert); return NULL; } gcc_assert (slot && *slot); return (struct varpool_node *)*slot; } struct varpool_node * real_varpool_node (tree decl) { return real_varpool_node_1 (decl, true); } /* Remove NODE from the link table. */ void varpool_remove_link_node (struct varpool_node *node) { tree name; tree decl; if (!L_IPO_COMP_MODE || !varpool_symtab) return; decl = node->decl; if (!TREE_PUBLIC (decl) || DECL_ARTIFICIAL (decl)) return; if (real_varpool_node_1 (decl, false) != node) return; name = DECL_ASSEMBLER_NAME (decl); htab_remove_elt_with_hash (varpool_symtab, name, decl_assembler_name_hash (name)); } /* Merge the addressable attribute from DECL2 to DECL1. */ static inline void merge_addressable_attr (tree decl1, tree decl2) { if (TREE_ADDRESSABLE (decl2)) TREE_ADDRESSABLE (decl1) = 1; } /* Resolve NODE->decl to symbol table entry *SLOT. */ static void resolve_varpool_node (struct varpool_node **slot, struct varpool_node *node) { tree decl1, decl2; decl1 = (*slot)->decl; decl2 = node->decl; /* Take the decl with the complete type. */ if (COMPLETE_TYPE_P (TREE_TYPE (decl1)) && !COMPLETE_TYPE_P (TREE_TYPE (decl2))) { merge_addressable_attr (decl1, decl2); return; } if (!COMPLETE_TYPE_P (TREE_TYPE (decl1)) && COMPLETE_TYPE_P (TREE_TYPE (decl2))) { *slot = node; merge_addressable_attr (decl2, decl1); return; } if (DECL_INITIAL (decl1) && !DECL_INITIAL (decl2)) { merge_addressable_attr (decl1, decl2); return; } if (!DECL_INITIAL (decl1) && DECL_INITIAL (decl2)) { *slot = node; merge_addressable_attr (decl2, decl1); return; } /* Either all complete or neither's type is complete. Just pick the primary module's decl. */ if (!varpool_is_auxiliary (*slot)) { merge_addressable_attr (decl1, decl2); return; } if (!varpool_is_auxiliary (node)) { *slot = node; merge_addressable_attr (decl2, decl1); return; } merge_addressable_attr (decl1, decl2); return; } /* Link NODE into var_decl symbol table. */ void varpool_link_node (struct varpool_node *node) { tree name; void **slot; if (!L_IPO_COMP_MODE || !varpool_symtab) return; if (!TREE_PUBLIC (node->decl) || DECL_ARTIFICIAL (node->decl)) return; name = DECL_ASSEMBLER_NAME (node->decl); slot = htab_find_slot_with_hash (varpool_symtab, name, decl_assembler_name_hash (name), INSERT); if (*slot) resolve_varpool_node ((struct varpool_node **) slot, node); else *slot = node; } /* Fixup references of VNODE. */ static void fixup_reference_list (struct varpool_node *node) { int i; struct ipa_ref *ref; struct ipa_ref_list *list = &node->ref_list; vec new_refered; vec new_refered_type; struct symtab_node *sym_node; enum ipa_ref_use use_type = IPA_REF_LOAD; new_refered.create (10); new_refered_type.create (10); for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++) { if (is_a (ref->referred)) { struct cgraph_node *cnode = ipa_ref_node (ref); struct cgraph_node *r_cnode = cgraph_lipo_get_resolved_node (cnode->decl); new_refered.safe_push (r_cnode); use_type = ref->use; new_refered_type.safe_push ((int) use_type); gcc_assert (use_type != IPA_REF_ADDR || cnode->global.inlined_to || cnode->address_taken); if (use_type == IPA_REF_ADDR) cgraph_mark_address_taken_node (r_cnode); } else if (is_a (ref->referred)) { struct varpool_node *var = ipa_ref_varpool_node (ref); struct varpool_node *r_var = real_varpool_node (var->decl); new_refered.safe_push (r_var); use_type = ref->use; new_refered_type.safe_push ((int) use_type); } else gcc_assert (false); } ipa_remove_all_references (&node->ref_list); for (i = 0; new_refered.iterate (i, &sym_node); ++i) { ipa_record_reference (node, sym_node, (enum ipa_ref_use) new_refered_type[i], NULL); } } /* Perform cross module linking for var_decls. */ void varpool_do_link (void) { struct varpool_node *node; if (!L_IPO_COMP_MODE) return; varpool_symtab = htab_create_ggc (10, hash_node_by_assembler_name, eq_node_assembler_name, NULL); FOR_EACH_VARIABLE (node) varpool_link_node (node); /* Merge the externally visible attribute. */ FOR_EACH_VARIABLE (node) { if (node->externally_visible) (real_varpool_node (node->decl))->externally_visible = true; fixup_reference_list (node); } } /* Get the list of assembler name ids with reference bit set. */ void varpool_get_referenced_asm_ids (vec **ids) { struct varpool_node *node; FOR_EACH_VARIABLE (node) { tree asm_id = NULL; tree decl = node->decl; if (DECL_ASSEMBLER_NAME_SET_P (decl)) { asm_id = DECL_ASSEMBLER_NAME (decl); vec_safe_push (*ids, asm_id); } } } /* Clear the referenced bit in all assembler ids. */ void varpool_clear_asm_id_reference_bit (void) { struct varpool_node *node; FOR_EACH_VARIABLE (node) { tree asm_id = NULL; tree decl = node->decl; if (DECL_ASSEMBLER_NAME_SET_P (decl)) { asm_id = DECL_ASSEMBLER_NAME (decl); TREE_SYMBOL_REFERENCED (asm_id) = 0; } } } #include "gt-l-ipo.h"