[lto] Re-implement pass_ipa_free_lang_specifics [1/3]

Diego Novillo dnovillo@google.com
Mon Jan 26 19:42:00 GMT 2009


This is the final patch I committed.  I had held on to it because
it was showing 10 failures while building internal code.  I had
inadvertently switched two arguments in one of the calls to
walk_tree in find_decls_types_r.


Diego.


	* tree.h (TYPE_MAXVAL): Define.
	(TYPE_MINVAL): Define.
	* tree.c: Include cgraph.h, timevar.h and except.h.
	(free_lang_data_in_type): Rename from reset_type_lang_specific.
	Change argument to be the type to process.
	Change return type to void.
	Update all users.
	(set_asm_name): Remove.  Update all users.
	(free_lang_data_in_decl): Rename from
	reset_decl_lang_specific.
	Change argument to be the decl to process.
	Change return type to void.
	Update all users.
	Also analyze DECL_SIZE in RESULT_DECLs.
	(struct free_lang_data_d): Declare.
	(find_decls_types_r): New.
	(get_eh_types_for_runtime): Move from lto-function-out.c.
	(find_decls_types_in_eh_region): New.
	(find_decls_types_in_node): New.
	(find_decls_types_in_var): New.
	(free_lang_data_in_cgraph): New.
	(free_lang_data): Rename from free_lang_specifics
	Call free_lang_data_in_cgraph.
	Set char_type_node to unsigned_char_type_node if -funsigned-char
	was given.
	(gate_free_lang_data): Rename from gate_free_lang_specifics.
	Update all users.
	(pass_ipa_free_lang_data): Rename from free_lang_specifics.
	Update all users.
	Add timer TV_IPA_FREE_LANG_DATA.
	* Makefile.in (tree.o): Add dependency on CGRAPH_H,
	TIMEVAR_H and except.h.
	* lto-function-out.c (get_eh_types_for_runtime): Move to tree.c.
	(output_eh_region): Do not call get_eh_types_for_runtime.
	* timevar.def (TV_IPA_FREE_LANG_DATA): Define.
	* langhooks.h (struct lang_hooks): Rename
	free_lang_specifics to free_lang_data.
	Update all users.
	* langhooks-def.h (LANG_HOOKS_FREE_LANG_DATA): Rename
	from LANG_HOOKS_RESET_LANG_SPECIFICS.  Update all users.
	* except.c (output_ttype): Only call lookup_type_for_runtime
	if TYPE is actually a type.


	* tree.c (uid2type_map): Remove.  Update all users.
	(decl_for_uid_map): Remove.  Update all users.
	(insert_decl_to_uid_decl_map): Remove.  Update all users.
	(insert_type_to_uid_type_map): Remove.  Update all users.
	(uid_type_map_eq): Remove.  Update all users.
	(uid_type_map_hash): Remove.  Update all users.
	(insert_decl_to_uid_decl_map): Remove.  Update all users.
	(remove_decl_from_map): Remove.  Update all users.


	* tree.c (free_lang_data): Set lang_hooks.types_compatible_p
	to gimple_types_compatible_p.
	* gimple.c (gimple_types_compatible_p): Moved from
	lto/lto-lang.c.  Renamed from lto_types_compatible_p.
	* gimple.h (gimple_types_compatible_p): Declare.


cp/ChangeLog.lto

2009-01-26  Diego Novillo  <dnovillo@google.com>

	* tree.c (cp_free_lang_data): Rename from cp_reset_lang_specifics.
	Update all users.

lto/ChangeLog

	* lto-lang.c (LANG_HOOKS_TYPES_COMPATIBLE_P): Update.

	* lto-lang.c (lto_types_compatible_p): Move to gimple.c
	and rename into gimple_types_compatible_p.

Index: tree.c
===================================================================
--- tree.c	(revision 143674)
+++ tree.c	(revision 143675)
@@ -54,6 +54,9 @@ along with GCC; see the file COPYING3.
 #include "tree-pass.h"
 #include "langhooks-def.h"
 #include "diagnostic.h"
+#include "cgraph.h"
+#include "timevar.h"
+#include "except.h"

 /* Tree code classes.  */

@@ -148,15 +151,6 @@ static GTY(()) int next_decl_uid;
 /* Unique id for next type created.  */
 static GTY(()) int next_type_uid = 1;

-static GTY ((if_marked ("ggc_marked_p"), param_is (union tree_node)))
-     htab_t uid2type_map;
-
-/* Mapping from unique DECL_UID to the decl tree node.  */
-static GTY ((if_marked ("ggc_marked_p"), param_is (union tree_node)))
-     htab_t decl_for_uid_map;
-
-static void insert_decl_to_uid_decl_map (tree);
-
 /* Since we cannot rehash a type after it is in the table, we have to
    keep the hash code.  */

