public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [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).