| /* LTO symbol table. |
| Copyright (C) 2009-2022 Free Software Foundation, Inc. |
| Contributed by CodeSourcery, Inc. |
| |
| 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 |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "target.h" |
| #include "function.h" |
| #include "basic-block.h" |
| #include "tree.h" |
| #include "gimple.h" |
| #include "cgraph.h" |
| #include "lto-streamer.h" |
| #include "ipa-utils.h" |
| #include "builtins.h" |
| #include "alias.h" |
| #include "lto.h" |
| #include "lto-symtab.h" |
| #include "stringpool.h" |
| #include "attribs.h" |
| |
| /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging |
| all edges and removing the old node. */ |
| |
| static void |
| lto_cgraph_replace_node (struct cgraph_node *node, |
| struct cgraph_node *prevailing_node) |
| { |
| struct cgraph_edge *e, *next; |
| bool compatible_p; |
| |
| if (dump_file) |
| { |
| fprintf (dump_file, "Replacing cgraph node %s by %s" |
| " for symbol %s\n", |
| node->dump_name (), |
| prevailing_node->dump_name (), |
| IDENTIFIER_POINTER ((*targetm.asm_out.mangle_assembler_name) |
| (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl))))); |
| } |
| |
| /* Merge node flags. */ |
| if (node->force_output) |
| prevailing_node->mark_force_output (); |
| if (node->forced_by_abi) |
| prevailing_node->forced_by_abi = true; |
| if (node->address_taken) |
| { |
| gcc_assert (!prevailing_node->inlined_to); |
| prevailing_node->mark_address_taken (); |
| } |
| if (node->definition && prevailing_node->definition |
| && DECL_COMDAT (node->decl) && DECL_COMDAT (prevailing_node->decl)) |
| prevailing_node->merged_comdat = true; |
| else if ((node->definition || node->body_removed) |
| && DECL_DECLARED_INLINE_P (node->decl) |
| && DECL_EXTERNAL (node->decl) |
| && prevailing_node->definition) |
| prevailing_node->merged_extern_inline = true; |
| prevailing_node->merged_comdat |= node->merged_comdat; |
| prevailing_node->merged_extern_inline |= node->merged_extern_inline; |
| |
| /* Redirect all incoming edges. */ |
| compatible_p |
| = types_compatible_p (TREE_TYPE (TREE_TYPE (prevailing_node->decl)), |
| TREE_TYPE (TREE_TYPE (node->decl))); |
| for (e = node->callers; e; e = next) |
| { |
| next = e->next_caller; |
| e->redirect_callee (prevailing_node); |
| /* If there is a mismatch between the supposed callee return type and |
| the real one do not attempt to inline this function. |
| ??? We really need a way to match function signatures for ABI |
| compatibility and perform related promotions at inlining time. */ |
| if (!compatible_p) |
| { |
| e->inline_failed = CIF_LTO_MISMATCHED_DECLARATIONS; |
| e->call_stmt_cannot_inline_p = 1; |
| } |
| } |
| /* Redirect incomming references. */ |
| prevailing_node->clone_referring (node); |
| lto_free_function_in_decl_state_for_node (node); |
| |
| if (node->decl != prevailing_node->decl) |
| node->release_body (); |
| |
| /* Finally remove the replaced node. */ |
| node->remove (); |
| } |
| |
| /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging |
| all edges and removing the old node. */ |
| |
| static void |
| lto_varpool_replace_node (varpool_node *vnode, |
| varpool_node *prevailing_node) |
| { |
| gcc_assert (!vnode->definition || prevailing_node->definition); |
| gcc_assert (!vnode->analyzed || prevailing_node->analyzed); |
| |
| prevailing_node->clone_referring (vnode); |
| if (vnode->force_output) |
| prevailing_node->force_output = true; |
| if (vnode->forced_by_abi) |
| prevailing_node->forced_by_abi = true; |
| |
| /* Be sure we can garbage collect the initializer. */ |
| if (DECL_INITIAL (vnode->decl) |
| && vnode->decl != prevailing_node->decl) |
| DECL_INITIAL (vnode->decl) = error_mark_node; |
| |
| /* Check and report ODR violations on virtual tables. */ |
| if (DECL_VIRTUAL_P (vnode->decl) || DECL_VIRTUAL_P (prevailing_node->decl)) |
| compare_virtual_tables (prevailing_node, vnode); |
| |
| if (vnode->tls_model != prevailing_node->tls_model) |
| { |
| bool error = false; |
| |
| /* Non-TLS and TLS never mix together. Also emulated model is not |
| compatible with anything else. */ |
| if (prevailing_node->tls_model == TLS_MODEL_NONE |
| || prevailing_node->tls_model == TLS_MODEL_EMULATED |
| || vnode->tls_model == TLS_MODEL_NONE |
| || vnode->tls_model == TLS_MODEL_EMULATED) |
| error = true; |
| /* Linked is silently supporting transitions |
| GD -> IE, GD -> LE, LD -> LE, IE -> LE, LD -> IE. |
| Do the same transitions and error out on others. */ |
| else if ((prevailing_node->tls_model == TLS_MODEL_REAL |
| || prevailing_node->tls_model == TLS_MODEL_LOCAL_DYNAMIC) |
| && (vnode->tls_model == TLS_MODEL_INITIAL_EXEC |
| || vnode->tls_model == TLS_MODEL_LOCAL_EXEC)) |
| prevailing_node->tls_model = vnode->tls_model; |
| else if ((vnode->tls_model == TLS_MODEL_REAL |
| || vnode->tls_model == TLS_MODEL_LOCAL_DYNAMIC) |
| && (prevailing_node->tls_model == TLS_MODEL_INITIAL_EXEC |
| || prevailing_node->tls_model == TLS_MODEL_LOCAL_EXEC)) |
| ; |
| else if (prevailing_node->tls_model == TLS_MODEL_INITIAL_EXEC |
| && vnode->tls_model == TLS_MODEL_LOCAL_EXEC) |
| prevailing_node->tls_model = vnode->tls_model; |
| else if (vnode->tls_model == TLS_MODEL_INITIAL_EXEC |
| && prevailing_node->tls_model == TLS_MODEL_LOCAL_EXEC) |
| ; |
| else |
| error = true; |
| if (error) |
| { |
| error_at (DECL_SOURCE_LOCATION (vnode->decl), |
| "%qD is defined with tls model %s", vnode->decl, tls_model_names [vnode->tls_model]); |
| inform (DECL_SOURCE_LOCATION (prevailing_node->decl), |
| "previously defined here as %s", |
| tls_model_names [prevailing_node->tls_model]); |
| } |
| } |
| /* Finally remove the replaced node. */ |
| vnode->remove (); |
| } |
| |
| /* Return non-zero if we want to output waring about T1 and T2. |
| Return value is a bitmask of reasons of violation: |
| Bit 0 indicates that types are not compatible. |
| Bit 1 indicates that types are not compatible because of C++ ODR rule. |
| If COMMON_OR_EXTERN is true, do not warn on size mismatches of arrays. |
| Bit 2 indicates that types are not ODR compatible |
| |
| The interoperability rules are language specific. At present we do only |
| full checking for C++ ODR rule and for other languages we do basic check |
| that data structures are of same size and TBAA compatible. Our TBAA |
| implementation should be coarse enough so all valid type transitions |
| across different languages are allowed. |
| |
| In partiucular we thus allow almost arbitrary type changes with |
| -fno-strict-aliasing which may be tough of as a feature rather than bug |
| as it allows to implement dodgy tricks in the language runtimes. |
| |
| Naturally this code can be strenghtened significantly if we could track |
| down the language of origin. */ |
| |
| static int |
| warn_type_compatibility_p (tree prevailing_type, tree type, |
| bool common_or_extern) |
| { |
| int lev = 0; |
| bool odr_p = odr_or_derived_type_p (prevailing_type) |
| && odr_or_derived_type_p (type); |
| |
| if (prevailing_type == type) |
| return 0; |
| |
| /* C++ provide a robust way to check for type compatibility via the ODR |
| rule. */ |
| if (odr_p && !odr_types_equivalent_p (prevailing_type, type)) |
| lev |= 2; |
| |
| /* Function types needs special care, because types_compatible_p never |
| thinks prototype is compatible to non-prototype. */ |
| if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) |
| { |
| if (TREE_CODE (type) != TREE_CODE (prevailing_type)) |
| lev |= 1; |
| lev |= warn_type_compatibility_p (TREE_TYPE (prevailing_type), |
| TREE_TYPE (type), false); |
| if (TREE_CODE (type) == METHOD_TYPE |
| && TREE_CODE (prevailing_type) == METHOD_TYPE) |
| lev |= warn_type_compatibility_p (TYPE_METHOD_BASETYPE (prevailing_type), |
| TYPE_METHOD_BASETYPE (type), false); |
| if (prototype_p (prevailing_type) && prototype_p (type) |
| && TYPE_ARG_TYPES (prevailing_type) != TYPE_ARG_TYPES (type)) |
| { |
| tree parm1, parm2; |
| for (parm1 = TYPE_ARG_TYPES (prevailing_type), |
| parm2 = TYPE_ARG_TYPES (type); |
| parm1 && parm2; |
| parm1 = TREE_CHAIN (parm1), |
| parm2 = TREE_CHAIN (parm2)) |
| lev |= warn_type_compatibility_p (TREE_VALUE (parm1), |
| TREE_VALUE (parm2), false); |
| if (parm1 || parm2) |
| lev |= odr_p ? 3 : 1; |
| } |
| if (comp_type_attributes (prevailing_type, type) == 0) |
| lev |= 1; |
| return lev; |
| } |
| |
| /* Get complete type. */ |
| prevailing_type = TYPE_MAIN_VARIANT (prevailing_type); |
| type = TYPE_MAIN_VARIANT (type); |
| |
| /* We cannot use types_compatible_p because we permit some changes |
| across types. For example unsigned size_t and "signed size_t" may be |
| compatible when merging C and Fortran types. */ |
| if (COMPLETE_TYPE_P (prevailing_type) |
| && COMPLETE_TYPE_P (type) |
| /* While global declarations are never variadic, we can recurse here |
| for function parameter types. */ |
| && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST |
| && TREE_CODE (TYPE_SIZE (prevailing_type)) == INTEGER_CST |
| && !tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (prevailing_type))) |
| { |
| /* As a special case do not warn about merging |
| int a[]; |
| and |
| int a[]={1,2,3}; |
| here the first declaration is COMMON or EXTERN |
| and sizeof(a) == sizeof (int). */ |
| if (!common_or_extern |
| || TREE_CODE (type) != ARRAY_TYPE |
| || TYPE_SIZE (type) != TYPE_SIZE (TREE_TYPE (type))) |
| lev |= 1; |
| } |
| |
| /* Verify TBAA compatibility. Take care of alias set 0 and the fact that |
| we make ptr_type_node to TBAA compatible with every other type. */ |
| if (type_with_alias_set_p (type) && type_with_alias_set_p (prevailing_type)) |
| { |
| alias_set_type set1 = get_alias_set (type); |
| alias_set_type set2 = get_alias_set (prevailing_type); |
| |
| if (set1 && set2 && set1 != set2) |
| { |
| tree t1 = type, t2 = prevailing_type; |
| |
| /* Alias sets of arrays with aliased components are the same as alias |
| sets of the inner types. */ |
| while (TREE_CODE (t1) == ARRAY_TYPE |
| && !TYPE_NONALIASED_COMPONENT (t1) |
| && TREE_CODE (t2) == ARRAY_TYPE |
| && !TYPE_NONALIASED_COMPONENT (t2)) |
| { |
| t1 = TREE_TYPE (t1); |
| t2 = TREE_TYPE (t2); |
| } |
| if ((!POINTER_TYPE_P (t1) || !POINTER_TYPE_P (t2)) |
| || (set1 != TYPE_ALIAS_SET (ptr_type_node) |
| && set2 != TYPE_ALIAS_SET (ptr_type_node))) |
| lev |= 5; |
| } |
| } |
| |
| return lev; |
| } |
| |
| /* Merge two variable or function symbol table entries PREVAILING and ENTRY. |
| Return false if the symbols are not fully compatible and a diagnostic |
| should be emitted. */ |
| |
| static bool |
| lto_symtab_merge (symtab_node *prevailing, symtab_node *entry) |
| { |
| tree prevailing_decl = prevailing->decl; |
| tree decl = entry->decl; |
| |
| if (prevailing_decl == decl) |
| return true; |
| |
| if (TREE_CODE (decl) != TREE_CODE (prevailing_decl)) |
| return false; |
| |
| /* Merge decl state in both directions, we may still end up using |
| the new decl. */ |
| TREE_ADDRESSABLE (prevailing_decl) |= TREE_ADDRESSABLE (decl); |
| TREE_ADDRESSABLE (decl) |= TREE_ADDRESSABLE (prevailing_decl); |
| |
| /* The linker may ask us to combine two incompatible symbols. |
| Detect this case and notify the caller of required diagnostics. */ |
| |
| if (TREE_CODE (decl) == FUNCTION_DECL) |
| { |
| /* Merge decl state in both directions, we may still end up using |
| the new decl. */ |
| DECL_POSSIBLY_INLINED (prevailing_decl) |= DECL_POSSIBLY_INLINED (decl); |
| DECL_POSSIBLY_INLINED (decl) |= DECL_POSSIBLY_INLINED (prevailing_decl); |
| |
| if (warn_type_compatibility_p (TREE_TYPE (prevailing_decl), |
| TREE_TYPE (decl), |
| DECL_COMMON (decl) |
| || DECL_EXTERNAL (decl))) |
| return false; |
| |
| return true; |
| } |
| |
| if (warn_type_compatibility_p (TREE_TYPE (prevailing_decl), |
| TREE_TYPE (decl), |
| DECL_COMMON (decl) || DECL_EXTERNAL (decl))) |
| return false; |
| |
| /* There is no point in comparing too many details of the decls here. |
| The type compatibility checks or the completing of types has properly |
| dealt with most issues. */ |
| |
| /* The following should all not invoke fatal errors as in non-LTO |
| mode the linker wouldn't complain either. Just emit warnings. */ |
| |
| /* Report a warning if user-specified alignments do not match. */ |
| if ((DECL_USER_ALIGN (prevailing_decl) && DECL_USER_ALIGN (decl)) |
| && DECL_ALIGN (prevailing_decl) < DECL_ALIGN (decl)) |
| return false; |
| |
| if (DECL_SIZE (decl) && DECL_SIZE (prevailing_decl) |
| && !tree_int_cst_equal (DECL_SIZE (decl), DECL_SIZE (prevailing_decl))) |
| { |
| if (!DECL_COMMON (decl) && !DECL_EXTERNAL (decl)) |
| return false; |
| |
| tree type = TREE_TYPE (decl); |
| |
| /* For record type, check for array at the end of the structure. */ |
| if (TREE_CODE (type) == RECORD_TYPE) |
| { |
| tree field = TYPE_FIELDS (type); |
| while (DECL_CHAIN (field) != NULL_TREE) |
| field = DECL_CHAIN (field); |
| |
| return TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE; |
| } |
| /* As a special case do not warn about merging |
| int a[]; |
| and |
| int a[]={1,2,3}; |
| here the first declaration is COMMON |
| and sizeof(a) == sizeof (int). */ |
| else if (TREE_CODE (type) != ARRAY_TYPE |
| || (TYPE_SIZE (type) != TYPE_SIZE (TREE_TYPE (type)))) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* Return true if the symtab entry E can be replaced by another symtab |
| entry. */ |
| |
| static bool |
| lto_symtab_resolve_replaceable_p (symtab_node *e) |
| { |
| if (DECL_EXTERNAL (e->decl) |
| || DECL_COMDAT (e->decl) |
| || DECL_ONE_ONLY (e->decl) |
| || DECL_WEAK (e->decl)) |
| return true; |
| |
| if (TREE_CODE (e->decl) == VAR_DECL) |
| return (DECL_COMMON (e->decl) |
| || (!flag_no_common && !DECL_INITIAL (e->decl))); |
| |
| return false; |
| } |
| |
| /* Return true, if the symbol E should be resolved by lto-symtab. |
| Those are all external symbols and all real symbols that are not static (we |
| handle renaming of static later in partitioning). */ |
| |
| static bool |
| lto_symtab_symbol_p (symtab_node *e) |
| { |
| if (!TREE_PUBLIC (e->decl) && !DECL_EXTERNAL (e->decl)) |
| return false; |
| return e->real_symbol_p (); |
| } |
| |
| /* Return true if the symtab entry E can be the prevailing one. */ |
| |
| static bool |
| lto_symtab_resolve_can_prevail_p (symtab_node *e) |
| { |
| if (!lto_symtab_symbol_p (e)) |
| return false; |
| |
| /* The C++ frontend ends up neither setting TREE_STATIC nor |
| DECL_EXTERNAL on virtual methods but only TREE_PUBLIC. |
| So do not reject !TREE_STATIC here but only DECL_EXTERNAL. */ |
| if (DECL_EXTERNAL (e->decl)) |
| return false; |
| |
| return e->definition; |
| } |
| |
| /* Resolve the symbol with the candidates in the chain *SLOT and store |
| their resolutions. */ |
| |
| static symtab_node * |
| lto_symtab_resolve_symbols (symtab_node *first) |
| { |
| symtab_node *e; |
| symtab_node *prevailing = NULL; |
| |
| /* Always set e->node so that edges are updated to reflect decl merging. */ |
| for (e = first; e; e = e->next_sharing_asm_name) |
| if (lto_symtab_symbol_p (e) |
| && (e->resolution == LDPR_PREVAILING_DEF_IRONLY |
| || e->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP |
| || e->resolution == LDPR_PREVAILING_DEF)) |
| { |
| prevailing = e; |
| break; |
| } |
| |
| /* If the chain is already resolved there is nothing else to do. */ |
| if (prevailing) |
| { |
| /* Assert it's the only one. |
| GCC should silence multiple PREVAILING_DEF_IRONLY defs error |
| on COMMON symbols since it isn't error. |
| See: https://sourceware.org/bugzilla/show_bug.cgi?id=23079. */ |
| for (e = prevailing->next_sharing_asm_name; e; e = e->next_sharing_asm_name) |
| if (lto_symtab_symbol_p (e) |
| && !DECL_COMMON (prevailing->decl) |
| && !DECL_COMMON (e->decl) |
| && (e->resolution == LDPR_PREVAILING_DEF_IRONLY |
| || e->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP |
| || e->resolution == LDPR_PREVAILING_DEF)) |
| fatal_error (input_location, "multiple prevailing defs for %qE", |
| DECL_NAME (prevailing->decl)); |
| return prevailing; |
| } |
| |
| /* Find the single non-replaceable prevailing symbol and |
| diagnose ODR violations. */ |
| for (e = first; e; e = e->next_sharing_asm_name) |
| { |
| if (!lto_symtab_resolve_can_prevail_p (e)) |
| continue; |
| |
| /* If we have a non-replaceable definition it prevails. */ |
| if (!lto_symtab_resolve_replaceable_p (e)) |
| { |
| if (prevailing) |
| { |
| error_at (DECL_SOURCE_LOCATION (e->decl), |
| "%qD has already been defined", e->decl); |
| inform (DECL_SOURCE_LOCATION (prevailing->decl), |
| "previously defined here"); |
| } |
| prevailing = e; |
| } |
| } |
| if (prevailing) |
| return prevailing; |
| |
| /* Do a second round choosing one from the replaceable prevailing decls. */ |
| for (e = first; e; e = e->next_sharing_asm_name) |
| { |
| if (!lto_symtab_resolve_can_prevail_p (e)) |
| continue; |
| |
| /* Choose the first function that can prevail as prevailing. */ |
| if (TREE_CODE (e->decl) == FUNCTION_DECL) |
| { |
| prevailing = e; |
| break; |
| } |
| |
| /* From variables that can prevail choose the largest one. */ |
| if (!prevailing |
| || tree_int_cst_lt (DECL_SIZE (prevailing->decl), |
| DECL_SIZE (e->decl)) |
| /* When variables are equivalent try to chose one that has useful |
| DECL_INITIAL. This makes sense for keyed vtables that are |
| DECL_EXTERNAL but initialized. In units that do not need them |
| we replace the initializer by error_mark_node to conserve |
| memory. |
| |
| We know that the vtable is keyed outside the LTO unit - otherwise |
| the keyed instance would prevail. We still can preserve useful |
| info in the initializer. */ |
| || (DECL_SIZE (prevailing->decl) == DECL_SIZE (e->decl) |
| && (DECL_INITIAL (e->decl) |
| && DECL_INITIAL (e->decl) != error_mark_node) |
| && (!DECL_INITIAL (prevailing->decl) |
| || DECL_INITIAL (prevailing->decl) == error_mark_node))) |
| prevailing = e; |
| } |
| |
| return prevailing; |
| } |
| |
| /* Decide if it is OK to merge DECL into PREVAILING. |
| Because we wrap most of uses of declarations in MEM_REF, we can tolerate |
| some differences but other code may inspect directly the DECL. */ |
| |
| static bool |
| lto_symtab_merge_p (tree prevailing, tree decl) |
| { |
| if (TREE_CODE (prevailing) != TREE_CODE (decl)) |
| { |
| if (dump_file) |
| fprintf (dump_file, "Not merging decls; " |
| "TREE_CODE mismatch\n"); |
| return false; |
| } |
| gcc_checking_assert (TREE_CHAIN (prevailing) == TREE_CHAIN (decl)); |
| |
| if (TREE_CODE (prevailing) == FUNCTION_DECL) |
| { |
| if (fndecl_built_in_p (prevailing) != fndecl_built_in_p (decl)) |
| { |
| if (dump_file) |
| fprintf (dump_file, "Not merging decls; " |
| "DECL_BUILT_IN mismatch\n"); |
| return false; |
| } |
| if (fndecl_built_in_p (prevailing) |
| && (DECL_BUILT_IN_CLASS (prevailing) != DECL_BUILT_IN_CLASS (decl) |
| || (DECL_UNCHECKED_FUNCTION_CODE (prevailing) |
| != DECL_UNCHECKED_FUNCTION_CODE (decl)))) |
| { |
| if (dump_file) |
| fprintf (dump_file, "Not merging decls; " |
| "DECL_BUILT_IN_CLASS or CODE mismatch\n"); |
| return false; |
| } |
| } |
| |
| if (DECL_ATTRIBUTES (prevailing) != DECL_ATTRIBUTES (decl)) |
| { |
| tree prev_attr = lookup_attribute ("error", DECL_ATTRIBUTES (prevailing)); |
| tree attr = lookup_attribute ("error", DECL_ATTRIBUTES (decl)); |
| if ((prev_attr == NULL) != (attr == NULL) |
| || (prev_attr && !attribute_value_equal (prev_attr, attr))) |
| { |
| if (dump_file) |
| fprintf (dump_file, "Not merging decls; " |
| "error attribute mismatch\n"); |
| return false; |
| } |
| |
| prev_attr = lookup_attribute ("warning", DECL_ATTRIBUTES (prevailing)); |
| attr = lookup_attribute ("warning", DECL_ATTRIBUTES (decl)); |
| if ((prev_attr == NULL) != (attr == NULL) |
| || (prev_attr && !attribute_value_equal (prev_attr, attr))) |
| { |
| if (dump_file) |
| fprintf (dump_file, "Not merging decls; " |
| "warning attribute mismatch\n"); |
| return false; |
| } |
| |
| prev_attr = lookup_attribute ("noreturn", DECL_ATTRIBUTES (prevailing)); |
| attr = lookup_attribute ("noreturn", DECL_ATTRIBUTES (decl)); |
| if ((prev_attr == NULL) != (attr == NULL)) |
| { |
| if (dump_file) |
| fprintf (dump_file, "Not merging decls; " |
| "noreturn attribute mismatch\n"); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /* Merge all decls in the symbol table chain to the prevailing decl and |
| issue diagnostics about type mismatches. If DIAGNOSED_P is true |
| do not issue further diagnostics.*/ |
| |
| 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) |
| { |
| /* Do not diagnose two built-in declarations, there is no useful |
| location in that case. It also happens for AVR if two built-ins |
| use the same asm name because their libgcc assembler code is the |
| same, see PR78562. */ |
| if (DECL_IS_UNDECLARED_BUILTIN (prevailing->decl) |
| && DECL_IS_UNDECLARED_BUILTIN (decl)) |
| continue; |
| |
| int level = warn_type_compatibility_p (TREE_TYPE (prevailing->decl), |
| TREE_TYPE (decl), |
| DECL_COMDAT (decl)); |
| if (level) |
| { |
| bool diag = false; |
| if (level & 2) |
| { |
| /* Silence warning for method and variables which belong |
| to types which already have ODR violation reported. Complaining |
| once is enough. */ |
| if (TREE_CODE (decl) != FUNCTION_DECL |
| || TREE_CODE (TREE_TYPE (decl)) != METHOD_TYPE |
| || !TYPE_METHOD_BASETYPE (TREE_TYPE (decl)) |
| || !odr_type_p (TYPE_METHOD_BASETYPE (TREE_TYPE (decl))) |
| || !odr_type_violation_reported_p |
| (TYPE_METHOD_BASETYPE (TREE_TYPE (decl)))) |
| 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); |
| } |
| if (diagnosed_p) |
| inform (DECL_SOURCE_LOCATION (prevailing->decl), |
| "%qD was previously declared here", prevailing->decl); |
| if (tbaa_p) |
| inform (DECL_SOURCE_LOCATION (prevailing->decl), |
| "code may be misoptimized unless " |
| "%<-fno-strict-aliasing%> is used"); |
| |
| mismatches.release (); |
| } |
| |
| /* Helper to process the decl chain for the symbol table entry *SLOT. */ |
| |
| static void |
| lto_symtab_merge_decls_1 (symtab_node *first) |
| { |
| symtab_node *e; |
| symtab_node *prevailing; |
| bool diagnosed_p = false; |
| |
| if (dump_file) |
| { |
| fprintf (dump_file, "Merging nodes for %s. Candidates:\n", |
| first->asm_name ()); |
| for (e = first; e; e = e->next_sharing_asm_name) |
| if (TREE_PUBLIC (e->decl)) |
| e->dump (dump_file); |
| } |
| |
| /* Compute the symbol resolutions. This is a no-op when using the |
| linker plugin and resolution was decided by the linker. */ |
| prevailing = lto_symtab_resolve_symbols (first); |
| |
| /* If there's not a prevailing symbol yet it's an external reference. |
| Happens a lot during ltrans. Choose the first symbol with a |
| cgraph or a varpool node. */ |
| if (!prevailing) |
| { |
| for (prevailing = first; |
| prevailing; prevailing = prevailing->next_sharing_asm_name) |
| if (lto_symtab_symbol_p (prevailing)) |
| break; |
| if (!prevailing) |
| return; |
| /* For variables chose with a priority variant with vnode |
| attached (i.e. from unit where external declaration of |
| variable is actually used). |
| When there are multiple variants, chose one with size. |
| This is needed for C++ typeinfos, for example in |
| lto/20081204-1 there are typeifos in both units, just |
| one of them do have size. */ |
| if (TREE_CODE (prevailing->decl) == VAR_DECL) |
| { |
| for (e = prevailing->next_sharing_asm_name; |
| e; e = e->next_sharing_asm_name) |
| if (!COMPLETE_TYPE_P (TREE_TYPE (prevailing->decl)) |
| && COMPLETE_TYPE_P (TREE_TYPE (e->decl)) |
| && lto_symtab_symbol_p (e)) |
| prevailing = e; |
| } |
| /* For functions prefer the non-builtin if one is available. */ |
| else if (TREE_CODE (prevailing->decl) == FUNCTION_DECL) |
| { |
| for (e = first; e; e = e->next_sharing_asm_name) |
| if (TREE_CODE (e->decl) == FUNCTION_DECL |
| && !fndecl_built_in_p (e->decl) |
| && lto_symtab_symbol_p (e)) |
| { |
| prevailing = e; |
| break; |
| } |
| } |
| } |
| |
| symtab->symtab_prevail_in_asm_name_hash (prevailing); |
| |
| /* Diagnose mismatched objects. */ |
| for (e = prevailing->next_sharing_asm_name; |
| e; e = e->next_sharing_asm_name) |
| { |
| if (TREE_CODE (prevailing->decl) |
| == TREE_CODE (e->decl)) |
| continue; |
| if (!lto_symtab_symbol_p (e)) |
| continue; |
| |
| switch (TREE_CODE (prevailing->decl)) |
| { |
| case VAR_DECL: |
| gcc_assert (TREE_CODE (e->decl) == FUNCTION_DECL); |
| error_at (DECL_SOURCE_LOCATION (e->decl), |
| "variable %qD redeclared as function", |
| prevailing->decl); |
| break; |
| |
| case FUNCTION_DECL: |
| gcc_assert (TREE_CODE (e->decl) == VAR_DECL); |
| error_at (DECL_SOURCE_LOCATION (e->decl), |
| "function %qD redeclared as variable", |
| prevailing->decl); |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| diagnosed_p = true; |
| } |
| if (diagnosed_p) |
| inform (DECL_SOURCE_LOCATION (prevailing->decl), |
| "previously declared here"); |
| |
| /* Merge the chain to the single prevailing decl and diagnose |
| mismatches. */ |
| lto_symtab_merge_decls_2 (prevailing, diagnosed_p); |
| |
| if (dump_file) |
| { |
| fprintf (dump_file, "After resolution:\n"); |
| for (e = prevailing; e; e = e->next_sharing_asm_name) |
| e->dump (dump_file); |
| } |
| } |
| |
| /* Resolve and merge all symbol table chains to a prevailing decl. */ |
| |
| void |
| lto_symtab_merge_decls (void) |
| { |
| symtab_node *node; |
| |
| gcc_assert (!dump_file); |
| dump_file = dump_begin (decl_merge_dump_id, NULL); |
| |
| /* Populate assembler name hash. */ |
| symtab->symtab_initialize_asm_name_hash (); |
| |
| FOR_EACH_SYMBOL (node) |
| if (!node->previous_sharing_asm_name |
| && node->next_sharing_asm_name) |
| lto_symtab_merge_decls_1 (node); |
| |
| if (dump_file) |
| dump_end (decl_merge_dump_id, dump_file); |
| dump_file = NULL; |
| } |
| |
| /* Helper to process the decl chain for the symbol table entry *SLOT. */ |
| |
| static void |
| lto_symtab_merge_symbols_1 (symtab_node *prevailing) |
| { |
| symtab_node *e; |
| symtab_node *next; |
| |
| prevailing->decl->decl_with_vis.symtab_node = prevailing; |
| |
| /* Replace the cgraph node of each entry with the prevailing one. */ |
| for (e = prevailing->next_sharing_asm_name; e; |
| e = next) |
| { |
| next = e->next_sharing_asm_name; |
| cgraph_node *ce = dyn_cast <cgraph_node *> (e); |
| |
| if ((!TREE_PUBLIC (e->decl) && !DECL_EXTERNAL (e->decl)) |
| || (ce != NULL && ce->inlined_to)) |
| continue; |
| symtab_node *to = symtab_node::get (lto_symtab_prevailing_decl (e->decl)); |
| |
| /* No matter how we are going to deal with resolution, we will ultimately |
| use prevailing definition. */ |
| if (ce) |
| ipa_merge_profiles (dyn_cast<cgraph_node *> (prevailing), |
| dyn_cast<cgraph_node *> (e)); |
| |
| /* If we decided to replace the node by TO, do it. */ |
| if (e != to) |
| { |
| if (ce) |
| lto_cgraph_replace_node (ce, dyn_cast<cgraph_node *> (to)); |
| else if (varpool_node *ve = dyn_cast <varpool_node *> (e)) |
| lto_varpool_replace_node (ve, dyn_cast<varpool_node *> (to)); |
| } |
| /* Watch out for duplicated symbols for a given declaration. */ |
| else if (!e->transparent_alias |
| || !e->definition || e->get_alias_target () != to) |
| { |
| /* We got a new declaration we do not want to merge. In this case |
| get rid of the existing definition and create a transparent |
| alias. */ |
| if (ce) |
| { |
| lto_free_function_in_decl_state_for_node (ce); |
| if (!ce->weakref) |
| ce->release_body (); |
| ce->reset (); |
| symtab->call_cgraph_removal_hooks (ce); |
| } |
| else |
| { |
| DECL_INITIAL (e->decl) = error_mark_node; |
| if (e->lto_file_data) |
| { |
| lto_free_function_in_decl_state_for_node (e); |
| e->lto_file_data = NULL; |
| } |
| symtab->call_varpool_removal_hooks (dyn_cast<varpool_node *> (e)); |
| } |
| e->remove_all_references (); |
| e->analyzed = e->body_removed = false; |
| e->resolve_alias (prevailing, true); |
| gcc_assert (e != prevailing); |
| } |
| } |
| |
| return; |
| } |
| |
| /* Merge cgraph nodes according to the symbol merging done by |
| lto_symtab_merge_decls. */ |
| |
| void |
| lto_symtab_merge_symbols (void) |
| { |
| symtab_node *node; |
| |
| if (!flag_ltrans) |
| { |
| symtab->symtab_initialize_asm_name_hash (); |
| |
| /* Do the actual merging. |
| At this point we invalidate hash translating decls into symtab nodes |
| because after removing one of duplicate decls the hash is not correcly |
| updated to the other duplicate. */ |
| FOR_EACH_SYMBOL (node) |
| if (lto_symtab_symbol_p (node) |
| && node->next_sharing_asm_name |
| && !node->previous_sharing_asm_name) |
| lto_symtab_merge_symbols_1 (node); |
| |
| /* Resolve weakref aliases whose target are now in the compilation unit. |
| also re-populate the hash translating decls into symtab nodes*/ |
| FOR_EACH_SYMBOL (node) |
| { |
| cgraph_node *cnode, *cnode2; |
| varpool_node *vnode; |
| symtab_node *node2; |
| |
| if (!node->analyzed && node->alias_target) |
| { |
| symtab_node *tgt = symtab_node::get_for_asmname (node->alias_target); |
| gcc_assert (node->weakref); |
| if (tgt) |
| node->resolve_alias (tgt, true); |
| } |
| /* If the symbol was preempted outside IR, see if we want to get rid |
| of the definition. */ |
| if (node->analyzed |
| && !DECL_EXTERNAL (node->decl) |
| && (node->resolution == LDPR_PREEMPTED_REG |
| || node->resolution == LDPR_RESOLVED_IR |
| || node->resolution == LDPR_RESOLVED_EXEC |
| || node->resolution == LDPR_RESOLVED_DYN)) |
| { |
| DECL_EXTERNAL (node->decl) = 1; |
| /* If alias to local symbol was preempted by external definition, |
| we know it is not pointing to the local symbol. Remove it. */ |
| if (node->alias |
| && !node->weakref |
| && !node->transparent_alias |
| && node->get_alias_target ()->binds_to_current_def_p ()) |
| { |
| node->alias = false; |
| node->remove_all_references (); |
| node->definition = false; |
| node->analyzed = false; |
| node->cpp_implicit_alias = false; |
| } |
| else if (!node->alias |
| && node->definition |
| && node->get_availability () <= AVAIL_INTERPOSABLE) |
| { |
| if ((cnode = dyn_cast <cgraph_node *> (node)) != NULL) |
| cnode->reset (); |
| else |
| { |
| node->analyzed = node->definition = false; |
| node->remove_all_references (); |
| } |
| } |
| } |
| |
| if (!(cnode = dyn_cast <cgraph_node *> (node)) |
| || !cnode->clone_of |
| || cnode->clone_of->decl != cnode->decl) |
| { |
| /* Builtins are not merged via decl merging. It is however |
| possible that tree merging unified the declaration. We |
| do not want duplicate entries in symbol table. */ |
| if (cnode && fndecl_built_in_p (node->decl) |
| && (cnode2 = cgraph_node::get (node->decl)) |
| && cnode2 != cnode) |
| lto_cgraph_replace_node (cnode2, cnode); |
| |
| /* The user defined assembler variables are also not unified by their |
| symbol name (since it is irrelevant), but we need to unify symbol |
| nodes if tree merging occurred. */ |
| if ((vnode = dyn_cast <varpool_node *> (node)) |
| && DECL_HARD_REGISTER (vnode->decl) |
| && (node2 = symtab_node::get (vnode->decl)) |
| && node2 != node) |
| lto_varpool_replace_node (dyn_cast <varpool_node *> (node2), |
| vnode); |
| |
| |
| /* Abstract functions may have duplicated cgraph nodes attached; |
| remove them. */ |
| else if (cnode && DECL_ABSTRACT_P (cnode->decl) |
| && (cnode2 = cgraph_node::get (node->decl)) |
| && cnode2 != cnode) |
| cnode2->remove (); |
| |
| node->decl->decl_with_vis.symtab_node = node; |
| } |
| } |
| } |
| } |
| |
| /* Virtual tables may matter for code generation even if they are not |
| directly referenced by the code because they may be used for |
| devirtualization. |
| For this reason it is important to merge even virtual tables that have no |
| associated symbol table entries. Without doing so we lose optimization |
| oppurtunities by losing track of the vtable constructor. |
| FIXME: we probably ought to introduce explicit symbol table entries for |
| those before streaming. */ |
| |
| tree |
| lto_symtab_prevailing_virtual_decl (tree decl) |
| { |
| if (DECL_ABSTRACT_P (decl)) |
| return decl; |
| |
| if (type_in_anonymous_namespace_p (DECL_CONTEXT (decl))) |
| /* There can't be any other declarations. */ |
| return decl; |
| |
| gcc_checking_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); |
| |
| symtab_node *n = symtab_node::get_for_asmname |
| (DECL_ASSEMBLER_NAME (decl)); |
| while (n && ((!DECL_EXTERNAL (n->decl) && !TREE_PUBLIC (n->decl)) |
| || !DECL_VIRTUAL_P (n->decl))) |
| n = n->next_sharing_asm_name; |
| if (n) |
| { |
| /* Merge decl state in both directions, we may still end up using |
| the other decl. */ |
| TREE_ADDRESSABLE (n->decl) |= TREE_ADDRESSABLE (decl); |
| TREE_ADDRESSABLE (decl) |= TREE_ADDRESSABLE (n->decl); |
| |
| if (TREE_CODE (decl) == FUNCTION_DECL) |
| { |
| /* Merge decl state in both directions, we may still end up using |
| the other decl. */ |
| DECL_POSSIBLY_INLINED (n->decl) |= DECL_POSSIBLY_INLINED (decl); |
| DECL_POSSIBLY_INLINED (decl) |= DECL_POSSIBLY_INLINED (n->decl); |
| } |
| lto_symtab_prevail_decl (n->decl, decl); |
| decl = n->decl; |
| } |
| else |
| symtab_node::get_create (decl); |
| |
| return decl; |
| } |