This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[lto][patch] Fix the decls only after reading all the files


This patch changes how we fix (link) decls. Currently we keep the
first one we see and overwrite it when we find the prevailing one.
With this patch we keep track of the prevailing one but don't update
anything until we have read all the decls.

The advantages of doing this is that the code is easier to understand
since each file is read independently. This is also a requirement for
updating the cgraph with the symbol resolution information, since
today when the cgraph is read, the non prevailing defs have already
been removed.

Sorry for the size of the patch, but I couldn't figure out a way to
reduce its size or split it.


Bootstrapped and regression tested on linux x86-64. I have also
manually tested a minimal c++ case to check that the NOTHROW updates
still work.

gcc/
2008-10-02 Rafael Espindola  <espindola@google.com>

	* lto-function-in.c (global_vector_fixup) Remove. Remove all calls.

gcc/lto/
2008-10-02 Rafael Espindola  <espindola@google.com>

	* lto-symtab.c (lto_symtab_overwrite_decl): Remove. Remove all calls.
	(lto_symtab_merge_decl): Update  LTO_IDENTIFIER_DECL the reflect the
	prevailing definition. Don't mark TREE_NOTHROW differences.
	* lto.c (lto_fixup_tree): New.
	(lto_fixup_state): New.
	(lto_fixup_state_aux): New.
	(free_decl): New.
	(lto_fixup_decls): New.
	(lto_main): Call lto_fixup_decls.

Cheers,
-- 
Rafael Avila de Espindola

Google | Gordon House | Barrow Street | Dublin 4 | Ireland
Registered in Dublin, Ireland | Registration Number: 368047
diff --git a/gcc/lto-function-in.c b/gcc/lto-function-in.c
index c519635..9be4098 100644
--- a/gcc/lto-function-in.c
+++ b/gcc/lto-function-in.c
@@ -2642,45 +2642,6 @@ global_vector_enter (struct data_in *data_in, tree node)
   return index;
 }
 
-/* Replace the entry at position INDEX in the globals index vector
-   obtained from DATA_IN with the prevailing decl. */
-
-static tree
-global_vector_fixup (struct data_in *data_in, unsigned index)
-{
-  tree node;
-  tree old_node;
-  gcc_assert (index < VEC_length (tree, data_in->globals_index));
-  old_node = VEC_index (tree, data_in->globals_index, index);
-  gcc_assert (old_node);
-
-  node = lto_symtab_prevailing_decl (old_node);
-  
-#ifdef LTO_GLOBAL_VECTOR_TRACE
-  fprintf (stderr, "FIXUP %u: %p [", index, (void *) old_node);
-  print_generic_expr (stderr, old_node, 0);
-  fprintf (stderr, "] -> %p [", (void *) node);
-  print_generic_expr (stderr, node, 0);
-  fprintf (stderr, "]");
-#endif
-
-  VEC_replace (tree, data_in->globals_index, index, node);
-
-  if (old_node && old_node != node)
-    {
-      /* Note that we cannot do the ggc_free when we merge the declaration,
-	 but must wait until we have finished using it above. */
-      remove_decl_from_map (old_node);
-      ggc_free (old_node);
-    }
-
-#ifdef LTO_GLOBAL_VECTOR_TRACE
-  fprintf (stderr, "\n");
-#endif
-
-  return node;
-}
-
 static tree
 input_field_decl (struct lto_input_block *ib, struct data_in *data_in)
 {
@@ -2886,7 +2847,6 @@ input_function_decl (struct lto_input_block *ib, struct data_in *data_in)
       enum ld_plugin_symbol_resolution resolution =
 	get_resolution (data_in, index);
       lto_symtab_merge_fn (decl, resolution);
-      decl = global_vector_fixup (data_in, index);
     }
 
   LTO_DEBUG_TOKEN ("end_function_decl");
@@ -2990,11 +2950,9 @@ input_var_decl (struct lto_input_block *ib, struct data_in *data_in)
 	  enum ld_plugin_symbol_resolution resolution =
 	    get_resolution (data_in, index);
 	  lto_symtab_merge_var (decl, resolution);
-	  decl = global_vector_fixup (data_in, index);
 	}
     }
-  
-  /* Read initial value expression last, after the global_vector_fixup.  */
+
   decl->decl_common.initial = input_tree (ib, data_in);
 
   LTO_DEBUG_TOKEN ("end_var_decl");
diff --git a/gcc/lto/lto-symtab.c b/gcc/lto/lto-symtab.c
index 65b643e..c62fa45 100644
--- a/gcc/lto/lto-symtab.c
+++ b/gcc/lto/lto-symtab.c
@@ -432,58 +432,6 @@ lto_symtab_compatible (tree old_decl, tree new_decl)
   return true;
 }
 
