* [LTO][PATCH] Move lto-symtab.c out of lto and remove input_cgraph lang-hook.
@ 2008-10-28 7:18 Doug Kwan (關振德)
2008-10-28 13:34 ` Diego Novillo
0 siblings, 1 reply; 2+ messages in thread
From: Doug Kwan (關振德) @ 2008-10-28 7:18 UTC (permalink / raw)
To: gcc-patches, Diego Novillo, Rafael Espindola
[-- Attachment #1: Type: text/plain, Size: 2124 bytes --]
Hi,
This patch move the file lto-symtab.c out of the lto FE directory.
It also move the resolution annotations of out language specific part
of tree nodes into two hash tables. Since the functionality of
lto-symtab.c is now available to all parts of gcc, there is not need
for the input_cgraph lang-hook. I also move the cgraph read/write
part of the lto1 FE back to lto-cgraph.c, where it logically belong.
-Doug
2008-10-27 Doug Kwan <dougkwan@google.com>
* lto-symtab.c (New file): Move from up from lto sub-directory.
* lto-cgraph.c (lto-tree-in.h): New include
(input_overwrite_node, input_node, input_edge, input_cgraph_1,
input_cgraph): Move from back from lto/lto-lang.c to here.
* lto-tree-in.h (lto_symtab_clear_resolution): New prototype.
* langhooks.c (lhd_input_cgraph): Remove.
* langhooks.h (struct lang_hooks_for_lto): Remove INPUT_CRAPH hooks.
* Makefile.in (PLUGIN_API_H, LTO_TREE_IN_H): New vars.
(OBJS-common): Include lto-symtab.o
(lto-cgraph.o): Add LTO_TREE_IN_H in dependency.
(lto-function-in.o): Ditto.
(lto-symtab.o): New rule.
(GTFILES): Add lto-symtab.c
* langhooks-def.h (lhd_input_cgraph): Remove prototype.
(LANG_HOOKS_INPUT_GRAPH): Remove macro.
(LANG_HOOKS_LTO): Remove LANG_HOOKS_INPUT_CGRAPH from initializer.
lto/ChangeLog:
* lto.c (free_decl): Call lto_symtab_clear_resolution when freeing
DECL.
* Make-lang.in (LTO_OBJS): Remove lto/lto-symtab.o
(lto/lto-symtab.o): Remove rule.
* lto-tree.h (struct lang_identifier): Remove LTO specific fields.
(struct lang_decl): Remove RESOLUTION and add DUMMY in struct.
(LANG_IDENTIFIER_CAST, LTO_IDENTIFIER_DECL, LTO_DECL_RESOLUTION):
Remove macros.
lto-symtab.c (File): Move up one level.
lto-lang.c (cgraph.h): Remove include.
(input_overwrite_node, input_node, input_edge, input_cgraph_1,
input_cgraph): Move to lto-cgraph.c in gcc directory above.
(LANG_HOOKS_INPUT_CGRAPH): Remove use of macro.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 73156 bytes --]
Index: gcc/gcc/lto-symtab.c
===================================================================
--- gcc/gcc/lto-symtab.c (revision 0)
+++ gcc/gcc/lto-symtab.c (revision 0)
@@ -0,0 +1,795 @@
+/* LTO symbol table.
+ Copyright 2006 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 2, 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 COPYING. If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "toplev.h"
+#include "tree.h"
+#include "gimple.h"
+#include "lto-tree-in.h"
+#include "ggc.h" /* lambda.h needs this */
+#include "lambda.h" /* gcd */
+#include "hashtab.h"
+
+/* Vector to keep track of external variables we've seen so far. */
+VEC(tree,gc) *lto_global_var_decls;
+
+/* A poor man's symbol table. This hashes identifier to prevailing DECL
+ if there is one. */
+
+/* Base type for resolution map. It maps NODE to resolution. */
+
+struct lto_symtab_base_def GTY(())
+{
+ /* Key is either an IDENTIFIER or a DECL. */
+ tree node;
+};
+typedef struct lto_symtab_base_def *lto_symtab_base_t;
+
+struct lto_symtab_identifier_def GTY (())
+{
+ struct lto_symtab_base_def base;
+ tree decl;
+};
+typedef struct lto_symtab_identifier_def *lto_symtab_identifier_t;
+
+struct lto_symtab_decl_def GTY (())
+{
+ struct lto_symtab_base_def base;
+ enum ld_plugin_symbol_resolution resolution;
+};
+typedef struct lto_symtab_decl_def *lto_symtab_decl_t;
+
+static GTY ((if_marked ("lto_symtab_identifier_marked_p"),
+ param_is (struct lto_symtab_identifier_def)))
+ htab_t lto_symtab_identifiers;
+
+static GTY ((if_marked ("lto_symtab_decl_marked_p"),
+ param_is (struct lto_symtab_decl_def)))
+ htab_t lto_symtab_decls;
+
+/* Return the hash value of an lto_symtab_base_t object pointed to by P. */
+
+static hashval_t
+lto_symtab_base_hash (const void *p)
+{
+ const struct lto_symtab_base_def *base =
+ (const struct lto_symtab_base_def*) p;
+ return htab_hash_pointer (base->node);
+}
+
+/* Return non-zero if P1 and P2 points to lto_symtab_base_def structs
+ corresponding to the same tree node. */
+
+static int
+lto_symtab_base_eq (const void *p1, const void *p2)
+{
+ const struct lto_symtab_base_def *base1 =
+ (const struct lto_symtab_base_def *) p1;
+ const struct lto_symtab_base_def *base2 =
+ (const struct lto_symtab_base_def *) p2;
+ return (base1->node == base2->node);
+}
+
+/* Returns non-zero if P points to an lto_symtab_base_def struct that needs
+ to be marked for GC. */
+
+static int
+lto_symtab_base_marked_p (const void *p)
+{
+ const struct lto_symtab_base_def *base =
+ (const struct lto_symtab_base_def *) p;
+
+ /* Keep this only if the key node is marked. */
+ return ggc_marked_p (base->node);
+}
+
+/* Returns non-zero if P points to an lto_symtab_identifier_def struct that
+ needs to be marked for GC. */
+
+static int
+lto_symtab_identifier_marked_p (const void *p)
+{
+ return lto_symtab_base_marked_p (p);
+}
+
+/* Returns non-zero if P points to an lto_symtab_decl_def struct that needs
+ to be marked for GC. */
+
+static int
+lto_symtab_decl_marked_p (const void *p)
+{
+ return lto_symtab_base_marked_p (p);
+}
+
+#define lto_symtab_identifier_eq lto_symtab_base_eq
+#define lto_symtab_identifier_hash lto_symtab_base_hash
+#define lto_symtab_decl_eq lto_symtab_base_eq
+#define lto_symtab_decl_hash lto_symtab_base_hash
+
+/* Lazily initialize resolution hash tables. */
+
+static void
+lto_symtab_maybe_init_hash_tables (void)
+{
+ if (!lto_symtab_identifiers)
+ {
+ lto_symtab_identifiers =
+ htab_create_ggc (1021, lto_symtab_identifier_hash,
+ lto_symtab_identifier_eq, ggc_free);
+ lto_symtab_decls =
+ htab_create_ggc (1021, lto_symtab_decl_hash,
+ lto_symtab_decl_eq, ggc_free);
+ }
+}
+
+/* Returns true iff TYPE_1 and TYPE_2 are the same type. */
+
+static bool
+lto_same_type_p (tree type_1, tree type_2)
+{
+ unsigned int code;
+
+ /* Check first for the obvious case of pointer identity. */
+ if (type_1 == type_2)
+ return true;
+
+ /* Check that we have two types to compare. */
+ if (type_1 == NULL_TREE || type_2 == NULL_TREE)
+ return false;
+
+ /* Can't be the same type if the types don't have the same code. */
+ code = TREE_CODE (type_1);
+ if (code != TREE_CODE (type_2))
+ return false;
+
+ /* Can't be the same type if they have different CV qualifiers. */
+ if (TYPE_QUALS (type_1) != TYPE_QUALS (type_2))
+ return false;
+
+ /* "If GNU attributes are present, types which could be the same be it not
+ for their GNU attributes may in fact be different due to the use of GNU
+ attributes." Hmmm. Punt on this for now and assume they're different
+ if we see attributes on either type. */
+ if (TYPE_ATTRIBUTES (type_1) || TYPE_ATTRIBUTES (type_2))
+ return false;
+
+ switch (code)
+ {
+ case VOID_TYPE:
+ /* Void types are the same in all translation units. */
+ return true;
+
+ case INTEGER_TYPE:
+ case BOOLEAN_TYPE:
+ /* Corresponding integral types are the same. */
+ return (TYPE_PRECISION (type_1) == TYPE_PRECISION (type_2)
+ && TYPE_UNSIGNED (type_1) == TYPE_UNSIGNED (type_2)
+ && tree_int_cst_equal (TYPE_SIZE (type_1), TYPE_SIZE (type_2))
+ && TYPE_ALIGN (type_1) == TYPE_ALIGN (type_2)
+ && TYPE_STRING_FLAG (type_1) == TYPE_STRING_FLAG (type_2));
+
+ case REAL_TYPE:
+ /* Corresponding float types are the same. */
+ return (TYPE_PRECISION (type_1) == TYPE_PRECISION (type_2)
+ && tree_int_cst_equal (TYPE_SIZE (type_1), TYPE_SIZE (type_2))
+ && TYPE_ALIGN (type_1) == TYPE_ALIGN (type_2));
+
+ case ARRAY_TYPE:
+ /* Array types are the same if the element types are the same and
+ the number of elements are the same. */
+ if (!lto_same_type_p (TREE_TYPE (type_1), TREE_TYPE (type_2))
+ || TYPE_STRING_FLAG (type_1) != TYPE_STRING_FLAG (type_2))
+ return false;
+ else
+ {
+ tree index_1 = TYPE_DOMAIN (type_1);
+ tree index_2 = TYPE_DOMAIN (type_2);
+ if (!index_1 || !index_2)
+ return false;
+ else
+ {
+ tree min_1 = TYPE_MIN_VALUE (index_1);
+ tree min_2 = TYPE_MIN_VALUE (index_2);
+ tree max_1 = TYPE_MAX_VALUE (index_1);
+ tree max_2 = TYPE_MAX_VALUE (index_2);
+ /* If the array types both have unspecified bounds, then
+ MAX_{1,2} will be NULL_TREE. */
+ if (min_1 && min_2 && !max_1 && !max_2)
+ return (integer_zerop (min_1)
+ && integer_zerop (min_2));
+ /* Otherwise, we need the bounds to be fully
+ specified. */
+ if (!min_1 || !min_2 || !max_1 || !max_2)
+ return false;
+ if (TREE_CODE (min_1) != INTEGER_CST
+ || TREE_CODE (min_2) != INTEGER_CST
+ || TREE_CODE (max_1) != INTEGER_CST
+ || TREE_CODE (max_2) != INTEGER_CST)
+ return false;
+ if (tree_int_cst_equal (min_1, min_2))
+ return tree_int_cst_equal (max_1, max_2);
+ else
+ {
+ tree nelts_1 = array_type_nelts (type_1);
+ tree nelts_2 = array_type_nelts (type_2);
+ if (! nelts_1 || ! nelts_2)
+ return false;
+ if (TREE_CODE (nelts_1) != INTEGER_CST
+ || TREE_CODE (nelts_2) != INTEGER_CST)
+ return false;
+ return tree_int_cst_equal (nelts_1, nelts_2);
+ }
+ }
+ }
+
+ case FUNCTION_TYPE:
+ /* Function types are the same if the return type and arguments types
+ are the same. */
+ if (!lto_same_type_p (TREE_TYPE (type_1), TREE_TYPE (type_2)))
+ return false;
+ else
+ {
+ tree parms_1 = TYPE_ARG_TYPES (type_1);
+ tree parms_2 = TYPE_ARG_TYPES (type_2);
+ if (parms_1 == parms_2)
+ return true;
+ else
+ {
+ while (parms_1 && parms_2)
+ {
+ if (!lto_same_type_p (TREE_VALUE (parms_1),
+ TREE_VALUE (parms_2)))
+ return false;
+ parms_1 = TREE_CHAIN (parms_1);
+ parms_2 = TREE_CHAIN (parms_2);
+ }
+ return !parms_1 && !parms_2;
+ }
+ }
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ /* Pointer and reference types are the same if the pointed-to types are
+ the same. */
+ return lto_same_type_p (TREE_TYPE (type_1), TREE_TYPE (type_2));
+
+ case ENUMERAL_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ /* Enumeration and class types are the same if they have the same
+ name. */
+ {
+ tree name_1 = TYPE_NAME (type_1);
+ tree name_2 = TYPE_NAME (type_2);
+ if (!name_1 || !name_2)
+ /* Presumably, anonymous types are all unique. */
+ return false;
+
+ if (TREE_CODE (name_1) == TYPE_DECL)
+ {
+ name_1 = DECL_NAME (name_1);
+ if (! name_1)
+ return false;
+ }
+ gcc_assert (TREE_CODE (name_1) == IDENTIFIER_NODE);
+
+ if (TREE_CODE (name_2) == TYPE_DECL)
+ {
+ name_2 = DECL_NAME (name_2);
+ if (! name_2)
+ return false;
+ }
+ gcc_assert (TREE_CODE (name_2) == IDENTIFIER_NODE);
+
+ /* Identifiers can be compared with pointer equality rather
+ than a string comparison. */
+ return name_1 == name_2;
+ }
+
+ /* FIXME: add pointer to member types. */
+ default:
+ return false;
+ }
+}
+
+/* If TYPE_1 and TYPE_2 can be merged to form a common type, do it.
+ Specifically, if they are both array types that have the same element
+ type and one of them is a complete array type and the other isn't,
+ return the complete array type. Otherwise return NULL_TREE. */
+static tree
+lto_merge_types (tree type_1, tree type_2)
+{
+ if (TREE_CODE (type_1) == ARRAY_TYPE
+ && (TREE_CODE (type_2) == ARRAY_TYPE)
+ && (TYPE_QUALS (type_1) == TYPE_QUALS (type_2))
+ && !TYPE_ATTRIBUTES (type_1) && ! TYPE_ATTRIBUTES (type_2)
+ && (lto_same_type_p (TREE_TYPE (type_1), TREE_TYPE (type_2))))
+ {
+ if (COMPLETE_TYPE_P (type_1) && !COMPLETE_TYPE_P (type_2))
+ return type_1;
+ else if (COMPLETE_TYPE_P (type_2) && !COMPLETE_TYPE_P (type_1))
+ return type_2;
+ else
+ return NULL_TREE;
+ }
+ return NULL_TREE;
+}
+
+/* Returns true iff the union of ATTRIBUTES_1 and ATTRIBUTES_2 can be
+ applied to DECL. */
+static bool
+lto_compatible_attributes_p (tree decl ATTRIBUTE_UNUSED,
+ tree attributes_1,
+ tree attributes_2)
+{
+#if 0
+ /* ??? For now, assume two attribute sets are compatible only if they
+ are both empty. */
+ return !attributes_1 && !attributes_2;
+#else
+ /* FIXME. For the moment, live dangerously, and assume the user knows
+ what he's doing. I don't think the linker would distinguish these cases. */
+ return true || (!attributes_1 && !attributes_2);
+#endif
+}
+
+/* Compute the least common multiple of A and B. */
+
+static inline unsigned
+lto_least_common_multiple (unsigned a, unsigned b)
+{
+ return (a * b) / gcd (a, b);
+}
+
+/* Check if OLD_DECL and NEW_DECL are compatible. */
+
+static bool
+lto_symtab_compatible (tree old_decl, tree new_decl)
+{
+ tree merged_type = NULL_TREE;
+ tree merged_result = NULL_TREE;
+
+ if (TREE_CODE (old_decl) != TREE_CODE (new_decl))
+ {
+ switch (TREE_CODE (new_decl))
+ {
+ case VAR_DECL:
+ gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL);
+ error ("function %qD redeclared as variable", old_decl);
+ return false;
+ case FUNCTION_DECL:
+ gcc_assert (TREE_CODE (old_decl) == VAR_DECL);
+ error ("variable %qD redeclared as function", old_decl);
+ return false;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ if (!lto_same_type_p (TREE_TYPE (old_decl), TREE_TYPE (new_decl)))
+ {
+ /* Allow an array type with unspecified bounds to
+ be merged with an array type whose bounds are specified, so
+ as to allow "extern int i[];" in one file to be combined with
+ "int i[3];" in another. */
+ if (TREE_CODE (new_decl) == VAR_DECL)
+ merged_type = lto_merge_types (TREE_TYPE (old_decl),
+ TREE_TYPE (new_decl));
+ else if (TREE_CODE (new_decl) == FUNCTION_DECL)
+ {
+ if (DECL_IS_BUILTIN (old_decl) || DECL_IS_BUILTIN (new_decl))
+ {
+ tree candidate = match_builtin_function_types (TREE_TYPE (new_decl),
+ TREE_TYPE (old_decl));
+ /* We don't really have source location information at this
+ point, so the above matching was a bit of a gamble. */
+ if (candidate)
+ merged_type = candidate;
+ }
+
+ if (!merged_type
+ /* We want either of the types to have argument types,
+ but not both. */
+ && ((TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != NULL)
+ ^ (TYPE_ARG_TYPES (TREE_TYPE (new_decl)) != NULL)))
+ {
+ /* The situation here is that (in C) somebody was smart
+ enough to use proper declarations in a header file, but
+ the actual definition of the function uses
+ non-ANSI-style argument lists. Or we have a situation
+ where declarations weren't used anywhere and we're
+ merging the actual definition with a use. One of the
+ decls will then have a complete function type, whereas
+ the other will only have a result type. Assume that
+ the more complete type is the right one and don't
+ complain. */
+ if (TYPE_ARG_TYPES (TREE_TYPE (old_decl)))
+ {
+ merged_type = TREE_TYPE (old_decl);
+ merged_result = DECL_RESULT (old_decl);
+ }
+ else
+ {
+ merged_type = TREE_TYPE (new_decl);
+ merged_result = DECL_RESULT (new_decl);
+ }
+ }
+
+ /* If we don't have a merged type yet...sigh. The linker
+ wouldn't complain if the types were mismatched, so we
+ probably shouldn't either. Just use the type from
+ whichever decl appears to be associated with the
+ definition. If for some odd reason neither decl is, the
+ older one wins. */
+ if (!merged_type)
+ {
+ if (!DECL_EXTERNAL (new_decl))
+ {
+ merged_type = TREE_TYPE (new_decl);
+ merged_result = DECL_RESULT (new_decl);
+ }
+ else
+ {
+ merged_type = TREE_TYPE (old_decl);
+ merged_result = DECL_RESULT (old_decl);
+ }
+ }
+ }
+
+ if (!merged_type)
+ {
+ error ("type of %qD does not match original declaration",
+ new_decl);
+ return false;
+ }
+ }
+ if (DECL_UNSIGNED (old_decl) != DECL_UNSIGNED (new_decl))
+ {
+ error ("signedness of %qD does not match original declaration",
+ new_decl);
+ return false;
+ }
+ if (!tree_int_cst_equal (DECL_SIZE (old_decl),
+ DECL_SIZE (new_decl))
+ || !tree_int_cst_equal (DECL_SIZE_UNIT (old_decl),
+ DECL_SIZE_UNIT (new_decl)))
+ {
+ /* Permit cases where we are declaring arrays and at least one of
+ the decls is external and one of the decls has a size whereas
+ the other one does not. */
+ if (!((DECL_EXTERNAL (old_decl) || DECL_EXTERNAL (new_decl))
+ && ((DECL_SIZE (old_decl) == NULL_TREE
+ && DECL_SIZE (new_decl) != NULL_TREE)
+ || (DECL_SIZE (new_decl) == NULL_TREE
+ && DECL_SIZE (old_decl) != NULL_TREE))
+ && TREE_CODE (TREE_TYPE (old_decl)) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (new_decl)) == ARRAY_TYPE))
+ {
+ error ("size of %qD does not match original declaration",
+ new_decl);
+ return false;
+ }
+ }
+ /* Report an error if user-specified alignments do not match. */
+ if ((DECL_USER_ALIGN (old_decl) && DECL_USER_ALIGN (new_decl))
+ && DECL_ALIGN (old_decl) != DECL_ALIGN (new_decl))
+ {
+ error ("alignment of %qD does not match original declaration",
+ new_decl);
+ return false;
+ }
+ if (DECL_MODE (old_decl) != DECL_MODE (new_decl))
+ {
+ /* We can arrive here when we are merging 'extern char foo[]' and
+ 'char foo[SMALLNUM]'; the former is probably BLKmode and the
+ latter is not. In such a case, we should have merged the types
+ already; detect it and don't complain. */
+ if (TREE_CODE (old_decl) == VAR_DECL
+ && TREE_CODE (TREE_TYPE (old_decl)) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (new_decl)) == ARRAY_TYPE
+ && merged_type)
+ ;
+ else
+ {
+ error ("machine mode of %qD does not match original declaration",
+ new_decl);
+ return false;
+ }
+ }
+ if (!lto_compatible_attributes_p (old_decl,
+ DECL_ATTRIBUTES (old_decl),
+ DECL_ATTRIBUTES (new_decl)))
+ {
+ error ("attributes applied to %qD are incompatible with original "
+ "declaration", new_decl);
+ return false;
+ }
+
+ /* We do not require matches for:
+
+ - DECL_NAME
+
+ Only the name used in object files matters.
+
+ - DECL_CONTEXT
+
+ An entity might be declared in a C++ namespace in one file and
+ with a C identifier in another file.
+
+ - TREE_PRIVATE, TREE_PROTECTED
+
+ Access control is the problem of the front end that created the
+ object file.
+
+ Therefore, at this point we have decided to merge the declarations. */
+ return true;
+}
+
+/* Marks decl DECL as having resolution RESOLUTION. */
+
+static void
+lto_symtab_set_resolution (tree decl,
+ ld_plugin_symbol_resolution_t resolution)
+{
+ lto_symtab_decl_t new_entry;
+ void **slot;
+
+ gcc_assert (decl);
+
+ gcc_assert (TREE_PUBLIC (decl));
+ gcc_assert (TREE_CODE (decl) != FUNCTION_DECL || !DECL_ABSTRACT (decl));
+
+ new_entry = GGC_CNEW (struct lto_symtab_decl_def);
+ new_entry->base.node = decl;
+ new_entry->resolution = resolution;
+
+ lto_symtab_maybe_init_hash_tables ();
+ slot = htab_find_slot (lto_symtab_decls, new_entry, INSERT);
+ gcc_assert (!*slot);
+ *slot = new_entry;
+}
+
+/* Get the lto_symtab_identifier_def struct associated with ID
+ if there is one. If there is none and INSERT_P is true, create
+ a new one. */
+
+static lto_symtab_identifier_t
+lto_symtab_get_identifier (tree id, bool insert_p)
+{
+ struct lto_symtab_identifier_def temp;
+ lto_symtab_identifier_t symtab_id;
+ void **slot;
+
+ lto_symtab_maybe_init_hash_tables ();
+ temp.base.node = id;
+ slot = htab_find_slot (lto_symtab_identifiers, &temp,
+ insert_p ? INSERT : NO_INSERT);
+ if (insert_p)
+ {
+ if (*slot)
+ return (lto_symtab_identifier_t) *slot;
+ else
+ {
+ symtab_id = GGC_CNEW (struct lto_symtab_identifier_def);
+ symtab_id->base.node = id;
+ *slot = symtab_id;
+ return symtab_id;
+ }
+ }
+ else
+ return slot ? *slot : NULL;
+}
+
+/* Return the DECL associated with an IDENTIFIER ID or return NULL_TREE
+ if there is none. */
+
+static tree
+lto_symtab_get_identifier_decl (tree id)
+{
+ lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, false);
+ return symtab_id ? symtab_id->decl : NULL_TREE;
+}
+
+/* SET the associated DECL of an IDENTIFIER ID to be DECL. */
+
+static void
+lto_symtab_set_identifier_decl (tree id, tree decl)
+{
+ lto_symtab_identifier_t symtab_id = lto_symtab_get_identifier (id, true);
+ symtab_id->decl = decl;
+}
+
+/* Common helper function for merging variable and function declarations.
+ NEW_DECL is the newly found decl. RESOLUTION is the decl's resolution
+ provided by the linker. */
+
+static void
+lto_symtab_merge_decl (tree new_decl,
+ enum ld_plugin_symbol_resolution resolution)
+{
+ tree old_decl;
+ tree name;
+ ld_plugin_symbol_resolution_t old_resolution;
+
+ gcc_assert (TREE_CODE (new_decl) == VAR_DECL
+ || TREE_CODE (new_decl) == FUNCTION_DECL);
+
+ gcc_assert (TREE_PUBLIC (new_decl));
+
+ /* Check that declarations reaching this function do not have
+ properties inconsistent with having external linkage. If any of
+ these asertions fail, then the object file reader has failed to
+ detect these cases and issue appropriate error messages. */
+ /* FIXME lto: The assertion below may fail incorrectly on a static
+ class member. The problem seems to be the (documented) fact
+ that DECL_NONLOCAL may be set for class instance variables as
+ well as for variables referenced from inner functions. */
+ /*gcc_assert (!DECL_NONLOCAL (new_decl));*/
+ if (TREE_CODE (new_decl) == VAR_DECL)
+ {
+ gcc_assert (!DECL_REGISTER (new_decl));
+ gcc_assert (!(DECL_EXTERNAL (new_decl) && DECL_INITIAL (new_decl)));
+ }
+
+ /* Remember the resolution of this symbol. */
+ lto_symtab_set_resolution (new_decl, resolution);
+
+ /* Retrieve the previous declaration. */
+ name = DECL_ASSEMBLER_NAME (new_decl);
+ old_decl = lto_symtab_get_identifier_decl (name);
+
+ /* If there was no previous declaration, then there is nothing to
+ merge. */
+ if (!old_decl)
+ {
+ lto_symtab_set_identifier_decl (name, new_decl);
+ VEC_safe_push (tree, gc, lto_global_var_decls, new_decl);
+ return;
+ }
+
+ /* The linker may ask us to combine two incompatible symbols. */
+ if (!lto_symtab_compatible (old_decl, new_decl))
+ return;
+
+ old_resolution = lto_symtab_get_resolution (old_decl);
+ gcc_assert (resolution != LDPR_UNKNOWN
+ && resolution != LDPR_UNDEF
+ && old_resolution != LDPR_UNKNOWN
+ && old_resolution != LDPR_UNDEF);
+
+ if (resolution == LDPR_PREVAILING_DEF
+ || resolution == LDPR_PREVAILING_DEF_IRONLY)
+ {
+ if (old_resolution == LDPR_PREVAILING_DEF
+ || old_resolution == LDPR_PREVAILING_DEF_IRONLY)
+ {
+ error ("%qD has already been defined", new_decl);
+ return;
+ }
+ gcc_assert (old_resolution == LDPR_PREEMPTED_IR
+ || old_resolution == LDPR_RESOLVED_IR);
+ lto_symtab_set_identifier_decl (name, new_decl);
+ return;
+ }
+
+ if (resolution == LDPR_PREEMPTED_REG
+ || resolution == LDPR_RESOLVED_EXEC
+ || resolution == LDPR_RESOLVED_DYN)
+ gcc_assert (old_resolution == LDPR_PREEMPTED_REG
+ || old_resolution == LDPR_RESOLVED_EXEC
+ || old_resolution == LDPR_RESOLVED_DYN);
+
+ if (resolution == LDPR_PREEMPTED_IR
+ || resolution == LDPR_RESOLVED_IR)
+ gcc_assert (old_resolution == LDPR_PREVAILING_DEF
+ || old_resolution == LDPR_PREVAILING_DEF_IRONLY
+ || old_resolution == LDPR_PREEMPTED_IR
+ || old_resolution == LDPR_RESOLVED_IR);
+
+ return;
+}
+
+/* Merge the VAR_DECL NEW_VAR with resolution RESOLUTION with any previous
+ declaration with the same name. */
+
+void
+lto_symtab_merge_var (tree new_var, enum ld_plugin_symbol_resolution resolution)
+{
+ lto_symtab_merge_decl (new_var, resolution);
+}
+
+/* Merge the FUNCTION_DECL NEW_FN with resolution RESOLUTION with any previous
+ declaration with the same name. */
+
+void
+lto_symtab_merge_fn (tree new_fn, enum ld_plugin_symbol_resolution resolution)
+{
+ lto_symtab_merge_decl (new_fn, resolution);
+}
+
+/* Given the decl DECL, return the prevailing decl with the same name. */
+
+tree
+lto_symtab_prevailing_decl (tree decl)
+{
+ tree ret;
+ gcc_assert (decl);
+
+ if (!TREE_PUBLIC (decl))
+ return decl;
+
+ /* FIXME lto. There should be no DECL_ABSTRACT in the middle end. */
+ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
+ return decl;
+
+ ret = lto_symtab_get_identifier_decl (DECL_ASSEMBLER_NAME (decl));
+
+ return ret;
+}
+
+/* Return the resolution of DECL. */
+
+enum ld_plugin_symbol_resolution
+lto_symtab_get_resolution (tree decl)
+{
+ struct lto_symtab_decl_def temp, *symtab_decl;
+ void **slot;
+
+ gcc_assert (decl);
+
+ if (!TREE_PUBLIC (decl))
+ return LDPR_PREVAILING_DEF_IRONLY;
+
+ /* LTO FIXME: There should be no DECL_ABSTRACT in the middle end. */
+ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
+ return LDPR_PREVAILING_DEF_IRONLY;
+
+ lto_symtab_maybe_init_hash_tables ();
+ temp.base.node = decl;
+ slot = htab_find_slot (lto_symtab_decls, &temp, NO_INSERT);
+ gcc_assert (slot && *slot);
+ symtab_decl = (struct lto_symtab_decl_def*) *slot;
+ return symtab_decl->resolution;
+}
+
+/* Remove any storage used to store resolution of DECL. */
+
+void
+lto_symtab_clear_resolution (tree decl)
+{
+ struct lto_symtab_decl_def temp;
+ gcc_assert (decl);
+
+ if (!TREE_PUBLIC (decl))
+ return;
+
+ /* LTO FIXME: There should be no DECL_ABSTRACT in the middle end. */
+ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
+ return;
+
+ lto_symtab_maybe_init_hash_tables ();
+ temp.base.node = decl;
+ htab_remove_elt (lto_symtab_decls, &temp);
+}
+
+#include "gt-lto-symtab.h"
Index: gcc/gcc/lto-cgraph.c
===================================================================
--- gcc/gcc/lto-cgraph.c (revision 141379)
+++ gcc/gcc/lto-cgraph.c (working copy)
@@ -51,6 +51,7 @@ Boston, MA 02110-1301, USA. */
#include "lto-section-in.h"
#include "lto-section-out.h"
#include "pointer-set.h"
+#include "lto-tree-in.h"
#include <ctype.h>
/* Call-Graph Streamer.
@@ -456,15 +457,321 @@ output_cgraph (cgraph_node_set set)
}
+/* Overwrite the information in NODE based on FILE_DATA, TAG, FLAGS,
+ STACK_SIZE and SELF_INSNS. This is called either to initialize
+ NODE or to replace the values in it, for instance becasue the first
+ time we saw it, the function body was not available but now it
+ is. */
+
+static void
+input_overwrite_node (struct lto_file_decl_data* file_data,
+ struct cgraph_node *node,
+ enum LTO_cgraph_tags tag,
+ unsigned HOST_WIDEST_INT flags,
+ unsigned int stack_size,
+ unsigned int self_insns)
+{
+ node->aux = (void *)tag;
+ node->local.inline_summary.estimated_self_stack_size = stack_size;
+ node->local.inline_summary.self_insns = self_insns;
+ node->global.insns = self_insns;
+ node->local.lto_file_data = file_data;
+
+ /* This list must be in the reverse order that they are set in
+ output_node. */
+ node->local.vtable_method = lto_get_flag (&flags);
+ node->local.for_functions_valid = lto_get_flag (&flags);
+ node->local.redefined_extern_inline = lto_get_flag (&flags);
+ node->local.disregard_inline_limits = lto_get_flag (&flags);
+ node->local.inlinable = lto_get_flag (&flags);
+ node->local.finalized = lto_get_flag (&flags);
+ node->local.externally_visible = lto_get_flag (&flags);
+ node->local.local = lto_get_flag (&flags);
+ node->needed = lto_get_flag (&flags);
+ node->analyzed = node->local.finalized;
+ node->lowered = node->local.finalized;
+}
+
+/* Read a node from input_block IB. TAG is the node's tag just read.
+ Return the node read or overwriten. NODES points to a vector of nodes
+ read so far. */
+
+static struct cgraph_node *
+input_node (struct lto_file_decl_data* file_data,
+ struct lto_input_block *ib,
+ enum LTO_cgraph_tags tag,
+ VEC(cgraph_node_ptr, heap) *nodes)
+{
+ tree fn_decl;
+ struct cgraph_node *node, *master_clone;
+ unsigned int flags;
+ int stack_size = 0;
+ int self_insns = 0;
+ unsigned decl_index;
+ bool clone_p;
+ int estimated_stack_size = 0;
+ int stack_frame_offset = 0;
+ int ref = LCC_NOT_FOUND;
+ int insns = 0;
+ int estimated_growth = 0;
+ bool inlined = false;
+
+ LTO_DEBUG_TOKEN ("clone_p");
+ clone_p = lto_input_uleb128 (ib);
+
+ if (clone_p)
+ {
+ LTO_DEBUG_TOKEN ("master");
+ master_clone = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
+ gcc_assert (master_clone);
+ node = cgraph_clone_input_node (master_clone);
+ }
+ else
+ {
+ decl_index = lto_input_uleb128 (ib);
+ fn_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
+ LTO_DEBUG_FN_NAME (fn_decl);
+ node = cgraph_node (fn_decl);
+ }
+
+ LTO_DEBUG_TOKEN ("flags");
+ flags = lto_input_uleb128 (ib);
+
+ if (tag == LTO_cgraph_avail_node)
+ {
+ LTO_DEBUG_TOKEN ("stack_size");
+ stack_size = lto_input_sleb128 (ib);
+ LTO_DEBUG_TOKEN ("self_insns");
+ self_insns = lto_input_sleb128 (ib);
+ }
+
+ /* Read additional global data for LTRANS. */
+ if (flag_ltrans)
+ {
+ LTO_DEBUG_TOKEN ("estimated_stack_size");
+ estimated_stack_size = lto_input_sleb128 (ib);
+ LTO_DEBUG_TOKEN ("stack_frame_offset");
+ stack_frame_offset = lto_input_sleb128 (ib);
+ LTO_DEBUG_TOKEN ("inlined_to");
+ ref = lto_input_sleb128 (ib);
+
+ LTO_DEBUG_TOKEN ("insns");
+ insns = lto_input_sleb128 (ib);
+ LTO_DEBUG_TOKEN ("estimated_growth");
+ estimated_growth = lto_input_sleb128 (ib);
+ LTO_DEBUG_TOKEN ("inlined");
+ inlined = lto_input_uleb128 (ib);
+ }
+
+ gcc_assert (!node->aux);
+
+ input_overwrite_node (file_data, node, tag, flags, stack_size,
+ self_insns);
+ if (flag_ltrans)
+ {
+ node->global.estimated_stack_size = estimated_stack_size;
+ node->global.stack_frame_offset = stack_frame_offset;
+ node->global.insns = insns;
+
+ /* Store a reference for now, and fix up later to be a pointer. */
+ node->global.inlined_to = (cgraph_node_ptr) (intptr_t) ref;
+
+ node->global.estimated_growth = estimated_growth;
+ node->global.inlined = inlined;
+ }
+
+ return node;
+}
+
+/* Read an edge from IB. NODES points to a vector of previously read
+ nodes for decoding caller and callee of the edge to be read. */
+
+static void
+input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes)
+{
+ struct cgraph_node *caller, *callee;
+ struct cgraph_edge *edge;
+ unsigned int stmt_id;
+ unsigned int count;
+ unsigned int freq;
+ unsigned int nest;
+ cgraph_inline_failed_t inline_failed;
+ unsigned HOST_WIDEST_INT flags;
+ tree prevailing;
+ enum ld_plugin_symbol_resolution caller_resolution;
+
+ LTO_DEBUG_TOKEN ("caller");
+ caller = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
+ gcc_assert (caller);
+ gcc_assert (caller->decl);
+
+ LTO_DEBUG_TOKEN ("callee");
+ callee = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
+ gcc_assert (callee);
+ gcc_assert (callee->decl);
+
+ caller_resolution = lto_symtab_get_resolution (caller->decl);
+
+ /* FIXME lto: The following assert would currently fail for extern inline
+ functions. */
+
+/* gcc_assert (caller_resolution == LDPR_PREVAILING_DEF */
+/* || caller_resolution == LDPR_PREVAILING_DEF_IRONLY */
+/* || caller_resolution == LDPR_PREEMPTED_REG */
+/* || caller_resolution == LDPR_PREEMPTED_IR); */
+
+ LTO_DEBUG_TOKEN ("stmt");
+ stmt_id = lto_input_uleb128 (ib);
+ LTO_DEBUG_TOKEN ("inline_failed");
+ inline_failed = lto_input_uleb128 (ib);
+ LTO_DEBUG_TOKEN ("count");
+ count = lto_input_uleb128 (ib);
+ LTO_DEBUG_TOKEN ("frequency");
+ freq = lto_input_uleb128 (ib);
+ LTO_DEBUG_TOKEN ("loop_next");
+ nest = lto_input_uleb128 (ib);
+ LTO_DEBUG_TOKEN ("flags");
+ flags = lto_input_uleb128 (ib);
+
+ /* If the caller was preempted, don't create the edge. */
+ if (caller_resolution == LDPR_PREEMPTED_REG
+ || caller_resolution == LDPR_PREEMPTED_IR)
+ return;
+
+ /* Make sure the callee is the prevailing decl. */
+ prevailing = lto_symtab_prevailing_decl (callee->decl);
+
+ /* FIXME lto: remove this once extern inline in handled in lgen. */
+ if (caller_resolution != LDPR_PREVAILING_DEF
+ && caller_resolution != LDPR_PREVAILING_DEF_IRONLY
+ && caller_resolution != LDPR_PREEMPTED_REG
+ && caller_resolution != LDPR_PREEMPTED_IR)
+ {
+ /* If we have a extern inline, make sure it is the prevailing. */
+ gcc_assert (prevailing == callee->decl);
+ }
+
+ if (prevailing != callee->decl)
+ {
+ /* We cannot replace a clone! */
+ gcc_assert (callee == cgraph_node (callee->decl));
+
+
+ callee = cgraph_node (prevailing);
+ gcc_assert (callee);
+ }
+
+ edge = cgraph_create_edge (caller, callee, NULL, count, freq, nest);
+ edge->lto_stmt_uid = stmt_id;
+ edge->inline_failed = inline_failed;
+
+ /* This list must be in the reverse order that they are set in
+ output_edge. */
+ edge->call_stmt_cannot_inline_p = lto_get_flag (&flags);
+ edge->indirect_call = lto_get_flag (&flags);
+}
+
+/* Input a cgraph from IB using the info in FILE_DATA. */
+
+static void
+input_cgraph_1 (struct lto_file_decl_data* file_data,
+ struct lto_input_block *ib)
+{
+ enum LTO_cgraph_tags tag;
+ VEC(cgraph_node_ptr, heap) *nodes = NULL;
+ struct cgraph_node *node;
+ unsigned i;
+
+ tag = lto_input_uleb128 (ib);
+ while (tag)
+ {
+ LTO_DEBUG_INDENT (tag);
+
+ if (tag == LTO_cgraph_edge)
+ input_edge (ib, nodes);
+ else
+ {
+ node = input_node (file_data, ib, tag, nodes);
+ gcc_assert (node);
+ gcc_assert (node->decl);
+ VEC_safe_push (cgraph_node_ptr, heap, nodes, node);
+ }
+
+ LTO_DEBUG_UNDENT();
+ tag = lto_input_uleb128 (ib);
+ }
+
+ if (flag_ltrans)
+ {
+ for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
+ {
+ const int ref = (int) (intptr_t) node->global.inlined_to;
+
+ /* Fixup inlined_to from reference to pointer. */
+ if (ref != LCC_NOT_FOUND)
+ node->global.inlined_to = VEC_index (cgraph_node_ptr, nodes, ref);
+ else
+ node->global.inlined_to = NULL;
+ }
+ }
+
+ for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
+ {
+ tree prevailing = lto_symtab_prevailing_decl (node->decl);
+
+ if (prevailing != node->decl)
+ {
+ cgraph_remove_node (node);
+ VEC_replace (cgraph_node_ptr, nodes, i, NULL);
+ }
+ }
+
+ for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
+ if (node && cgraph_decide_is_function_needed (node))
+ cgraph_mark_needed_node (node);
+
+ VEC_free (cgraph_node_ptr, heap, nodes);
+}
+
/* Input and merge the cgraph from each of the .o files passed to
lto1. */
static void
input_cgraph (void)
{
- lang_hooks.lto.input_cgraph ();
-}
+ struct lto_file_decl_data ** file_data_vec
+ = lto_get_file_decl_data ();
+ struct lto_file_decl_data * file_data;
+ unsigned int j = 0;
+ struct cgraph_node *node;
+
+#ifdef LTO_STREAM_DEBUGGING
+ lto_debug_context.tag_names = LTO_cgraph_tag_names;
+ lto_debug_context.stream_name = "cgraph";
+#endif
+ while ((file_data = file_data_vec[j++]))
+ {
+ const char *data;
+ size_t len;
+ struct lto_input_block *ib
+ = lto_create_simple_input_block (file_data,
+ LTO_section_cgraph,
+ &data, &len);
+ input_cgraph_1 (file_data, ib);
+ lto_destroy_simple_input_block (file_data,
+ LTO_section_cgraph,
+ ib, data, len);
+ }
+
+ /* Clear out the aux field that was used to store enough state to
+ tell which nodes should be overwritten. */
+ for (node = cgraph_nodes; node; node = node->next)
+ {
+ gcc_assert (node->local.lto_file_data);
+ node->aux = NULL;
+ }
+}
struct ipa_opt_pass pass_ipa_lto_cgraph =
Index: gcc/gcc/lto-tree-in.h
===================================================================
--- gcc/gcc/lto-tree-in.h (revision 141379)
+++ gcc/gcc/lto-tree-in.h (working copy)
@@ -119,5 +119,6 @@ extern void lto_symtab_merge_fn (tree ne
extern tree lto_symtab_prevailing_decl (tree decl);
extern enum ld_plugin_symbol_resolution lto_symtab_get_resolution (tree decl);
+extern void lto_symtab_clear_resolution (tree decl);
#endif /* GCC_LTO_TREE_IN_H */
Index: gcc/gcc/langhooks.c
===================================================================
--- gcc/gcc/langhooks.c (revision 141379)
+++ gcc/gcc/langhooks.c (working copy)
@@ -647,9 +647,3 @@ lhd_end_section (void)
saved_section = NULL;
}
}
-
-void
-lhd_input_cgraph (void)
-{
- gcc_unreachable ();
-}
Index: gcc/gcc/langhooks.h
===================================================================
--- gcc/gcc/langhooks.h (revision 141379)
+++ gcc/gcc/langhooks.h (working copy)
@@ -235,9 +235,6 @@ struct lang_hooks_for_lto
/* End the previously begun LTO section. */
void (*end_section) (void);
-
- /* Read cgraph. */
- void (*input_cgraph) (void);
};
/* Language-specific hooks. See langhooks-def.h for defaults. */
Index: gcc/gcc/lto/lto.c
===================================================================
--- gcc/gcc/lto/lto.c (revision 141379)
+++ gcc/gcc/lto/lto.c (working copy)
@@ -929,6 +929,7 @@ free_decl (const void *p, void *data ATT
tree t = CONST_CAST_TREE (ct);
remove_decl_from_map (t);
+ lto_symtab_clear_resolution (t);
ggc_free (t);
return true;
}
Index: gcc/gcc/lto/Make-lang.in
===================================================================
--- gcc/gcc/lto/Make-lang.in (revision 141379)
+++ gcc/gcc/lto/Make-lang.in (working copy)
@@ -27,7 +27,7 @@
LTO_EXE = lto1$(exeext)
# The LTO-specific object files inclued in $(LTO_EXE).
LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-elf.o \
- lto/lto-symtab.o lto/common.o attribs.o
+ lto/common.o attribs.o
LTO_H = lto/lto.h lto-header.h $(LTO_SECTION_IN_H) $(LTO_SECTION_OUT_H) \
$(HASHTAB_H) $(TREE_H)
@@ -100,7 +100,4 @@ lto/lto.o: lto/lto.c $(CONFIG_H) $(CGRAP
pointer-set.h vec.h $(BITMAP_H) $(IPA_PROP_H) lto/common.h
lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
toplev.h $(LTO_H) $(TM_H)
-lto/lto-symtab.o: lto/lto-symtab.c lto-tree-in.h $(CONFIG_H) coretypes.h \
- $(SYSTEM_H) toplev.h $(LTO_H) $(LTO_TREE_H) $(GGC_H) $(LAMBDA_H) \
- $(GIMPLE_H)
lto/common.o: lto/common.h
Index: gcc/gcc/lto/lto-tree.h
===================================================================
--- gcc/gcc/lto/lto-tree.h (revision 141379)
+++ gcc/gcc/lto/lto-tree.h (working copy)
@@ -27,14 +27,11 @@ Boston, MA 02110-1301, USA. */
struct lang_identifier GTY(())
{
struct tree_identifier base;
- /* LTO_IDENTIFIER_DECL */
- tree decl;
- enum ld_plugin_symbol_resolution resolution;
};
struct lang_decl GTY(())
{
- enum ld_plugin_symbol_resolution resolution;
+ int dummy; /* Added because ggc does not like empty structs. */
};
struct lang_type GTY(())
@@ -59,20 +56,6 @@ union lang_tree_node GTY(
desc ("tree_node_structure (&%h)"))) generic;
};
-/* Return NODE (an IDENTIFIER_NODE) as a pointer to a
- "lang_identifier". */
-#define LANG_IDENTIFIER_CAST(NODE) \
- ((struct lang_identifier*)IDENTIFIER_NODE_CHECK (NODE))
-
-/* Return the VAR_DECL or FUNCTION_DECL with external linkage whose
- DECL_ASSEMBLER_NAME is NODE, or NULL_TREE if there is no such
- declaration. */
-#define LTO_IDENTIFIER_DECL(NODE) \
- (LANG_IDENTIFIER_CAST (NODE)->decl)
-
-#define LTO_DECL_RESOLUTION(NODE) \
- (DECL_LANG_SPECIFIC (NODE)->resolution)
-
/* Vector to keep track of external variables we've seen so far. */
extern GTY(()) VEC(tree,gc) *lto_global_var_decls;
Index: gcc/gcc/lto/lto-symtab.c
===================================================================
--- gcc/gcc/lto/lto-symtab.c (revision 141379)
+++ gcc/gcc/lto/lto-symtab.c (working copy)
@@ -1,598 +0,0 @@
-/* LTO symbol table.
- Copyright 2006 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 2, 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 COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "toplev.h"
-#include "tree.h"
-#include "lto.h"
-#include "gimple.h"
-#include "lto-tree.h"
-#include "lto-tree-in.h"
-#include "ggc.h" /* lambda.h needs this */
-#include "lambda.h" /* gcd */
-
-/* Vector to keep track of external variables we've seen so far. */
-VEC(tree,gc) *lto_global_var_decls;
-
-/* Returns true iff TYPE_1 and TYPE_2 are the same type. */
-
-static bool
-lto_same_type_p (tree type_1, tree type_2)
-{
- unsigned int code;
-
- /* Check first for the obvious case of pointer identity. */
- if (type_1 == type_2)
- return true;
-
- /* Check that we have two types to compare. */
- if (type_1 == NULL_TREE || type_2 == NULL_TREE)
- return false;
-
- /* Can't be the same type if the types don't have the same code. */
- code = TREE_CODE (type_1);
- if (code != TREE_CODE (type_2))
- return false;
-
- /* Can't be the same type if they have different CV qualifiers. */
- if (TYPE_QUALS (type_1) != TYPE_QUALS (type_2))
- return false;
-
- /* "If GNU attributes are present, types which could be the same be it not
- for their GNU attributes may in fact be different due to the use of GNU
- attributes." Hmmm. Punt on this for now and assume they're different
- if we see attributes on either type. */
- if (TYPE_ATTRIBUTES (type_1) || TYPE_ATTRIBUTES (type_2))
- return false;
-
- switch (code)
- {
- case VOID_TYPE:
- /* Void types are the same in all translation units. */
- return true;
-
- case INTEGER_TYPE:
- case BOOLEAN_TYPE:
- /* Corresponding integral types are the same. */
- return (TYPE_PRECISION (type_1) == TYPE_PRECISION (type_2)
- && TYPE_UNSIGNED (type_1) == TYPE_UNSIGNED (type_2)
- && tree_int_cst_equal (TYPE_SIZE (type_1), TYPE_SIZE (type_2))
- && TYPE_ALIGN (type_1) == TYPE_ALIGN (type_2)
- && TYPE_STRING_FLAG (type_1) == TYPE_STRING_FLAG (type_2));
-
- case REAL_TYPE:
- /* Corresponding float types are the same. */
- return (TYPE_PRECISION (type_1) == TYPE_PRECISION (type_2)
- && tree_int_cst_equal (TYPE_SIZE (type_1), TYPE_SIZE (type_2))
- && TYPE_ALIGN (type_1) == TYPE_ALIGN (type_2));
-
- case ARRAY_TYPE:
- /* Array types are the same if the element types are the same and
- the number of elements are the same. */
- if (!lto_same_type_p (TREE_TYPE (type_1), TREE_TYPE (type_2))
- || TYPE_STRING_FLAG (type_1) != TYPE_STRING_FLAG (type_2))
- return false;
- else
- {
- tree index_1 = TYPE_DOMAIN (type_1);
- tree index_2 = TYPE_DOMAIN (type_2);
- if (!index_1 || !index_2)
- return false;
- else
- {
- tree min_1 = TYPE_MIN_VALUE (index_1);
- tree min_2 = TYPE_MIN_VALUE (index_2);
- tree max_1 = TYPE_MAX_VALUE (index_1);
- tree max_2 = TYPE_MAX_VALUE (index_2);
- /* If the array types both have unspecified bounds, then
- MAX_{1,2} will be NULL_TREE. */
- if (min_1 && min_2 && !max_1 && !max_2)
- return (integer_zerop (min_1)
- && integer_zerop (min_2));
- /* Otherwise, we need the bounds to be fully
- specified. */
- if (!min_1 || !min_2 || !max_1 || !max_2)
- return false;
- if (TREE_CODE (min_1) != INTEGER_CST
- || TREE_CODE (min_2) != INTEGER_CST
- || TREE_CODE (max_1) != INTEGER_CST
- || TREE_CODE (max_2) != INTEGER_CST)
- return false;
- if (tree_int_cst_equal (min_1, min_2))
- return tree_int_cst_equal (max_1, max_2);
- else
- {
- tree nelts_1 = array_type_nelts (type_1);
- tree nelts_2 = array_type_nelts (type_2);
- if (! nelts_1 || ! nelts_2)
- return false;
- if (TREE_CODE (nelts_1) != INTEGER_CST
- || TREE_CODE (nelts_2) != INTEGER_CST)
- return false;
- return tree_int_cst_equal (nelts_1, nelts_2);
- }
- }
- }
-
- case FUNCTION_TYPE:
- /* Function types are the same if the return type and arguments types
- are the same. */
- if (!lto_same_type_p (TREE_TYPE (type_1), TREE_TYPE (type_2)))
- return false;
- else
- {
- tree parms_1 = TYPE_ARG_TYPES (type_1);
- tree parms_2 = TYPE_ARG_TYPES (type_2);
- if (parms_1 == parms_2)
- return true;
- else
- {
- while (parms_1 && parms_2)
- {
- if (!lto_same_type_p (TREE_VALUE (parms_1),
- TREE_VALUE (parms_2)))
- return false;
- parms_1 = TREE_CHAIN (parms_1);
- parms_2 = TREE_CHAIN (parms_2);
- }
- return !parms_1 && !parms_2;
- }
- }
-
- case POINTER_TYPE:
- case REFERENCE_TYPE:
- /* Pointer and reference types are the same if the pointed-to types are
- the same. */
- return lto_same_type_p (TREE_TYPE (type_1), TREE_TYPE (type_2));
-
- case ENUMERAL_TYPE:
- case RECORD_TYPE:
- case UNION_TYPE:
- case QUAL_UNION_TYPE:
- /* Enumeration and class types are the same if they have the same
- name. */
- {
- tree name_1 = TYPE_NAME (type_1);
- tree name_2 = TYPE_NAME (type_2);
- if (!name_1 || !name_2)
- /* Presumably, anonymous types are all unique. */
- return false;
-
- if (TREE_CODE (name_1) == TYPE_DECL)
- {
- name_1 = DECL_NAME (name_1);
- if (! name_1)
- return false;
- }
- gcc_assert (TREE_CODE (name_1) == IDENTIFIER_NODE);
-
- if (TREE_CODE (name_2) == TYPE_DECL)
- {
- name_2 = DECL_NAME (name_2);
- if (! name_2)
- return false;
- }
- gcc_assert (TREE_CODE (name_2) == IDENTIFIER_NODE);
-
- /* Identifiers can be compared with pointer equality rather
- than a string comparison. */
- return name_1 == name_2;
- }
-
- /* FIXME: add pointer to member types. */
- default:
- return false;
- }
-}
-
-/* If TYPE_1 and TYPE_2 can be merged to form a common type, do it.
- Specifically, if they are both array types that have the same element
- type and one of them is a complete array type and the other isn't,
- return the complete array type. Otherwise return NULL_TREE. */
-static tree
-lto_merge_types (tree type_1, tree type_2)
-{
- if (TREE_CODE (type_1) == ARRAY_TYPE
- && (TREE_CODE (type_2) == ARRAY_TYPE)
- && (TYPE_QUALS (type_1) == TYPE_QUALS (type_2))
- && !TYPE_ATTRIBUTES (type_1) && ! TYPE_ATTRIBUTES (type_2)
- && (lto_same_type_p (TREE_TYPE (type_1), TREE_TYPE (type_2))))
- {
- if (COMPLETE_TYPE_P (type_1) && !COMPLETE_TYPE_P (type_2))
- return type_1;
- else if (COMPLETE_TYPE_P (type_2) && !COMPLETE_TYPE_P (type_1))
- return type_2;
- else
- return NULL_TREE;
- }
- return NULL_TREE;
-}
-
-/* Returns true iff the union of ATTRIBUTES_1 and ATTRIBUTES_2 can be
- applied to DECL. */
-static bool
-lto_compatible_attributes_p (tree decl ATTRIBUTE_UNUSED,
- tree attributes_1,
- tree attributes_2)
-{
-#if 0
- /* ??? For now, assume two attribute sets are compatible only if they
- are both empty. */
- return !attributes_1 && !attributes_2;
-#else
- /* FIXME. For the moment, live dangerously, and assume the user knows
- what he's doing. I don't think the linker would distinguish these cases. */
- return true || (!attributes_1 && !attributes_2);
-#endif
-}
-
-/* Compute the least common multiple of A and B. */
-
-static inline unsigned
-lto_least_common_multiple (unsigned a, unsigned b)
-{
- return (a * b) / gcd (a, b);
-}
-
-/* Check if OLD_DECL and NEW_DECL are compatible. */
-
-static bool
-lto_symtab_compatible (tree old_decl, tree new_decl)
-{
- tree merged_type = NULL_TREE;
- tree merged_result = NULL_TREE;
-
- if (TREE_CODE (old_decl) != TREE_CODE (new_decl))
- {
- switch (TREE_CODE (new_decl))
- {
- case VAR_DECL:
- gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL);
- error ("function %qD redeclared as variable", old_decl);
- return false;
- case FUNCTION_DECL:
- gcc_assert (TREE_CODE (old_decl) == VAR_DECL);
- error ("variable %qD redeclared as function", old_decl);
- return false;
- default:
- gcc_unreachable ();
- }
- }
- if (!lto_same_type_p (TREE_TYPE (old_decl), TREE_TYPE (new_decl)))
- {
- /* Allow an array type with unspecified bounds to
- be merged with an array type whose bounds are specified, so
- as to allow "extern int i[];" in one file to be combined with
- "int i[3];" in another. */
- if (TREE_CODE (new_decl) == VAR_DECL)
- merged_type = lto_merge_types (TREE_TYPE (old_decl),
- TREE_TYPE (new_decl));
- else if (TREE_CODE (new_decl) == FUNCTION_DECL)
- {
- if (DECL_IS_BUILTIN (old_decl) || DECL_IS_BUILTIN (new_decl))
- {
- tree candidate = match_builtin_function_types (TREE_TYPE (new_decl),
- TREE_TYPE (old_decl));
- /* We don't really have source location information at this
- point, so the above matching was a bit of a gamble. */
- if (candidate)
- merged_type = candidate;
- }
-
- if (!merged_type
- /* We want either of the types to have argument types,
- but not both. */
- && ((TYPE_ARG_TYPES (TREE_TYPE (old_decl)) != NULL)
- ^ (TYPE_ARG_TYPES (TREE_TYPE (new_decl)) != NULL)))
- {
- /* The situation here is that (in C) somebody was smart
- enough to use proper declarations in a header file, but
- the actual definition of the function uses
- non-ANSI-style argument lists. Or we have a situation
- where declarations weren't used anywhere and we're
- merging the actual definition with a use. One of the
- decls will then have a complete function type, whereas
- the other will only have a result type. Assume that
- the more complete type is the right one and don't
- complain. */
- if (TYPE_ARG_TYPES (TREE_TYPE (old_decl)))
- {
- merged_type = TREE_TYPE (old_decl);
- merged_result = DECL_RESULT (old_decl);
- }
- else
- {
- merged_type = TREE_TYPE (new_decl);
- merged_result = DECL_RESULT (new_decl);
- }
- }
-
- /* If we don't have a merged type yet...sigh. The linker
- wouldn't complain if the types were mismatched, so we
- probably shouldn't either. Just use the type from
- whichever decl appears to be associated with the
- definition. If for some odd reason neither decl is, the
- older one wins. */
- if (!merged_type)
- {
- if (!DECL_EXTERNAL (new_decl))
- {
- merged_type = TREE_TYPE (new_decl);
- merged_result = DECL_RESULT (new_decl);
- }
- else
- {
- merged_type = TREE_TYPE (old_decl);
- merged_result = DECL_RESULT (old_decl);
- }
- }
- }
-
- if (!merged_type)
- {
- error ("type of %qD does not match original declaration",
- new_decl);
- return false;
- }
- }
- if (DECL_UNSIGNED (old_decl) != DECL_UNSIGNED (new_decl))
- {
- error ("signedness of %qD does not match original declaration",
- new_decl);
- return false;
- }
- if (!tree_int_cst_equal (DECL_SIZE (old_decl),
- DECL_SIZE (new_decl))
- || !tree_int_cst_equal (DECL_SIZE_UNIT (old_decl),
- DECL_SIZE_UNIT (new_decl)))
- {
- /* Permit cases where we are declaring arrays and at least one of
- the decls is external and one of the decls has a size whereas
- the other one does not. */
- if (!((DECL_EXTERNAL (old_decl) || DECL_EXTERNAL (new_decl))
- && ((DECL_SIZE (old_decl) == NULL_TREE
- && DECL_SIZE (new_decl) != NULL_TREE)
- || (DECL_SIZE (new_decl) == NULL_TREE
- && DECL_SIZE (old_decl) != NULL_TREE))
- && TREE_CODE (TREE_TYPE (old_decl)) == ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (new_decl)) == ARRAY_TYPE))
- {
- error ("size of %qD does not match original declaration",
- new_decl);
- return false;
- }
- }
- /* Report an error if user-specified alignments do not match. */
- if ((DECL_USER_ALIGN (old_decl) && DECL_USER_ALIGN (new_decl))
- && DECL_ALIGN (old_decl) != DECL_ALIGN (new_decl))
- {
- error ("alignment of %qD does not match original declaration",
- new_decl);
- return false;
- }
- if (DECL_MODE (old_decl) != DECL_MODE (new_decl))
- {
- /* We can arrive here when we are merging 'extern char foo[]' and
- 'char foo[SMALLNUM]'; the former is probably BLKmode and the
- latter is not. In such a case, we should have merged the types
- already; detect it and don't complain. */
- if (TREE_CODE (old_decl) == VAR_DECL
- && TREE_CODE (TREE_TYPE (old_decl)) == ARRAY_TYPE
- && TREE_CODE (TREE_TYPE (new_decl)) == ARRAY_TYPE
- && merged_type)
- ;
- else
- {
- error ("machine mode of %qD does not match original declaration",
- new_decl);
- return false;
- }
- }
- if (!lto_compatible_attributes_p (old_decl,
- DECL_ATTRIBUTES (old_decl),
- DECL_ATTRIBUTES (new_decl)))
- {
- error ("attributes applied to %qD are incompatible with original "
- "declaration", new_decl);
- return false;
- }
-
- /* We do not require matches for:
-
- - DECL_NAME
-
- Only the name used in object files matters.
-
- - DECL_CONTEXT
-
- An entity might be declared in a C++ namespace in one file and
- with a C identifier in another file.
-
- - TREE_PRIVATE, TREE_PROTECTED
-
- Access control is the problem of the front end that created the
- object file.
-
- Therefore, at this point we have decided to merge the declarations. */
- return true;
-}
-
-/* Marks decl DECL as having resolution RESOLUTION. */
-
-static void
-lto_symtab_set_resolution (tree decl, ld_plugin_symbol_resolution_t resolution)
-{
- gcc_assert (decl);
-
- gcc_assert (TREE_PUBLIC (decl));
- gcc_assert (TREE_CODE (decl) != FUNCTION_DECL || !DECL_ABSTRACT (decl));
-
- gcc_assert (!DECL_LANG_SPECIFIC (decl));
- DECL_LANG_SPECIFIC (decl) = GGC_NEW (struct lang_decl);
- LTO_DECL_RESOLUTION (decl) = resolution;
-}
-
-/* Common helper function for merging variable and function declarations.
- NEW_DECL is the newly found decl. RESOLUTION is the decl's resolution
- provided by the linker. */
-
-static void
-lto_symtab_merge_decl (tree new_decl,
- enum ld_plugin_symbol_resolution resolution)
-{
- tree old_decl;
- tree name;
- ld_plugin_symbol_resolution_t old_resolution;
-
- gcc_assert (TREE_CODE (new_decl) == VAR_DECL
- || TREE_CODE (new_decl) == FUNCTION_DECL);
-
- gcc_assert (TREE_PUBLIC (new_decl));
-
- /* Check that declarations reaching this function do not have
- properties inconsistent with having external linkage. If any of
- these asertions fail, then the object file reader has failed to
- detect these cases and issue appropriate error messages. */
- /* FIXME lto: The assertion below may fail incorrectly on a static
- class member. The problem seems to be the (documented) fact
- that DECL_NONLOCAL may be set for class instance variables as
- well as for variables referenced from inner functions. */
- /*gcc_assert (!DECL_NONLOCAL (new_decl));*/
- if (TREE_CODE (new_decl) == VAR_DECL)
- {
- gcc_assert (!DECL_REGISTER (new_decl));
- gcc_assert (!(DECL_EXTERNAL (new_decl) && DECL_INITIAL (new_decl)));
- }
-
- /* Remember the resolution of this symbol. */
- lto_symtab_set_resolution (new_decl, resolution);
-
- /* Retrieve the previous declaration. */
- name = DECL_ASSEMBLER_NAME (new_decl);
- old_decl = LTO_IDENTIFIER_DECL (name);
-
- /* If there was no previous declaration, then there is nothing to
- merge. */
- if (!old_decl)
- {
- LTO_IDENTIFIER_DECL (name) = new_decl;
- VEC_safe_push (tree, gc, lto_global_var_decls, new_decl);
- return;
- }
-
- /* The linker may ask us to combine two incompatible symbols. */
- if (!lto_symtab_compatible (old_decl, new_decl))
- return;
-
- old_resolution = lto_symtab_get_resolution (old_decl);
- gcc_assert (resolution != LDPR_UNKNOWN
- && resolution != LDPR_UNDEF
- && old_resolution != LDPR_UNKNOWN
- && old_resolution != LDPR_UNDEF);
-
- if (resolution == LDPR_PREVAILING_DEF
- || resolution == LDPR_PREVAILING_DEF_IRONLY)
- {
- if (old_resolution == LDPR_PREVAILING_DEF
- || old_resolution == LDPR_PREVAILING_DEF_IRONLY)
- {
- error ("%qD has already been defined", new_decl);
- return;
- }
- gcc_assert (old_resolution == LDPR_PREEMPTED_IR
- || old_resolution == LDPR_RESOLVED_IR);
- LTO_IDENTIFIER_DECL (name) = new_decl;
- return;
- }
-
- if (resolution == LDPR_PREEMPTED_REG
- || resolution == LDPR_RESOLVED_EXEC
- || resolution == LDPR_RESOLVED_DYN)
- gcc_assert (old_resolution == LDPR_PREEMPTED_REG
- || old_resolution == LDPR_RESOLVED_EXEC
- || old_resolution == LDPR_RESOLVED_DYN);
-
- if (resolution == LDPR_PREEMPTED_IR
- || resolution == LDPR_RESOLVED_IR)
- gcc_assert (old_resolution == LDPR_PREVAILING_DEF
- || old_resolution == LDPR_PREVAILING_DEF_IRONLY
- || old_resolution == LDPR_PREEMPTED_IR
- || old_resolution == LDPR_RESOLVED_IR);
-
- return;
-}
-
-/* Merge the VAR_DECL NEW_VAR with resolution RESOLUTION with any previous
- declaration with the same name. */
-
-void
-lto_symtab_merge_var (tree new_var, enum ld_plugin_symbol_resolution resolution)
-{
- lto_symtab_merge_decl (new_var, resolution);
-}
-
-/* Merge the FUNCTION_DECL NEW_FN with resolution RESOLUTION with any previous
- declaration with the same name. */
-
-void
-lto_symtab_merge_fn (tree new_fn, enum ld_plugin_symbol_resolution resolution)
-{
- lto_symtab_merge_decl (new_fn, resolution);
-}
-
-/* Given the decl DECL, return the prevailing decl with the same name. */
-
-tree
-lto_symtab_prevailing_decl (tree decl)
-{
- tree ret;
- gcc_assert (decl);
-
- if (!TREE_PUBLIC (decl))
- return decl;
-
- /* FIXME lto. There should be no DECL_ABSTRACT in the middle end. */
- if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
- return decl;
-
- ret = LTO_IDENTIFIER_DECL (DECL_ASSEMBLER_NAME (decl));
-
- return ret;
-}
-
-/* Return the resolution of DECL. */
-
-enum ld_plugin_symbol_resolution
-lto_symtab_get_resolution (tree decl)
-{
- gcc_assert (decl);
-
- if (!TREE_PUBLIC (decl))
- return LDPR_PREVAILING_DEF_IRONLY;
-
- /* LTO FIXME: There should be no DECL_ABSTRACT in the middle end. */
- if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl))
- return LDPR_PREVAILING_DEF_IRONLY;
-
- return LTO_DECL_RESOLUTION (decl);
-}
Index: gcc/gcc/lto/lto-lang.c
===================================================================
--- gcc/gcc/lto/lto-lang.c (revision 141379)
+++ gcc/gcc/lto/lto-lang.c (working copy)
@@ -37,7 +37,6 @@ Boston, MA 02110-1301, USA. */
#include "toplev.h"
#include "libfuncs.h"
#include "except.h"
-#include "cgraph.h"
#include "lto/common.h"
#include "lto-tree-in.h"
@@ -1069,323 +1068,6 @@ static void lto_init_ts (void)
tree_contains_struct[NAMESPACE_DECL][TS_DECL_MINIMAL] = 1;
}
-
-/* Overwrite the information in NODE based on FILE_DATA, TAG, FLAGS,
- STACK_SIZE and SELF_INSNS. This is called either to initialize
- NODE or to replace the values in it, for instance becasue the first
- time we saw it, the function body was not available but now it
- is. */
-
-static void
-input_overwrite_node (struct lto_file_decl_data* file_data,
- struct cgraph_node *node,
- enum LTO_cgraph_tags tag,
- unsigned HOST_WIDEST_INT flags,
- unsigned int stack_size,
- unsigned int self_insns)
-{
- node->aux = (void *)tag;
- node->local.inline_summary.estimated_self_stack_size = stack_size;
- node->local.inline_summary.self_insns = self_insns;
- node->global.insns = self_insns;
- node->local.lto_file_data = file_data;
-
- /* This list must be in the reverse order that they are set in
- output_node. */
- node->local.vtable_method = lto_get_flag (&flags);
- node->local.for_functions_valid = lto_get_flag (&flags);
- node->local.redefined_extern_inline = lto_get_flag (&flags);
- node->local.disregard_inline_limits = lto_get_flag (&flags);
- node->local.inlinable = lto_get_flag (&flags);
- node->local.finalized = lto_get_flag (&flags);
- node->local.externally_visible = lto_get_flag (&flags);
- node->local.local = lto_get_flag (&flags);
- node->needed = lto_get_flag (&flags);
- node->analyzed = node->local.finalized;
- node->lowered = node->local.finalized;
-}
-
-/* Read a node from input_block IB. TAG is the node's tag just read.
- Return the node read or overwriten. NODES points to a vector of nodes
- read so far. */
-
-static struct cgraph_node *
-input_node (struct lto_file_decl_data* file_data,
- struct lto_input_block *ib,
- enum LTO_cgraph_tags tag,
- VEC(cgraph_node_ptr, heap) *nodes)
-{
- tree fn_decl;
- struct cgraph_node *node, *master_clone;
- unsigned int flags;
- int stack_size = 0;
- int self_insns = 0;
- unsigned decl_index;
- bool clone_p;
- int estimated_stack_size = 0;
- int stack_frame_offset = 0;
- int ref = LCC_NOT_FOUND;
- int insns = 0;
- int estimated_growth = 0;
- bool inlined = false;
-
- LTO_DEBUG_TOKEN ("clone_p");
- clone_p = lto_input_uleb128 (ib);
-
- if (clone_p)
- {
- LTO_DEBUG_TOKEN ("master");
- master_clone = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
- gcc_assert (master_clone);
- node = cgraph_clone_input_node (master_clone);
- }
- else
- {
- decl_index = lto_input_uleb128 (ib);
- fn_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
- LTO_DEBUG_FN_NAME (fn_decl);
- node = cgraph_node (fn_decl);
- }
-
- LTO_DEBUG_TOKEN ("flags");
- flags = lto_input_uleb128 (ib);
-
- if (tag == LTO_cgraph_avail_node)
- {
- LTO_DEBUG_TOKEN ("stack_size");
- stack_size = lto_input_sleb128 (ib);
- LTO_DEBUG_TOKEN ("self_insns");
- self_insns = lto_input_sleb128 (ib);
- }
-
- /* Read additional global data for LTRANS. */
- if (flag_ltrans)
- {
- LTO_DEBUG_TOKEN ("estimated_stack_size");
- estimated_stack_size = lto_input_sleb128 (ib);
- LTO_DEBUG_TOKEN ("stack_frame_offset");
- stack_frame_offset = lto_input_sleb128 (ib);
- LTO_DEBUG_TOKEN ("inlined_to");
- ref = lto_input_sleb128 (ib);
-
- LTO_DEBUG_TOKEN ("insns");
- insns = lto_input_sleb128 (ib);
- LTO_DEBUG_TOKEN ("estimated_growth");
- estimated_growth = lto_input_sleb128 (ib);
- LTO_DEBUG_TOKEN ("inlined");
- inlined = lto_input_uleb128 (ib);
- }
-
- gcc_assert (!node->aux);
-
- input_overwrite_node (file_data, node, tag, flags, stack_size,
- self_insns);
- if (flag_ltrans)
- {
- node->global.estimated_stack_size = estimated_stack_size;
- node->global.stack_frame_offset = stack_frame_offset;
- node->global.insns = insns;
-
- /* Store a reference for now, and fix up later to be a pointer. */
- node->global.inlined_to = (cgraph_node_ptr) (intptr_t) ref;
-
- node->global.estimated_growth = estimated_growth;
- node->global.inlined = inlined;
- }
-
- return node;
-}
-
-/* Read an edge from IB. NODES points to a vector of previously read
- nodes for decoding caller and callee of the edge to be read. */
-
-static void
-input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes)
-{
- struct cgraph_node *caller, *callee;
- struct cgraph_edge *edge;
- unsigned int stmt_id;
- unsigned int count;
- unsigned int freq;
- unsigned int nest;
- cgraph_inline_failed_t inline_failed;
- unsigned HOST_WIDEST_INT flags;
- tree prevailing;
- enum ld_plugin_symbol_resolution caller_resolution;
-
- LTO_DEBUG_TOKEN ("caller");
- caller = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
- gcc_assert (caller);
- gcc_assert (caller->decl);
-
- LTO_DEBUG_TOKEN ("callee");
- callee = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
- gcc_assert (callee);
- gcc_assert (callee->decl);
-
- caller_resolution = lto_symtab_get_resolution (caller->decl);
-
- /* FIXME lto: The following assert would currently fail for extern inline
- functions. */
-
-/* gcc_assert (caller_resolution == LDPR_PREVAILING_DEF */
-/* || caller_resolution == LDPR_PREVAILING_DEF_IRONLY */
-/* || caller_resolution == LDPR_PREEMPTED_REG */
-/* || caller_resolution == LDPR_PREEMPTED_IR); */
-
- LTO_DEBUG_TOKEN ("stmt");
- stmt_id = lto_input_uleb128 (ib);
- LTO_DEBUG_TOKEN ("inline_failed");
- inline_failed = lto_input_uleb128 (ib);
- LTO_DEBUG_TOKEN ("count");
- count = lto_input_uleb128 (ib);
- LTO_DEBUG_TOKEN ("frequency");
- freq = lto_input_uleb128 (ib);
- LTO_DEBUG_TOKEN ("loop_next");
- nest = lto_input_uleb128 (ib);
- LTO_DEBUG_TOKEN ("flags");
- flags = lto_input_uleb128 (ib);
-
- /* If the caller was preempted, don't create the edge. */
- if (caller_resolution == LDPR_PREEMPTED_REG
- || caller_resolution == LDPR_PREEMPTED_IR)
- return;
-
- /* Make sure the callee is the prevailing decl. */
- prevailing = lto_symtab_prevailing_decl (callee->decl);
-
- /* FIXME lto: remove this once extern inline in handled in lgen. */
- if (caller_resolution != LDPR_PREVAILING_DEF
- && caller_resolution != LDPR_PREVAILING_DEF_IRONLY
- && caller_resolution != LDPR_PREEMPTED_REG
- && caller_resolution != LDPR_PREEMPTED_IR)
- {
- /* If we have a extern inline, make sure it is the prevailing. */
- gcc_assert (prevailing == callee->decl);
- }
-
- if (prevailing != callee->decl)
- {
- /* We cannot replace a clone! */
- gcc_assert (callee == cgraph_node (callee->decl));
-
-
- callee = cgraph_node (prevailing);
- gcc_assert (callee);
- }
-
- edge = cgraph_create_edge (caller, callee, NULL, count, freq, nest);
- edge->lto_stmt_uid = stmt_id;
- edge->inline_failed = inline_failed;
-
- /* This list must be in the reverse order that they are set in
- output_edge. */
- edge->call_stmt_cannot_inline_p = lto_get_flag (&flags);
- edge->indirect_call = lto_get_flag (&flags);
-}
-
-/* Input a cgraph from IB using the info in FILE_DATA. */
-
-static void
-input_cgraph_1 (struct lto_file_decl_data* file_data,
- struct lto_input_block *ib)
-{
- enum LTO_cgraph_tags tag;
- VEC(cgraph_node_ptr, heap) *nodes = NULL;
- struct cgraph_node *node;
- unsigned i;
-
- tag = lto_input_uleb128 (ib);
- while (tag)
- {
- LTO_DEBUG_INDENT (tag);
-
- if (tag == LTO_cgraph_edge)
- input_edge (ib, nodes);
- else
- {
- node = input_node (file_data, ib, tag, nodes);
- gcc_assert (node);
- gcc_assert (node->decl);
- VEC_safe_push (cgraph_node_ptr, heap, nodes, node);
- }
-
- LTO_DEBUG_UNDENT();
- tag = lto_input_uleb128 (ib);
- }
-
- if (flag_ltrans)
- {
- for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
- {
- const int ref = (int) (intptr_t) node->global.inlined_to;
-
- /* Fixup inlined_to from reference to pointer. */
- if (ref != LCC_NOT_FOUND)
- node->global.inlined_to = VEC_index (cgraph_node_ptr, nodes, ref);
- else
- node->global.inlined_to = NULL;
- }
- }
-
- for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
- {
- tree prevailing = lto_symtab_prevailing_decl (node->decl);
-
- if (prevailing != node->decl)
- {
- cgraph_remove_node (node);
- VEC_replace (cgraph_node_ptr, nodes, i, NULL);
- }
- }
-
- for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++)
- if (node && cgraph_decide_is_function_needed (node))
- cgraph_mark_needed_node (node);
-
- VEC_free (cgraph_node_ptr, heap, nodes);
-}
-
-/* Input and merge the cgraph from each of the .o files passed to
- lto1. */
-
-static void
-input_cgraph (void)
-{
- struct lto_file_decl_data ** file_data_vec
- = lto_get_file_decl_data ();
- struct lto_file_decl_data * file_data;
- unsigned int j = 0;
- struct cgraph_node *node;
-
-#ifdef LTO_STREAM_DEBUGGING
- lto_debug_context.tag_names = LTO_cgraph_tag_names;
- lto_debug_context.stream_name = "cgraph";
-#endif
-
- while ((file_data = file_data_vec[j++]))
- {
- const char *data;
- size_t len;
- struct lto_input_block *ib
- = lto_create_simple_input_block (file_data,
- LTO_section_cgraph,
- &data, &len);
- input_cgraph_1 (file_data, ib);
- lto_destroy_simple_input_block (file_data,
- LTO_section_cgraph,
- ib, data, len);
- }
-
- /* Clear out the aux field that was used to store enough state to
- tell which nodes should be overwritten. */
- for (node = cgraph_nodes; node; node = node->next)
- {
- gcc_assert (node->local.lto_file_data);
- node->aux = NULL;
- }
-}
-
#undef LANG_HOOKS_NAME
#define LANG_HOOKS_NAME "GNU GIMPLE"
#undef LANG_HOOKS_INIT_OPTIONS
@@ -1437,8 +1119,6 @@ input_cgraph (void)
#define LANG_HOOKS_APPEND_DATA lto_elf_append_data
#undef LANG_HOOKS_END_SECTION
#define LANG_HOOKS_END_SECTION lto_elf_end_section
-#undef LANG_HOOKS_INPUT_CGRAPH
-#define LANG_HOOKS_INPUT_CGRAPH input_cgraph
#undef LANG_HOOKS_INIT_TS
#define LANG_HOOKS_INIT_TS lto_init_ts
Index: gcc/gcc/Makefile.in
===================================================================
--- gcc/gcc/Makefile.in (revision 141379)
+++ gcc/gcc/Makefile.in (working copy)
@@ -388,6 +388,9 @@ FIBHEAP_H = $(srcdir)/../include/fibhe
PARTITION_H = $(srcdir)/../include/partition.h
MD5_H = $(srcdir)/../include/md5.h
+# Linker plugin API header
+PLUGIN_API_H = $(srcdir)/../include/plugin-api.h
+
# Default native SYSTEM_HEADER_DIR, to be overridden by targets.
NATIVE_SYSTEM_HEADER_DIR = /usr/include
# Default cross SYSTEM_HEADER_DIR, to be overridden by targets.
@@ -871,6 +874,7 @@ LTO_TAGS_H = lto-tags.h tree.h sbitmap.h
LTO_SECTION_H = lto-section.h lto-header.h
LTO_SECTION_IN_H = lto-section-in.h lto-header.h
LTO_SECTION_OUT_H = lto-section-in.h lto-section.h
+LTO_TREE_IN_H = lto-tree-in.h $(LTO_SECTION_IN_H) $(PLUGIN_API_H)
TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H)
IPA_PROP_H = ipa-prop.h $(TREE_H) vec.h $(CGRAPH_H)
GSTAB_H = gstab.h stab.def
@@ -1149,6 +1153,7 @@ OBJS-common = \
lto-section-in.o \
lto-section-out.o \
lto-stream-debug.o \
+ lto-symtab.o \
lto-wpa-fixup.o \
mcf.o \
mode-switching.o \
@@ -2064,12 +2069,13 @@ lto-cgraph.o: lto-cgraph.c $(CONFIG_H) $
$(VARRAY_H) $(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) tree-iterator.h \
tree-pass.h tree-flow.h $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) \
except.h debug.h $(TIMEVAR_H) $(LTO_TAGS_H) $(LTO_SECTION_IN_H) \
- $(LTO_SECTION_OUT_H) output.h dwarf2asm.h dwarf2out.h pointer-set.h
+ $(LTO_SECTION_OUT_H) output.h dwarf2asm.h dwarf2out.h pointer-set.h \
+ $(LTO_TREE_IN_H)
lto-function-in.o: lto-function-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TOPLEV_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h $(VARRAY_H) \
$(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) tree-iterator.h tree-pass.h \
tree-flow.h $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) except.h \
- debug.h $(TIMEVAR_H) $(LTO_TAGS_H) lto-tree-flags.def \
+ debug.h $(TIMEVAR_H) $(LTO_TAGS_H) lto-tree-flags.def $(LTO_TREE_IN_H) \
lto-tree-tags.def $(LTO_SECTION_IN_H) output.h dwarf2asm.h dwarf2out.h
lto-function-out.o : lto-function-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TOPLEV_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
@@ -2089,6 +2095,9 @@ lto-section-out.o : lto-section-out.c $(
tree-pass.h tree-flow.h $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) \
except.h debug.h $(TIMEVAR_H) lto-header.h $(LTO_SECTION_OUT_H) output.h \
dwarf2asm.h dwarf2out.h $(BITMAP_H)
+lto-symtab.o: lto-symtab.c $(LTO_TREE_IN_H) $(CONFIG_H) coretypes.h \
+ $(SYSTEM_H) toplev.h $(LTO_TREE_H) $(GGC_H) $(LAMBDA_H) \
+ $(GIMPLE_H) $(HASHTAB_H) $(LTO_TREE_IN_H) gt-lto-symtab.h
lto-wpa-fixup.o: lto-wpa-fixup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TOPLEV_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) tree-pass.h \
$(CGRAPH_H) $(FUNCTION_H) $(DIAGNOSTIC_H) vec.h $(BITMAP_H) $(TIMEVAR_H) \
@@ -3375,6 +3384,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp
$(srcdir)/tree-phinodes.c \
$(srcdir)/ipa-reference.c $(srcdir)/tree-ssa-structalias.h \
$(srcdir)/tree-ssa-structalias.c \
+ $(srcdir)/lto-symtab.c \
@all_gtfiles@
# Compute the list of GT header files from the corresponding C sources,
Index: gcc/gcc/langhooks-def.h
===================================================================
--- gcc/gcc/langhooks-def.h (revision 141379)
+++ gcc/gcc/langhooks-def.h (working copy)
@@ -227,18 +227,15 @@ extern tree lhd_make_node (enum tree_cod
extern void lhd_begin_section (const char *);
extern void lhd_append_data (const void *, size_t, void *);
extern void lhd_end_section (void);
-extern void lhd_input_cgraph (void);
#define LANG_HOOKS_BEGIN_SECTION lhd_begin_section
#define LANG_HOOKS_APPEND_DATA lhd_append_data
#define LANG_HOOKS_END_SECTION lhd_end_section
-#define LANG_HOOKS_INPUT_CGRAPH lhd_input_cgraph
#define LANG_HOOKS_LTO { \
LANG_HOOKS_BEGIN_SECTION, \
LANG_HOOKS_APPEND_DATA, \
- LANG_HOOKS_END_SECTION, \
- LANG_HOOKS_INPUT_CGRAPH \
+ LANG_HOOKS_END_SECTION \
}
/* The whole thing. The structure is defined in langhooks.h. */
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [LTO][PATCH] Move lto-symtab.c out of lto and remove input_cgraph lang-hook.
2008-10-28 7:18 [LTO][PATCH] Move lto-symtab.c out of lto and remove input_cgraph lang-hook Doug Kwan (關振德)
@ 2008-10-28 13:34 ` Diego Novillo
0 siblings, 0 replies; 2+ messages in thread
From: Diego Novillo @ 2008-10-28 13:34 UTC (permalink / raw)
To: Doug Kwan (關振德); +Cc: gcc-patches, Rafael Espindola
2008/10/27 Doug Kwan (???) <dougkwan@google.com>:
> +/* A poor man's symbol table. This hashes identifier to prevailing DECL
> + if there is one. */
This comment is stale now. Not needed anymore.
> +/* Compute the least common multiple of A and B. */
> +
> +static inline unsigned
> +lto_least_common_multiple (unsigned a, unsigned b)
> +{
> + return (a * b) / gcd (a, b);
> +}
This appears to be unused now.
OK if testing succeeds.
Diego.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2008-10-28 12:30 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-10-28 7:18 [LTO][PATCH] Move lto-symtab.c out of lto and remove input_cgraph lang-hook Doug Kwan (關振德)
2008-10-28 13:34 ` Diego Novillo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).