@@ -272,41 +266,6 @@ const char * const omp_clause_code_name[
 

 /* Init tree.c.  */

-/* Add tree NODE into the UID2TYPE_MAP hash table. */
-
-static void
-insert_type_to_uid_type_map (tree node)
-{
-  void **slot;
-  struct tree_type key;
-
-  key.uid = TYPE_UID (node);
-  slot = htab_find_slot_with_hash (uid2type_map,
-				   &key, TYPE_UID (node), INSERT);
-
-  gcc_assert (!*slot);
-
-  *(tree *)slot = node;
-}
-
-/* Compares tree VA and tree VB.  */
-
-static int
-uid_type_map_eq (const void *va, const void *vb)
-{
-  const_tree a = (const_tree) va;
-  const_tree b = (const_tree) vb;
-  return (a->type.uid == b->type.uid);
-}
-
-/* Hash the tree ITEM. */
-
-static unsigned int
-uid_type_map_hash (const void *item)
-{
-  return ((const_tree)item)->type.uid;
-}
-
 void
 init_ttree (void)
 {
@@ -329,12 +288,6 @@ init_ttree (void)

   int_cst_node = make_node (INTEGER_CST);

-  decl_for_uid_map = htab_create_ggc (4093, uid_decl_map_hash,
-				      uid_decl_map_eq, NULL);
-
-  uid2type_map = htab_create_ggc (4093, uid_type_map_hash,
-				  uid_type_map_eq, NULL);
-
   cl_option_hash_table = htab_create_ggc (64, cl_option_hash_hash,
 					  cl_option_hash_eq, NULL);

@@ -736,8 +689,6 @@ make_node_stat (enum tree_code code MEM_
 	}
       DECL_SOURCE_LOCATION (t) = input_location;
       DECL_UID (t) = next_decl_uid++;
-      insert_decl_to_uid_decl_map (t);
-
       break;

     case tcc_type:
@@ -753,7 +704,6 @@ make_node_stat (enum tree_code code MEM_

       /* We have not yet computed the alias set for this type.  */
       TYPE_ALIAS_SET (t) = -1;
-      insert_type_to_uid_type_map (t);
       break;

     case tcc_constant:
@@ -828,7 +778,6 @@ copy_node_stat (tree node MEM_STAT_DECL)
 	  SET_DECL_RESTRICT_BASE (t, DECL_GET_RESTRICT_BASE (node));
 	  DECL_BASED_ON_RESTRICT_P (t) = 1;
 	}
-      insert_decl_to_uid_decl_map (t);
     }
   else if (TREE_CODE_CLASS (code) == tcc_type)
     {
@@ -847,7 +796,6 @@ copy_node_stat (tree node MEM_STAT_DECL)
 	  TYPE_CACHED_VALUES_P (t) = 0;
 	  TYPE_CACHED_VALUES (t) = NULL_TREE;
 	}
-      insert_type_to_uid_type_map (t);
     }

   return t;
@@ -3560,45 +3508,6 @@ build_nt_call_list (tree fn, tree arglis
   return t;
 }

-/* Insert the declaration NODE into the map mapping its unique uid
-   back to the tree.  */
-
-static void
-insert_decl_to_uid_decl_map (tree node)
-{
-  void **slot;
-  struct tree_decl_minimal key;
-
-  key.uid = DECL_UID (node);
-  slot = htab_find_slot_with_hash (decl_for_uid_map,
-				   &key, DECL_UID (node), INSERT);
-
-  /* We should never try to re-insert a decl with the same uid.
-     ???  The C++ frontend breaks this invariant.  Hopefully in a
-     non-fatal way, so just overwrite the slot in this case.  */
-#if 0
-  gcc_assert (!*slot);
-#endif
-
-  *(tree *)slot = node;
-}
-
-/* Remove the declaration tree DECL from the global UID to decl map.
-   This needs to be called if you ggc_free a decl tree, otherwise
-   garbage collection will take care of it.  */
-
-void
-remove_decl_from_map (tree decl)
-{
-    struct tree_decl_minimal key;
-
-    key.uid = DECL_UID (decl);
-#if ENABLE_CHECKING
-    gcc_assert (decl == htab_find_with_hash (decl_for_uid_map, &key, key.uid));
-#endif
-    htab_remove_elt_with_hash (decl_for_uid_map, &key, key.uid);
-}
-
 

 /* Create a DECL_... node of code CODE, name NAME and data type TYPE.
    We do NOT enter this node in any sort of symbol table.
@@ -3884,13 +3793,15 @@ build_type_attribute_variant (tree ttype
 					    TYPE_QUALS (ttype));
 }

-/* Helper function of free_lang_specifics. */
+/* Reset all language specific information still present in TYPE.  */

-static int
-reset_type_lang_specific (void **slot, void *unused ATTRIBUTE_UNUSED)
+static void
+free_lang_data_in_type (tree type)
 {
-  tree type = *(tree *) slot;
-  lang_hooks.reset_lang_specifics (type);
+  gcc_assert (TYPE_P (type));
+
+  /* Give the FE a chance to remove its own data first.  */
+  lang_hooks.free_lang_data (type);

   TREE_LANG_FLAG_0 (type) = 0;
   TREE_LANG_FLAG_1 (type) = 0;
@@ -3981,12 +3892,9 @@ reset_type_lang_specific (void **slot, v
      scoping and should not be part of the IR.
      FIXME lto: This will break debug info generation.  */
   TYPE_CONTEXT (type) = NULL_TREE;
-
-  return 1;
 }


-
 /* Return true if DECL may need an assembler name to be set.  */

 static inline bool
@@ -4021,29 +3929,16 @@ need_assembler_name_p (tree decl)
 }


-/* Helper function of free_lang_specifics.
-   Set the assembler name for nodes that may need one.  */
-
-static int
-set_asm_name (void **slot, void *unused ATTRIBUTE_UNUSED)
-{
-  tree decl = *((tree *) slot);
-
-  if (need_assembler_name_p (decl))
-    lang_hooks.set_decl_assembler_name (decl);
-
-  return 1;
-}
-
-
-/* Helper function of free_lang_specifics. */
+/* Reset all language specific information still present in symbol
+   DECL.  */