-/* Overwrite DEST with SRC. */
-
-static void
-lto_symtab_overwrite_decl (tree dest, tree src)
-{
-  LTO_DECL_RESOLUTION (dest) = LTO_DECL_RESOLUTION (src);
-
-  TREE_SIDE_EFFECTS (dest) = TREE_SIDE_EFFECTS (src);
-  TREE_CONSTANT (dest) = TREE_CONSTANT (src);
-  TREE_ADDRESSABLE (dest) = TREE_ADDRESSABLE (src);
-  TREE_THIS_VOLATILE (dest) = TREE_THIS_VOLATILE (src);
-  TREE_READONLY (dest) = TREE_READONLY (src);
-  DECL_EXTERNAL (dest) = DECL_EXTERNAL (src);
-
-  DECL_ALIGN (dest) = DECL_ALIGN (src);
-
-  DECL_USER_ALIGN (dest) = DECL_USER_ALIGN (src);
-
-  DECL_WEAK (dest) = DECL_WEAK (src);
-
-  DECL_PRESERVE_P (dest) = DECL_PRESERVE_P (src);
-
-  TREE_TYPE (dest) = TREE_TYPE (src);
-  DECL_MODE (dest) = DECL_MODE (src);
-
-  if (TREE_CODE (src) == FUNCTION_DECL)
-    {
-      DECL_RESULT (dest) = DECL_RESULT (src);
-      if (DECL_RESULT (dest))
-	DECL_CONTEXT (DECL_RESULT (dest)) = dest;
-      TREE_STATIC (dest) = TREE_STATIC (src);
-      DECL_DECLARED_INLINE_P (dest) = DECL_DECLARED_INLINE_P (src);
-
-      /* Remember this to fix up EH region later.  */
-      if (TREE_NOTHROW (dest) != TREE_NOTHROW (src))
-	{
-	  TREE_NOTHROW (dest) = TREE_NOTHROW (src);
-	  if (TREE_NOTHROW (dest))
-	    lto_mark_nothrow_fndecl (dest);
-	  else
-	    error ("%qD change to exception throwing", dest);
-	};
-    }
-
-  if (TREE_CODE (src) == VAR_DECL)
-    {
-      DECL_INITIAL (dest) = DECL_INITIAL (src);
-      DECL_SIZE (dest) = DECL_SIZE (src);
-      DECL_SIZE_UNIT (dest) = DECL_SIZE_UNIT (src);
-    }
-}
-
 /* 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. */
@@ -555,22 +503,10 @@ lto_symtab_merge_decl (tree new_decl,
 	}
       gcc_assert (old_resolution == LDPR_PREEMPTED_IR
 		  || old_resolution ==  LDPR_RESOLVED_IR);
-      lto_symtab_overwrite_decl (old_decl, new_decl);
+      LTO_IDENTIFIER_DECL (name) = new_decl;
       return;
     }
 
-  if (TREE_CODE (new_decl) == FUNCTION_DECL
-      && TREE_NOTHROW (new_decl) != TREE_NOTHROW (old_decl))
-    {
-      /* Since we return old_decl as the canonical DECL, GIMPLE call
-	 statements originally associated with new_decl will now be
-	 associated with old_decl.  Hence we mark be old_decl for fix-up.  */
-      if (TREE_NOTHROW (old_decl))
-	lto_mark_nothrow_fndecl (old_decl);
-      else
-	error ("%qD change to exception throwing", new_decl);
-    }
-
   if (resolution == LDPR_PREEMPTED_REG
       || resolution == LDPR_RESOLVED_EXEC
       || resolution == LDPR_RESOLVED_DYN)
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 3e4f0e8..44dfd69 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -785,6 +785,170 @@ lto_execute_ltrans (char *const *files)
     }
 }
 
+/* A walk_tree callback used by lto_fixup_state. TP is the pointer to the
+   current tree. WALK_SUBTREES indicates if the subtrees will be walked.
+   DATA is ignored. */
+
+static tree
+lto_fixup_tree (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+{
+  tree t = *tp;
+  tree prevailing;
+
+  *walk_subtrees = 1;
+
+  if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != FUNCTION_DECL)
+    return NULL;
+
+  if (!TREE_PUBLIC (t))
+    return NULL;
+
+    /* LTO FIXME: There should be no DECL_ABSTRACT in the middle end. */
+  if (TREE_CODE (t) == FUNCTION_DECL && DECL_ABSTRACT (t))
+    return NULL;
+
+  prevailing = lto_symtab_prevailing_decl (t);
+  gcc_assert (prevailing);
+
+  *tp = prevailing;
+  *walk_subtrees = 0;
+  return NULL;
+}
+
+/* Helper function of lto_fixup_decls. Walks the var and fn streams in STATE,
+   replaces var and function decls with the corresponding prevailing def and
+   records the old decl in FREE_LIST. */
+
+static void
+lto_fixup_state (struct lto_in_decl_state *state,
+		 struct pointer_set_t *free_list)
+{
+  unsigned i;
+  struct lto_tree_ref_table vars = state->streams[LTO_DECL_STREAM_VAR_DECL];
+  struct lto_tree_ref_table fns = state->streams[LTO_DECL_STREAM_FN_DECL];
+
+  for (i = 0; i < fns.size; i++)
+    {
+      tree decl = fns.trees[i];
+      tree prevailing;
+
+      gcc_assert (decl);
+      gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+
+      /* LTO FIXME: There should be no DECL_ABSTRACT in the middle end. */
+      if (!TREE_PUBLIC (decl) || DECL_ABSTRACT (decl))
+	continue;
+
+      prevailing = lto_symtab_prevailing_decl (decl);
+      gcc_assert (prevailing);
+
+      if (TREE_NOTHROW (prevailing) != TREE_NOTHROW (decl))
+	{
+	  if (TREE_NOTHROW (prevailing))
+	    lto_mark_nothrow_fndecl (prevailing);
+	  else
+	    error ("%qD change to exception throwing", prevailing);
+	}
+
+      if (decl != prevailing)
+	pointer_set_insert (free_list, decl);
+
+      fns.trees[i] = prevailing;
+    }
+
+  for (i = 0; i < vars.size; i++)
+    {
+      tree decl = vars.trees[i];
+      tree prevailing;
+      tree initial;
+
+      gcc_assert (decl);
+
+      if (TREE_CODE (decl) == RESULT_DECL)
+	continue;
+
+      gcc_assert (TREE_CODE (decl) == VAR_DECL);
+
+      if (!TREE_PUBLIC (decl))
+	continue;
+
+      prevailing = lto_symtab_prevailing_decl (decl);
+      gcc_assert (prevailing);
+
+      initial = DECL_INITIAL (decl);
+
+      if (initial && decl == prevailing)
+	{
+	  walk_tree (&initial, lto_fixup_tree, NULL, NULL);
+	  DECL_INITIAL (decl) = initial;
+	}
+
+      if (decl != prevailing)
+	pointer_set_insert (free_list, decl);
+
+      vars.trees[i] = prevailing;
+    }
+}
+
+/* A callback of htab_traverse. Just extract a state from SLOT and the
+   free_list from aux and calls lto_fixup_state. */
+
+static int
+lto_fixup_state_aux (void **slot, void *aux)
+{
+  struct lto_in_decl_state *state = (struct lto_in_decl_state *) *slot;
+  struct pointer_set_t *free_list = (struct pointer_set_t *) aux;
+  lto_fixup_state (state, free_list);
+  return 1;
+}
+
+/* A callback to pointer_set_traverse. Frees the tree pointed by p. Removes
+   from it from the UID -> DECL mapping. */
+
+static bool
+free_decl (const void *p, void *data ATTRIBUTE_UNUSED)
+{
+  const_tree ct = (const_tree) p;
+  tree t = CONST_CAST_TREE (ct);
+
+  remove_decl_from_map (t);
+  ggc_free (t);
+  return true;
+}
+
+/* Fix the decls from all FILES. Replaces each decl with the corresponding
+   prevailing one. */
+
+static void
+lto_fixup_decls (struct lto_file_decl_data** files)
+{
+  unsigned int i;
+  tree decl;
+  struct pointer_set_t *free_list = pointer_set_create ();
+
+  for (i = 0; files[i]; i++)
+    {
+      struct lto_file_decl_data *file = files[i];
+      struct lto_in_decl_state *state = file->global_decl_state;
+      lto_fixup_state (state, free_list);
+
+      htab_traverse (file->function_decl_states, lto_fixup_state_aux,
+		     free_list);
+    }
+
+  for (i = 0; VEC_iterate (tree, lto_global_var_decls, i, decl); i++)
+    {
+      tree prevailing = lto_symtab_prevailing_decl (decl);
+      if (prevailing != decl) {
+	pointer_set_insert (free_list, decl);
+	VEC_replace (tree, lto_global_var_decls, i, prevailing);
+      }
+    }
+
+  pointer_set_traverse (free_list, free_decl, NULL);
+  pointer_set_destroy (free_list);
+}
+
 void
 lto_main (int debug_p ATTRIBUTE_UNUSED)
 {
@@ -838,6 +1002,8 @@ lto_main (int debug_p ATTRIBUTE_UNUSED)
 
   all_file_decl_data [j] = NULL;
 
+  lto_fixup_decls (all_file_decl_data);
+
   /* Set the hooks so that all of the ipa passes can read in their data.  */
   lto_set_in_hooks (all_file_decl_data, get_section_data,
 		    free_section_data);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]