-static int
-reset_decl_lang_specific (void **slot, void *unused ATTRIBUTE_UNUSED)
+static void
+free_lang_data_in_decl (tree decl)
 {
-  tree decl = *(tree *) slot;
+  gcc_assert (DECL_P (decl));

-  lang_hooks.reset_lang_specifics (decl);
+  /* Give the FE a chance to remove its own data first.  */
+  lang_hooks.free_lang_data (decl);

   TREE_LANG_FLAG_0 (decl) = 0;
   TREE_LANG_FLAG_1 (decl) = 0;
@@ -4056,9 +3951,9 @@ reset_decl_lang_specific (void **slot, v
   if (TREE_CODE (decl) == CONST_DECL)
     DECL_CONTEXT (decl) = NULL_TREE;

+  /* Ignore any intervening types, because we are going to clear their
+     TYPE_CONTEXT fields.  */
   if (TREE_CODE (decl) != FIELD_DECL)
-    /* Ignore any intervening types, because we
-       are going to clear their TYPE_CONTEXT fields.  */
     DECL_CONTEXT (decl) = decl_function_context (decl);

   if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)
@@ -4078,7 +3973,9 @@ reset_decl_lang_specific (void **slot, v
        }
    }

-  if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == FIELD_DECL)
+  if (TREE_CODE (decl) == PARM_DECL
+      || TREE_CODE (decl) == FIELD_DECL
+      || TREE_CODE (decl) == RESULT_DECL)
     {
       tree unit_size = DECL_SIZE_UNIT (decl);
       tree size = DECL_SIZE (decl);
@@ -4123,30 +4020,315 @@ reset_decl_lang_specific (void **slot, v
 	 in cgraph_node.  */
       DECL_CONTEXT (decl) = NULL_TREE;
     }
+}

-  return 1;
+/* Data used when collecting DECLs and TYPEs for language data removal.  */
+
+struct free_lang_data_d
+{
+  /* Set of traversed objects.  Used to avoid duplicate visits.  */
+  struct pointer_set_t *pset;
+
+  /* Array of symbols to process with free_lang_data_in_decl.  */
+  VEC(tree,heap) *decls;
+
+  /* Array of types to process with free_lang_data_in_type.  */
+  VEC(tree,heap) *types;
+};
+
+
+/* Operand callback helper for free_lang_data_in_node.  *TP is the
+   subtree operand being considered.  */
+
+static tree
+find_decls_types_r (tree *tp, int *ws ATTRIBUTE_UNUSED, void *data)
+{
+  tree t = *tp;
+  struct free_lang_data_d *fld = (struct free_lang_data_d *) data;
+
+  if (DECL_P (t))
+    {
+      /* Note that walk_tree does not traverse every possible field in
+	 decls, so we have to do our own traversals here.  */
+      VEC_safe_push (tree, heap, fld->decls, t);
+
+      walk_tree (&DECL_NAME (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&DECL_CONTEXT (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&DECL_SIZE (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&DECL_SIZE_UNIT (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&DECL_INITIAL (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&DECL_ATTRIBUTES (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&DECL_ABSTRACT_ORIGIN (t), find_decls_types_r, fld,
fld->pset);
+
+      if (TREE_CODE (t) == FUNCTION_DECL)
+	{
+	  walk_tree (&DECL_ARGUMENTS (t), find_decls_types_r, fld, fld->pset);
+	  walk_tree (&DECL_RESULT (t), find_decls_types_r, fld, fld->pset);
+	}
+      else if (TREE_CODE (t) == TYPE_DECL)
+	{
+	  walk_tree (&DECL_ARGUMENT_FLD (t), find_decls_types_r, fld,
+		     fld->pset);
+	  walk_tree (&DECL_VINDEX (t), find_decls_types_r, fld, fld->pset);
+	}
+      else if (TREE_CODE (t) == FIELD_DECL)
+	{
+	  walk_tree (&DECL_FIELD_OFFSET (t), find_decls_types_r, fld,
+		     fld->pset);
+	  walk_tree (&DECL_BIT_FIELD_TYPE (t), find_decls_types_r, fld,
+		     fld->pset);
+	  walk_tree (&DECL_QUALIFIER (t), find_decls_types_r, fld, fld->pset);
+	  walk_tree (&DECL_FIELD_BIT_OFFSET (t), find_decls_types_r, fld,
+		     fld->pset);
+	  walk_tree (&DECL_FCONTEXT (t), find_decls_types_r, fld, fld->pset);
+	}
+      else if (TREE_CODE (t) == VAR_DECL)
+	{
+	  walk_tree (&DECL_SECTION_NAME (t), find_decls_types_r, fld,
+		     fld->pset);
+	  walk_tree (&DECL_COMDAT_GROUP (t), find_decls_types_r, fld,
+		     fld->pset);
+	}
+    }
+  else if (TYPE_P (t))
+    {
+      /* Note that walk_tree does not traverse every possible field in
+	 types, so we have to do our own traversals here.  */
+      VEC_safe_push (tree, heap, fld->types, t);
+
+      walk_tree (&TYPE_CACHED_VALUES (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_SIZE (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_SIZE_UNIT (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_ATTRIBUTES (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_POINTER_TO (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_REFERENCE_TO (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_NAME (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_MINVAL (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_MAXVAL (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_NEXT_VARIANT (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_MAIN_VARIANT (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_CONTEXT (t), find_decls_types_r, fld, fld->pset);
+      walk_tree (&TYPE_CANONICAL (t), find_decls_types_r, fld, fld->pset);
+    }
+
+  if (TREE_TYPE (t))
+    walk_tree (&TREE_TYPE (t), find_decls_types_r, fld, fld->pset);
+
+  /* Do not recurse into TREE_CHAIN to avoid blowing up the stack.  */
+  for (tp = &TREE_CHAIN (t); *tp; tp = &TREE_CHAIN (*tp))
+    {
+      tree saved_chain = TREE_CHAIN (*tp);
+      TREE_CHAIN (*tp) = NULL_TREE;
+      walk_tree (tp, find_decls_types_r, fld, fld->pset);
+      TREE_CHAIN (*tp) = saved_chain;
+    }
+
+  return NULL_TREE;
 }

-/* Free resources that are used by FE but are not needed once they are done. */

-static unsigned
-free_lang_specifics (void)
+/* Translate all the types in LIST with the corresponding runtime
+   types.  */
+
+static tree
+get_eh_types_for_runtime (tree list)
 {
-  struct cgraph_node *node;
+  tree head, prev;

-  /* Set assembler names now, as callbacks from the back-end
-     will fail after we strip DECL_CONTEXT from declaration nodes.  */
-  htab_traverse (decl_for_uid_map, set_asm_name, NULL);
+  if (list == NULL_TREE)
+    return NULL_TREE;

-  for (node = cgraph_nodes; node; node = node->next)
+  head = build_tree_list (0, lookup_type_for_runtime (TREE_VALUE (list)));
+  prev = head;
+  list = TREE_CHAIN (list);
+  while (list)
     {
-      tree decl = node->decl;
-      if (!DECL_ASSEMBLER_NAME_SET_P (decl))
-	lang_hooks.set_decl_assembler_name (decl);
+      tree n = build_tree_list (0, lookup_type_for_runtime
(TREE_VALUE (list)));
+      TREE_CHAIN (prev) = n;
+      prev = TREE_CHAIN (prev);
+      list = TREE_CHAIN (list);
     }

-  htab_traverse (decl_for_uid_map, reset_decl_lang_specific, NULL);
-  htab_traverse (uid2type_map, reset_type_lang_specific, NULL);
+  return head;
+}
+
+
+/* Find decls and types referenced in EH region R and store them in
+   FLD->DECLS and FLD->TYPES.  */
+
+static void
+find_decls_types_in_eh_region (eh_region r, struct free_lang_data_d *fld)
+{
+  if (r == NULL)
+    return;
+
+  /* The types referenced in R must first be changed to the EH types
+     used at runtime.  This removes references to FE types in the
+     region.  */
+  if (r->type == ERT_CATCH)
+    {
+      tree list = r->u.eh_catch.type_list;
+      r->u.eh_catch.type_list = get_eh_types_for_runtime (list);
+      walk_tree (&r->u.eh_catch.type_list, find_decls_types_r, fld, fld->pset);
+    }
+  else if (r->type == ERT_ALLOWED_EXCEPTIONS)
+    {
+      tree list = r->u.allowed.type_list;
+      r->u.allowed.type_list = get_eh_types_for_runtime (list);
+      walk_tree (&r->u.allowed.type_list, find_decls_types_r, fld, fld->pset);
+    }
+}
+
+
+/* Find decls and types referenced in cgraph node N and store them in
+   FLD->DECLS and FLD->TYPES.  Unlike pass_referenced_vars, this will
+   look for *every* kind of DECL and TYPE node reachable from N,
+   including those embedded inside types and decls (i.e,, TYPE_DECLs,
+   NAMESPACE_DECLs, etc).  */
+
+static void
+find_decls_types_in_node (struct cgraph_node *n, struct free_lang_data_d *fld)
+{
+  basic_block bb;
+  struct function *fn;
+
+  /* Although free_lang_data_in_cgraph will set the assembler name on
+     most DECLs, it refuses to do it on unused ones.  For cgraph
+     nodes, we need to set it even if it's seemingly unused.  */
+  if (!DECL_ASSEMBLER_NAME_SET_P (n->decl))
+    lang_hooks.set_decl_assembler_name (n->decl);
+
+  walk_tree (&n->decl, find_decls_types_r, fld, fld->pset);
+
+  if (!gimple_has_body_p (n->decl))
+    return;
+
+  gcc_assert (current_function_decl == NULL_TREE && cfun == NULL);
+
+  fn = DECL_STRUCT_FUNCTION (n->decl);
+
+  /* Traverse EH regions in FN.  */
+  if (fn->eh->region_array)
+    {
+      unsigned i;
+      eh_region r;
+
+      for (i = 0; VEC_iterate (eh_region, fn->eh->region_array, i, r); i++)
+	find_decls_types_in_eh_region (r, fld);
+    }
+
+  /* Traverse every statement in FN.  */
+  FOR_EACH_BB_FN (bb, fn)
+    {
+      gimple_stmt_iterator si;
+      unsigned i;
+
+      for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
+	{
+	  gimple phi = gsi_stmt (si);
+
+	  for (i = 0; i < gimple_phi_num_args (phi); i++)
+	    {
+	      tree *arg_p = gimple_phi_arg_def_ptr (phi, i);
+	      walk_tree (arg_p, find_decls_types_r, fld, fld->pset);
+	    }
+	}
+
+      for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
+	{
+	  gimple stmt = gsi_stmt (si);
+
+	  for (i = 0; i < gimple_num_ops (stmt); i++)
+	    {
+	      tree *arg_p = gimple_op_ptr (stmt, i);
+	      walk_tree (arg_p, find_decls_types_r, fld, fld->pset);
+	    }
+	}
+    }
+}
+
+
+/* Find decls and types referenced in varpool node N and store them in
+   FLD->DECLS and FLD->TYPES.  Unlike pass_referenced_vars, this will
+   look for *every* kind of DECL and TYPE node reachable from N,
+   including those embedded inside types and decls (i.e,, TYPE_DECLs,
+   NAMESPACE_DECLs, etc).  */
+
+static void
+find_decls_types_in_var (struct varpool_node *v, struct free_lang_data_d *fld)
+{
+  walk_tree (&v->decl, find_decls_types_r, fld, fld->pset);
+}
+
+
+/* Free language specific information for every operand and expression
+   in every node of the call graph.  This process operates in three stages:
+
+   1- Every callgraph node and varpool node is traversed looking for
+      decls and types embedded in them.  This is a more exhaustive
+      search than that done by find_referenced_vars, because it will
+      also collect individual fields, decls embedded in types, etc.
+
+   2- All the decls found are sent to free_lang_data_in_decl.
+
+   3- All the types found are sent to free_lang_data_in_type.
+
+   The ordering between decls and types is important because
+   free_lang_data_in_decl sets assembler names, which includes
+   mangling.  So types cannot be freed up until assembler names have
+   been set up.  */
+
+static void
+free_lang_data_in_cgraph (void)
+{
+  struct cgraph_node *n;
+  struct varpool_node *v;
+  struct free_lang_data_d fld;
+  tree t;
+  unsigned i;
+
+  /* Initialize sets and arrays to store referenced decls and types.  */
+  fld.pset = pointer_set_create ();
+  fld.decls = VEC_alloc (tree, heap, 100);
+  fld.types = VEC_alloc (tree, heap, 100);
+
+  /* Find decls and types in the body of every function in the callgraph.  */
+  for (n = cgraph_nodes; n; n = n->next)
+    find_decls_types_in_node (n, &fld);
+
+  /* Find decls and types in every varpool symbol.  */
+  for (v = varpool_nodes_queue; v; v = v->next_needed)
+    find_decls_types_in_var (v, &fld);
+
+  /* Set the assembler name on every decl found.  We need to do this
+     now because free_lang_data_in_decl will invalidate data needed
+     for mangling.  This breaks mangling on interdependent decls.  */
+  for (i = 0; VEC_iterate (tree, fld.decls, i, t); i++)
+    if (need_assembler_name_p (t))
+      lang_hooks.set_decl_assembler_name (t);
+
+  /* Traverse every decl found freeing its language data.  */
+  for (i = 0; VEC_iterate (tree, fld.decls, i, t); i++)
+    free_lang_data_in_decl (t);
+
+  /* Traverse every type found freeing its language data.  */
+  for (i = 0; VEC_iterate (tree, fld.types, i, t); i++)
+    free_lang_data_in_type (t);
+
+  pointer_set_destroy (fld.pset);
+  VEC_free (tree, heap, fld.decls);
+  VEC_free (tree, heap, fld.types);
+}
+
+
+/* Free resources that are used by FE but are not needed once they are done. */
+
+static unsigned
+free_lang_data (void)
+{
+  /* Traverse the IL resetting language specific information for
+     operands, expressions, etc.  */
+  free_lang_data_in_cgraph ();

   /* FIXME lto.  This is a hack.  ptrdiff_type_node is only created
      by the C/C++ FE.  This should be converted to some similar
@@ -4157,10 +4339,11 @@ free_lang_specifics (void)
      a variant copy of ptr_type_node for front-end purposes.  */
   fileptr_type_node = ptr_type_node;

-  /* Reset some langhooks. */
+  /* Reset some langhooks.  */
   lang_hooks.callgraph.analyze_expr = NULL;
+  lang_hooks.types_compatible_p = gimple_types_compatible_p;

-  /* FIXME lto: We have to compute these names early. */
+  /* FIXME lto: We have to compute these names early.  */
   lang_hooks.dwarf_name = lhd_dwarf_name;
   lang_hooks.decl_printable_name = lhd_decl_printable_name;

@@ -4179,29 +4362,29 @@ free_lang_specifics (void)
 }


-/* Gate function for free_lang_specifics.  FIXME lto.  This should be
+/* Gate function for free_lang_data.  FIXME lto.  This should be
    unconditional and not depend on whether we're producing LTO
    information and it should be done very early on.  This currently
    breaks libstdc++ builds, though.  */

 static bool
-gate_free_lang_specifics (void)
+gate_free_lang_data (void)
 {
   return flag_generate_lto;
 }


-struct simple_ipa_opt_pass pass_ipa_free_lang_specifics =
+struct simple_ipa_opt_pass pass_ipa_free_lang_data =
 {
  {
   SIMPLE_IPA_PASS,
   NULL,					/* name */
-  gate_free_lang_specifics,		/* gate */
-  free_lang_specifics,			/* execute */
+  gate_free_lang_data,			/* gate */
+  free_lang_data,			/* execute */
   NULL,					/* sub */
   NULL,					/* next */
   0,					/* static_pass_number */
-  0,					/* tv_id */
+  TV_IPA_FREE_LANG_DATA,		/* tv_id */
   0,	                                /* properties_required */
   0,					/* properties_provided */
   0,					/* properties_destroyed */
Index: tree.h
===================================================================
--- tree.h	(revision 143674)
+++ tree.h	(revision 143675)
@@ -2098,6 +2098,8 @@ struct tree_block GTY(())
 #define TYPE_NEXT_VARIANT(NODE) (TYPE_CHECK (NODE)->type.next_variant)
 #define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK (NODE)->type.main_variant)
 #define TYPE_CONTEXT(NODE) (TYPE_CHECK (NODE)->type.context)
+#define TYPE_MAXVAL(NODE) (TYPE_CHECK (NODE)->type.maxval)
+#define TYPE_MINVAL(NODE) (TYPE_CHECK (NODE)->type.minval)

 /* Vector types need to check target flags to determine type.  */
 extern enum machine_mode vector_type_mode (const_tree);
@@ -5255,10 +5257,6 @@ struct tree_int_map GTY(())
 #define tree_int_map_hash tree_map_base_hash
 #define tree_int_map_marked_p tree_map_base_marked_p

-/* Map from a DECL_UID to the decl tree.  */
-
-extern void remove_decl_from_map (tree);
-
 /* Map from a tree to initialization/finalization priorities.  */

 struct tree_priority_map GTY(())
Index: tree-pass.h
===================================================================
--- tree-pass.h	(revision 143674)
+++ tree-pass.h	(revision 143675)
@@ -391,7 +391,7 @@ extern struct gimple_opt_pass pass_build
 extern struct gimple_opt_pass pass_reset_cc_flags;

 /* IPA Passes */
-extern struct simple_ipa_opt_pass pass_ipa_free_lang_specifics;
+extern struct simple_ipa_opt_pass pass_ipa_free_lang_data;
 extern struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility;
 extern struct simple_ipa_opt_pass pass_ipa_early_inline;

Index: lto-function-out.c
===================================================================
--- lto-function-out.c	(revision 143674)
+++ lto-function-out.c	(revision 143675)
@@ -675,32 +675,6 @@ output_record_start (struct output_block
 }


-/* Translate all the types in LIST with the corresponding runtime
-   types.  */
-
-static tree
-get_eh_types_for_runtime (tree list)
-{
-  tree head, prev;
-
-  if (list == NULL_TREE)
-    return NULL_TREE;
-
-  head = build_tree_list (0, lookup_type_for_runtime (TREE_VALUE (list)));
-  prev = head;
-  list = TREE_CHAIN (list);
-  while (list)
-    {
-      tree n = build_tree_list (0, lookup_type_for_runtime
(TREE_VALUE (list)));
-      TREE_CHAIN (prev) = n;
-      prev = TREE_CHAIN (prev);
-      list = TREE_CHAIN (list);
-    }
-
-  return head;
-}
-
-
 /* Output EH region R to OB.  */

 static void
@@ -790,10 +764,7 @@ output_eh_region (struct output_block *o
 	 by calling output_zero.  */
       list = r->u.eh_catch.type_list;
       if (list)
-	{
-	  list = get_eh_types_for_runtime (list);
-	  output_expr_operand (ob, list);
-	}
+	output_expr_operand (ob, list);
       else
 	output_zero (ob);

@@ -805,7 +776,7 @@ output_eh_region (struct output_block *o
     }
   else if (r->type == ERT_ALLOWED_EXCEPTIONS)
     {
-      tree list = get_eh_types_for_runtime (r->u.allowed.type_list);
+      tree list = r->u.allowed.type_list;
       if (list)
 	output_expr_operand (ob, list);
       else
@@ -2750,7 +2721,7 @@ output_type_decl (struct output_block *o
   /* Must output name before type.  */
   output_tree (ob, decl->decl_minimal.name);

-  /* Should be cleared by pass_ipa_free_lang_specifics.  */
+  /* Should be cleared by pass_ipa_free_lang_data.  */
   gcc_assert (decl->decl_minimal.context == NULL_TREE);

   output_tree (ob, decl->decl_with_vis.assembler_name);
@@ -2767,7 +2738,7 @@ output_type_decl (struct output_block *o
   output_tree (ob, decl->decl_common.size);
   output_tree (ob, decl->decl_common.size_unit);

-  /* We expect pass_ipa_free_lang_specifics to clear the INITIAL field.  */
+  /* We expect pass_ipa_free_lang_data to clear the INITIAL field.  */
   gcc_assert (decl->decl_common.initial == NULL_TREE);

   /* lang_specific */
@@ -2912,7 +2883,7 @@ output_type (struct output_block *ob, tr
   LTO_DEBUG_TOKEN ("binfo");
   output_tree (ob, type->type.binfo);

-  /* Should be cleared by pass_ipa_free_lang_specifics.  */
+  /* Should be cleared by pass_ipa_free_lang_data.  */
   gcc_assert (type->type.context == NULL_TREE);

   LTO_DEBUG_TOKEN ("canonical");
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 143674)
+++ cp/decl.c	(revision 143675)
@@ -2156,7 +2156,6 @@ duplicate_decls (tree newdecl, tree oldd
   /* The NEWDECL will no longer be needed.  Because every out-of-class
      declaration of a member results in a call to duplicate_decls,
      freeing these nodes represents in a significant savings.  */
-  remove_decl_from_map (newdecl);
   ggc_free (newdecl);

   return olddecl;
Index: cp/cp-objcp-common.h
===================================================================
--- cp/cp-objcp-common.h	(revision 143674)
+++ cp/cp-objcp-common.h	(revision 143675)
@@ -30,8 +30,8 @@ extern tree objcp_tsubst_copy_and_build
    specific to C++ or ObjC++ go in cp/cp-lang.c and objcp/objcp-lang.c,
    respectively.  */

-#undef LANG_HOOKS_RESET_LANG_SPECIFICS
-#define LANG_HOOKS_RESET_LANG_SPECIFICS cp_reset_lang_specifics
+#undef LANG_HOOKS_FREE_LANG_DATA
+#define LANG_HOOKS_FREE_LANG_DATA cp_free_lang_data
 #undef LANG_HOOKS_TREE_SIZE
 #define LANG_HOOKS_TREE_SIZE cp_tree_size
 #undef LANG_HOOKS_FINISH
Index: cp/tree.c
===================================================================
--- cp/tree.c	(revision 143674)
+++ cp/tree.c	(revision 143675)
@@ -2829,7 +2829,7 @@ cp_fix_function_decl_p (tree decl)
 /* Clean the C++ specific parts of the tree T. */

 void
-cp_reset_lang_specifics (tree t)
+cp_free_lang_data (tree t)
 {
   if (TREE_CODE (t) == METHOD_TYPE
       || TREE_CODE (t) == FUNCTION_TYPE)
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 143674)
+++ cp/cp-tree.h	(revision 143675)
@@ -4819,7 +4819,7 @@ extern tree finish_decltype_type
 extern tree finish_trait_expr			(enum cp_trait_kind, tree, tree);

 /* in tree.c */
-void cp_reset_lang_specifics (tree t);
+void cp_free_lang_data 				(tree t);
 extern void lang_check_failed			(const char *, int,
 						 const char *) ATTRIBUTE_NORETURN;
 extern tree stabilize_expr			(tree, tree *);
Index: timevar.def
===================================================================
--- timevar.def	(revision 143674)
+++ timevar.def	(revision 143675)
@@ -53,6 +53,7 @@ DEFTIMEVAR (TV_IPA_REFERENCE         , "
 DEFTIMEVAR (TV_IPA_PURE_CONST        , "ipa pure const")
 DEFTIMEVAR (TV_IPA_TYPE_ESCAPE       , "ipa type escape")
 DEFTIMEVAR (TV_IPA_PTA               , "ipa points-to")
+DEFTIMEVAR (TV_IPA_FREE_LANG_DATA    , "ipa free lang data")
 /* Time spent by constructing CFG.  */
 DEFTIMEVAR (TV_CFG                   , "cfg construction")
 /* Time spent by cleaning up CFG.  */
Index: langhooks.h
===================================================================
--- langhooks.h	(revision 143674)
+++ langhooks.h	(revision 143675)
@@ -240,7 +240,7 @@ struct lang_hooks
   size_t identifier_size;

   /* Remove any parts of the tree that are used only by the FE. */
-  void (*reset_lang_specifics) (tree);
+  void (*free_lang_data) (tree);

   /* Determines the size of any language-specific tcc_constant or
      tcc_exceptional nodes.  Since it is called from make_node, the
Index: except.c
===================================================================
--- except.c	(revision 143674)
+++ except.c	(revision 143675)
@@ -3481,7 +3481,14 @@ output_ttype (tree type, int tt_format,
     {
       struct varpool_node *node;

-      type = lookup_type_for_runtime (type);
+      /* FIXME lto.  During LTO compiles, pass_ipa_free_lang_data
+	 changes all types to runtime types so TYPE should already be
+	 a runtime type reference.  When pass_ipa_free_lang data is
+	 made a default pass, we can then remove the call to
+	 lookup_type_for_runtime below.  */
+      if (TYPE_P (type))
+	type = lookup_type_for_runtime (type);
+
       value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);

       /* Let cgraph know that the rtti decl is used.  Not all of the
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 143674)
+++ lto/lto.c	(revision 143675)
@@ -1308,7 +1308,6 @@ free_decl (const void *p, void *data ATT
   const_tree ct = (const_tree) p;
   tree t = CONST_CAST_TREE (ct);

-  remove_decl_from_map (t);
   lto_symtab_clear_resolution (t);
   ggc_free (t);
   return true;
Index: lto/lto-lang.c
===================================================================
--- lto/lto-lang.c	(revision 143674)
+++ lto/lto-lang.c	(revision 143675)
@@ -906,30 +906,6 @@ lto_builtin_function (tree decl)
   return decl;
 }

-static int
-lto_types_compatible_p (tree type1, tree type2)
-{
-  if (TREE_CODE (type1) == RECORD_TYPE
-      && TREE_CODE (type2) == RECORD_TYPE)
-    {
-      /* Check structural equality.  */
-      tree f1, f2;
-
-      for (f1 = TYPE_FIELDS (type1), f2 = TYPE_FIELDS (type2);
-	   f1 && f2;
-	   f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
-	{
-	  if (TREE_CODE (f1) != TREE_CODE (f2)
-	      || DECL_NAME (f1) != DECL_NAME (f2))
-	    break;
-	}
-
-      return f1 && f2 ? 0 : 1;
-    }
-
-  return TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2);
-}
-
 static void
 lto_register_builtin_type (tree type, const char *name)
 {
@@ -1074,7 +1050,7 @@ static void lto_init_ts (void)
 #undef LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS
 #define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS true
 #undef LANG_HOOKS_TYPES_COMPATIBLE_P
-#define LANG_HOOKS_TYPES_COMPATIBLE_P lto_types_compatible_p
+#define LANG_HOOKS_TYPES_COMPATIBLE_P gimple_types_compatible_p

 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 143674)
+++ Makefile.in	(revision 143675)
@@ -2135,7 +2135,7 @@ tree.o : tree.c $(CONFIG_H) $(SYSTEM_H)
    $(TOPLEV_H) $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H)
langhooks.h \
    $(REAL_H) gt-tree.h tree-iterator.h $(BASIC_BLOCK_H) $(TREE_FLOW_H) \
    $(OBSTACK_H) pointer-set.h fixed-value.h tree-pass.h langhooks-def.h \
-   $(DIAGNOSTIC_H)
+   $(DIAGNOSTIC_H) $(CGRAPH_H) $(TIMEVAR_H) except.h
 tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) langhooks.h $(TOPLEV_H) $(SPLAY_TREE_H) $(TREE_DUMP_H) \
    tree-iterator.h tree-pass.h $(DIAGNOSTIC_H) $(REAL_H) fixed-value.h
Index: gimple.c
===================================================================
--- gimple.c	(revision 143674)
+++ gimple.c	(revision 143675)
@@ -3192,4 +3192,31 @@ gimple_call_copy_skip_args (gimple stmt,
   return new_stmt;
 }

+
+/* Return 1 if TYPE1 and TYPE2 are structurally compatible and/or they
+   have the same main variant.  */
+
+int
+gimple_types_compatible_p (tree type1, tree type2)
+{
+  if (TREE_CODE (type1) == RECORD_TYPE
+      && TREE_CODE (type2) == RECORD_TYPE)
+    {
+      /* Check structural equality.  */
+      tree f1, f2;
+
+      for (f1 = TYPE_FIELDS (type1), f2 = TYPE_FIELDS (type2);
+	   f1 && f2;
+	   f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
+	{
+	  if (TREE_CODE (f1) != TREE_CODE (f2)
+	      || DECL_NAME (f1) != DECL_NAME (f2))
+	    break;
+	}
+
+      return f1 && f2 ? 0 : 1;
+    }
+
+  return TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2);
+}
 #include "gt-gimple.h"
Index: gimple.h
===================================================================
--- gimple.h	(revision 143674)
+++ gimple.h	(revision 143675)
@@ -913,6 +913,7 @@ extern bool is_gimple_call_addr (tree);
 extern tree get_call_expr_in (tree t);

 extern void recalculate_side_effects (tree);
+extern int gimple_types_compatible_p (tree, tree);

 /* In gimplify.c  */
 extern tree create_tmp_var_raw (tree, const char *);
Index: passes.c
===================================================================
--- passes.c	(revision 143674)
+++ passes.c	(revision 143675)
@@ -536,7 +536,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_inline_parameters);
       NEXT_PASS (pass_rebuild_cgraph_edges);
     }
-  NEXT_PASS (pass_ipa_free_lang_specifics);
+  NEXT_PASS (pass_ipa_free_lang_data);
   NEXT_PASS (pass_early_local_passes);
     {
       struct opt_pass **p = &pass_early_local_passes.pass.sub;
Index: lto-section-out.c
===================================================================
--- lto-section-out.c	(revision 143674)
+++ lto-section-out.c	(revision 143675)
@@ -867,8 +867,7 @@ lto_get_common_nodes (void)
      distinction should only be relevant to the front-end, so we always
      use the C definition here in lto1.

-     These should be assured in pass_ipa_free_lang_specifics.  */
-
+     These should be assured in pass_ipa_free_lang_data.  */
   gcc_assert (fileptr_type_node == ptr_type_node);
   gcc_assert (TYPE_MAIN_VARIANT (fileptr_type_node) == ptr_type_node);

Index: langhooks-def.h
===================================================================
--- langhooks-def.h	(revision 143674)
+++ langhooks-def.h	(revision 143675)
@@ -103,7 +103,7 @@ extern void lhd_omp_firstprivatize_type_
 #define LANG_HOOKS_DECL_PRINTABLE_NAME	lhd_decl_printable_name
 #define LANG_HOOKS_DWARF_NAME		lhd_dwarf_name
 #define LANG_HOOKS_EXPR_SIZE		lhd_expr_size
-#define LANG_HOOKS_RESET_LANG_SPECIFICS	lhd_do_nothing_t
+#define LANG_HOOKS_FREE_LANG_DATA	lhd_do_nothing_t
 #define LANG_HOOKS_TREE_SIZE		lhd_tree_size
 #define LANG_HOOKS_TYPES_COMPATIBLE_P	lhd_types_compatible_p
 #define LANG_HOOKS_BUILTIN_FUNCTION	lhd_builtin_function
@@ -239,7 +239,7 @@ extern void lhd_end_section (void);
 #define LANG_HOOKS_INITIALIZER { \
   LANG_HOOKS_NAME, \
   LANG_HOOKS_IDENTIFIER_SIZE, \
-  LANG_HOOKS_RESET_LANG_SPECIFICS, \
+  LANG_HOOKS_FREE_LANG_DATA, \
   LANG_HOOKS_TREE_SIZE, \
   LANG_HOOKS_INIT_OPTIONS, \
   LANG_HOOKS_INITIALIZE_DIAGNOSTICS, \



More information about the Gcc-patches mailing list