[pph] Add symbol table - Fix remaining asm differences (issue4732043)

Diego Novillo dnovillo@google.com
Thu Jul 14 23:09:00 GMT 2011


This patch fixes the remaining assembly differences between non-pph
and pph compiles.

The idea is to make the pph compiler process functions and variables
in the same order that they had been processed in the original
compile.  To do this, we intercept calls to rest_of_decl_compilation
and allocate_struct_function.  At every call, we add the declaration
to a list.

This list becomes the symbol table for the header file, which is then
written to the end of the file.  When reading the file, we read this
table and present the symbols to the middle end in that order.

The symbol table is written in pph_out_symtab and read in
pph_in_symtab.  The other changes are mostly wrapping calls to
rest_of_decl_compilation so that we can add the declarations to the
symbol table.

This simplifies the logic we use to present symbols to the middle end
as it encodes the sequence in the symbol table itself.  No need to
reverse lists of symbols or the other contortions we used to make.

Tested on x86_64.  Applied to branch.


Diego.

cp/ChangeLog.pph
2011-07-14   Diego Novillo  <dnovillo@google.com>

	* Make-lang.in (cp/decl.o): Add dependency on CXX_PPH_STREAMER_H.
	(cp/pph-streamer-out.o): Add dependency on CGRAPH_H.
        (cp/pph-streamer-in.o): Add dependency on toplev.h

	* cp-tree.h (cp_rest_of_decl_compilation): Declare.
	* call.c (set_up_extended_ref_temp): Call cp_rest_of_decl_compilation
        instead of rest_of_decl_compilation.
	* class.c (build_clone): Likewise.
	* decl2.c (finish_anon_union): Likewise.
	(maybe_emit_vtables): Likewise.
	(write_out_vars): Likewise.
	* method.c (implicitly_declare_fn): Likewise.
	* semantics.c (maybe_add_lambda_conv_op): Likewise.
	* decl.c (make_rtl_for_nonlocal_decl): Likewise.
	(cp_finish_decl): Likewise.
	(start_preparsed_function): Likewise.
	(cp_rest_of_decl_compilation): New.

	* pph-streamer-in.c: Include toplev.h
        (pph_in_language_function): Tidy.
	(pph_in_struct_function): Remove parameter DECL.
        Support reading shared struct functions.
        Read FN->DECL.
	(pph_register_decl_in_symtab): Remove.  Update all users.
	(pph_register_binding_in_symtab): Remove.  Update all users.
	(pph_in_symtab_marker): New.
	(pph_in_symtab): New.
	(pph_read_file_contents): Call it.
	(pph_in_function_decl): Do not call pph_in_struct_function.
	* pph-streamer-out.c: Include cgraph.h.
        (decls_to_register): New.
	(pph_out_chain_filtered): Remove argument REVERSE_P.  Update
        all users.
	(pph_out_struct_function): Write FN->DECL.
	(pph_out_symtab_marker): New.
	(pph_out_symtab): New.
	(pph_write_file_contents): Call it.
	(pph_out_function_decl): Do not call pph_out_struct_function.
	(pph_add_decl_to_register): New.
	* pph-streamer.h (enum pph_symtab_marker): New.
        (struct pph_stream): Remove field FNS_TO_EXPAND.  Update all
        users.
        (pph_add_decl_to_register): Declare.

testsuite/ChangeLog.pph
	* g++.dg/pph/c1pr44948-1a.cc: Adjust expected failure.
	* g++.dg/pph/x0hardlookup.h: Add new symbol in global namespace.
	* g++.dg/pph/c4meteor-contest.cc: Mark fixed.
	* g++.dg/pph/c1attr-warn-unused.cc: Likewise.
	* g++.dg/pph/x1globalref.cc: Likewise.
	* g++.dg/pph/x1hardlookup.cc: Likewise.


diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 5f3249e..9634c47 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -271,7 +271,7 @@ cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \
   cp/operators.def $(TM_P_H) $(TREE_INLINE_H) $(DIAGNOSTIC_H) $(C_PRAGMA_H) \
   debug.h gt-cp-decl.h $(TIMEVAR_H) $(TARGET_H) $(PLUGIN_H) \
   intl.h tree-iterator.h pointer-set.h $(SPLAY_TREE_H) \
-  c-family/c-objc.h
+  c-family/c-objc.h $(CXX_PPH_STREAMER_H)
 cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \
   output.h toplev.h $(C_COMMON_H) gt-cp-decl2.h $(CGRAPH_H) \
   $(C_PRAGMA_H) $(TREE_DUMP_H) intl.h $(TARGET_H) $(GIMPLE_H) pointer-set.h \
@@ -351,8 +351,8 @@ cp/pph-streamer.o: cp/pph-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 cp/pph-streamer-out.o: cp/pph-streamer-out.c $(CONFIG_H) $(SYSTEM_H) \
 	coretypes.h $(TREE_H) tree-pretty-print.h $(LTO_STREAMER_H) \
 	$(CXX_PPH_STREAMER_H) $(CXX_PPH_H) $(TREE_PASS_H) version.h \
-	cppbuiltin.h tree-iterator.h
+	cppbuiltin.h tree-iterator.h $(CGRAPH_H)
 cp/pph-streamer-in.o: cp/pph-streamer-in.c $(CONFIG_H) $(SYSTEM_H) \
 	coretypes.h $(TREE_H) tree-pretty-print.h $(LTO_STREAMER_H) \
 	$(CXX_PPH_STREAMER_H) $(CXX_PPH_H) $(TREE_PASS_H) version.h \
-	cppbuiltin.h tree-iterator.h
+	cppbuiltin.h tree-iterator.h toplev.h
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 56f3408..6988dc7 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -8567,7 +8567,7 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
     }
   else
     {
-      rest_of_decl_compilation (var, /*toplev=*/1, at_eof);
+      cp_rest_of_decl_compilation (var, /*toplev=*/1, at_eof);
       if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
 	static_aggregates = tree_cons (NULL_TREE, var,
 				       static_aggregates);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 466f5ea..d33158a 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4054,7 +4054,7 @@ build_clone (tree fn, tree name)
 
   /* Create the RTL for this function.  */
   SET_DECL_RTL (clone, NULL);
-  rest_of_decl_compilation (clone, /*top_level=*/1, at_eof);
+  cp_rest_of_decl_compilation (clone, /*top_level=*/1, at_eof);
 
   if (pch_file)
     note_decl_for_pch (clone);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f641896..077ed95 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4896,6 +4896,7 @@ extern tree groktypename			(cp_decl_specifier_seq *, const cp_declarator *, bool
 extern tree start_decl				(const cp_declarator *, cp_decl_specifier_seq *, int, tree, tree, tree *);
 extern void start_decl_1			(tree, bool);
 extern bool check_array_initializer		(tree, tree, tree);
+extern void cp_rest_of_decl_compilation 	(tree, int, int);
 extern void cp_finish_decl			(tree, tree, bool, tree, int);
 extern int cp_complete_array_type		(tree *, tree, bool);
 extern int cp_complete_array_type_or_error	(tree *, tree, bool, tsubst_flags_t);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 2742af5..5896688 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "pointer-set.h"
 #include "splay-tree.h"
 #include "plugin.h"
+#include "pph-streamer.h"
 
 /* Possible cases of bad specifiers type used by bad_specifiers. */
 enum bad_spec_place {
@@ -5604,7 +5605,7 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec)
   /* Handle non-variables up front.  */
   if (TREE_CODE (decl) != VAR_DECL)
     {
-      rest_of_decl_compilation (decl, toplev, at_eof);
+      cp_rest_of_decl_compilation (decl, toplev, at_eof);
       return;
     }
 
@@ -5657,7 +5658,7 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec)
 
   /* If we're not deferring, go ahead and assemble the variable.  */
   if (!defer_p)
-    rest_of_decl_compilation (decl, toplev, at_eof);
+    cp_rest_of_decl_compilation (decl, toplev, at_eof);
 }
 
 /* walk_tree helper for wrap_temporary_cleanups, below.  */
@@ -5870,6 +5871,21 @@ value_dependent_init_p (tree init)
   return false;
 }
 
+/* Register DECL with the middle end.  TOP_LEVEL and AT_END are as in
+   rest_of_decl_compilation.  */
+
+void
+cp_rest_of_decl_compilation (tree decl, int top_level, int at_end)
+{
+  rest_of_decl_compilation (decl, top_level, at_end);
+
+  /* If we are generating a PPH image, add DECL to the list of
+     declarations that need to be registered when this image is read.  */
+  if (pph_out_file)
+    pph_add_decl_to_register (decl);
+}
+
+
 /* Finish processing of a declaration;
    install its line number and initial value.
    If the length of an array type is not known before,
@@ -6062,8 +6078,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	  && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
 	TYPE_DECL_SUPPRESS_DEBUG (decl) = 1;
 
-      rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl),
-				at_eof);
+      cp_rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), at_eof);
       return;
     }
 
@@ -12799,6 +12814,11 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
   start_fname_decls ();
 
   store_parm_decls (current_function_parms);
+
+  /* If we are generating a PPH image, add DECL1 to the list of
+     declarations that need to be registered when restoring the image.  */
+  if (pph_out_file)
+    pph_add_decl_to_register (decl1);
 }
 
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index e1f9562..a9e06be 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1444,8 +1444,8 @@ finish_anon_union (tree anon_union_decl)
       && at_function_scope_p ())
     add_decl_expr (anon_union_decl);
   else if (!processing_template_decl)
-    rest_of_decl_compilation (anon_union_decl,
-			      toplevel_bindings_p (), at_eof);
+    cp_rest_of_decl_compilation (anon_union_decl,
+			         toplevel_bindings_p (), at_eof);
 }
 
 /* Auxiliary functions to make type signatures for
@@ -1875,7 +1875,7 @@ maybe_emit_vtables (tree ctype)
 
       /* Write it out.  */
       DECL_EXTERNAL (vtbl) = 0;
-      rest_of_decl_compilation (vtbl, 1, 1);
+      cp_rest_of_decl_compilation (vtbl, 1, 1);
 
       /* Because we're only doing syntax-checking, we'll never end up
 	 actually marking the variable as written.  */
@@ -3276,7 +3276,7 @@ write_out_vars (tree vars)
       if (!var_finalized_p (var))
 	{
 	  import_export_decl (var);
-	  rest_of_decl_compilation (var, 1, 1);
+	  cp_rest_of_decl_compilation (var, 1, 1);
 	}
     }
 }
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 3d272a3..e635461 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1544,7 +1544,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
 
   grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL);
   set_linkage_according_to_type (type, fn);
-  rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
+  cp_rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
   DECL_IN_AGGR_P (fn) = 1;
   DECL_ARTIFICIAL (fn) = 1;
   DECL_DEFAULTED_FN (fn) = 1;
diff --git a/gcc/cp/pph-streamer-in.c b/gcc/cp/pph-streamer-in.c
index 2026453..0808cab 100644
--- a/gcc/cp/pph-streamer-in.c
+++ b/gcc/cp/pph-streamer-in.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "version.h"
 #include "cppbuiltin.h"
+#include "toplev.h"
 
 /* Wrapper for memory allocation calls that should have their results
    registered in the PPH streamer cache.  DATA is the pointer returned
@@ -726,8 +727,7 @@ pph_in_language_function (pph_stream *stream)
   if (marker == PPH_RECORD_END)
     return NULL;
   else if (marker == PPH_RECORD_SHARED)
-    return (struct language_function *) pph_in_shared_data (stream,
-								     ix);
+    return (struct language_function *) pph_in_shared_data (stream, ix);
 
   ALLOC_AND_REGISTER (stream, ix, lf, ggc_alloc_cleared_language_function ());
   memcpy (&lf->base, pph_in_c_language_function (stream),
@@ -804,26 +804,33 @@ pph_in_ld_fn (pph_stream *stream, struct lang_decl_fn *ldf)
 
 
 /* Read applicable fields of struct function from STREAM.  Associate
-   the read structure to DECL.  */
+   the read structure to its corresponding FUNCTION_DECL and return
+   it.  */
 
 static struct function *
-pph_in_struct_function (pph_stream *stream, tree decl)
+pph_in_struct_function (pph_stream *stream)
 {
   size_t count, i;
   unsigned ix;
   enum pph_record_marker marker;
   struct function *fn;
+  tree decl;
 
   marker = pph_in_start_record (stream, &ix);
   if (marker == PPH_RECORD_END)
     return NULL;
+  else if (marker == PPH_RECORD_SHARED)
+    return (struct function *) pph_in_shared_data (stream, ix);
 
-  /* Since struct function is embedded in every decl, fn cannot be shared.  */
-  gcc_assert (marker != PPH_RECORD_SHARED);
+  decl = pph_in_tree (stream);
 
   allocate_struct_function (decl, false);
   fn = DECL_STRUCT_FUNCTION (decl);
 
+  /* Now register it.  We would normally use ALLOC_AND_REGISTER,
+     but retrofit_lang_decl does not return a pointer.  */
+  pph_register_shared_data (stream, fn, ix);
+
   input_struct_function_base (fn, stream->data_in, stream->ib);
 
   /* struct eh_status *eh;					-- zero init */
@@ -1175,37 +1182,10 @@ pph_in_lang_type (pph_stream *stream)
 }
 
 
-/* Register DECL with the middle end.  */
-
-static void
-pph_register_decl_in_symtab (tree decl)
-{
-  if (TREE_CODE (decl) == VAR_DECL
-      && TREE_STATIC (decl)
-      && !DECL_EXTERNAL (decl))
-    varpool_finalize_decl (decl);
-}
-
-
-/* Register all the symbols in binding level BL in the callgraph symbol
-   table.  */
-
-static void
-pph_register_binding_in_symtab (cp_binding_level *bl)
-{
-  tree t;
-
-  /* Add file-local symbols to the varpool.  */
-  for (t = bl->names; t; t = DECL_CHAIN (t))
-    pph_register_decl_in_symtab (t);
-
-  /* Recurse into the namespaces contained in BL.  */
-  for (t = bl->namespaces; t; t = DECL_CHAIN (t))
-    pph_register_binding_in_symtab (NAMESPACE_LEVEL (t));
-}
-
-
-/* Merge scope_chain bindings from STREAM into global_namespace. */
+/* Merge scope_chain bindings from STREAM into the scope_chain
+   bindings of the current translation unit.  This incorporates all
+   the symbols and types from the PPH image into the current TU so
+   name lookup can find identifiers brought from the image.  */
 
 static void
 pph_in_scope_chain (pph_stream *stream)
@@ -1223,9 +1203,6 @@ pph_in_scope_chain (pph_stream *stream)
   cur_bindings = scope_chain->bindings;
   new_bindings = pph_in_binding_level (stream, scope_chain->bindings);
 
-  /* Register all the symbols in STREAM with the call graph.  */
-  pph_register_binding_in_symtab (new_bindings);
-
   /* Merge the bindings from STREAM into saved_scope->bindings.  */
   chainon (cur_bindings->names, new_bindings->names);
   chainon (cur_bindings->namespaces, new_bindings->namespaces);
@@ -1377,6 +1354,69 @@ pph_in_identifiers (pph_stream *stream, cpp_idents_used *identifiers)
 }
 
 
+/* Read a symbol table marker from STREAM.  */
+
+static inline enum pph_symtab_marker
+pph_in_symtab_marker (pph_stream *stream)
+{
+  enum pph_symtab_marker m = (enum pph_symtab_marker) pph_in_uchar (stream);
+  gcc_assert (m == PPH_SYMTAB_FUNCTION
+	      || m == PPH_SYMTAB_FUNCTION_BODY
+	      || m == PPH_SYMTAB_DECL);
+  return m;
+}
+
+
+/* Read the symbol table from STREAM.  When this image is read into
+   another translation unit, we want to guarantee that the IL
+   instances taken from this image are instantiated in the same order
+   that they were instantiated when we generated this image.
+
+   With this, we can generate code in the same order out of the
+   original header files and out of PPH images.  */
+
+static void
+pph_in_symtab (pph_stream *stream)
+{
+  unsigned i, num;
+
+  /* Register all the symbols in STREAM in the same order of the
+     original compilation for this header file.  */
+  num = pph_in_uint (stream);
+  for (i = 0; i < num; i++)
+    {
+      enum pph_symtab_marker kind = pph_in_symtab_marker (stream);
+      if (kind == PPH_SYMTAB_FUNCTION || kind == PPH_SYMTAB_FUNCTION_BODY)
+	{
+	  struct function *fn = pph_in_struct_function (stream);
+
+	  if (kind == PPH_SYMTAB_FUNCTION_BODY)
+	    {
+	      /* FIXME pph - This is somewhat gross.  When we
+		 generated the PPH image, the parser called
+		 expand_or_defer_fn on FN->DECL, which marked it
+		 DECL_EXTERNAL (see expand_or_defer_fn_1 for details).
+
+		 However, this is not really an extern definition, so
+		 it was also marked not-really-extern (yes, I
+		 know...). If this happens, we need to unmark it,
+		 otherwise the code generator will toss it out.  */
+	      if (DECL_NOT_REALLY_EXTERN (fn->decl))
+		DECL_EXTERNAL (fn->decl) = 0;
+	      expand_or_defer_fn (fn->decl);
+	    }
+	}
+      else if (kind == PPH_SYMTAB_DECL)
+	{
+	  tree t = pph_in_tree (stream);
+	  cp_rest_of_decl_compilation (t, decl_function_context (t) == NULL, 1);
+	}
+      else
+	gcc_unreachable ();
+    }
+}
+
+
 /* Read contents of PPH file in STREAM.  */
 
 static void
@@ -1386,7 +1426,7 @@ pph_read_file_contents (pph_stream *stream)
   cpp_ident_use *bad_use;
   const char *cur_def;
   cpp_idents_used idents_used;
-  tree fndecl, t, file_keyed_classes, file_static_aggregates;
+  tree t, file_keyed_classes, file_static_aggregates;
   unsigned i;
   VEC(tree,gc) *file_unemitted_tinfo_decls;
 
@@ -1407,6 +1447,8 @@ pph_read_file_contents (pph_stream *stream)
   if (flag_pph_dump_tree)
     pph_dump_namespace (pph_logfile, global_namespace);
 
+  /* Read and merge the other global state collected during parsing of
+     the original header.  */
   file_keyed_classes = pph_in_tree (stream);
   keyed_classes = chainon (file_keyed_classes, keyed_classes);
 
@@ -1417,32 +1459,8 @@ pph_read_file_contents (pph_stream *stream)
   file_static_aggregates = pph_in_tree (stream);
   static_aggregates = chainon (file_static_aggregates, static_aggregates);
 
-  /* Register all symbols in FILE_STATIC_AGGREGATES with the middle end.
-     Each element of this list is an INIT_EXPR expression.  */
-  for (t = file_static_aggregates; t; t = TREE_CHAIN (t))
-    {
-      tree lhs = TREE_OPERAND (TREE_PURPOSE (t), 0);
-      tree rhs = TREE_OPERAND (TREE_PURPOSE (t), 1);
-      pph_register_decl_in_symtab (lhs);
-      pph_register_decl_in_symtab (rhs);
-    }
-
-  /* Expand all the functions with bodies that we read from STREAM.  */
-  FOR_EACH_VEC_ELT (tree, stream->fns_to_expand, i, fndecl)
-    {
-      /* FIXME pph - This is somewhat gross.  When we generated the
-	 PPH image, the parser called expand_or_defer_fn on FNDECL,
-	 which marked it DECL_EXTERNAL (see expand_or_defer_fn_1 for
-	 details).
-
-	 However, this is not really an extern definition, so it was
-	 also marked not-really-extern (yes, I know...). If this
-	 happens, we need to unmark it, otherwise the code generator
-	 will toss it out.  */
-      if (DECL_NOT_REALLY_EXTERN (fndecl))
-	DECL_EXTERNAL (fndecl) = 0;
-      expand_or_defer_fn (fndecl);
-    }
+  /* Read and process the symbol table.  */
+  pph_in_symtab (stream);
 }
 
 
@@ -1479,10 +1497,7 @@ pph_in_function_decl (pph_stream *stream, tree fndecl)
   DECL_INITIAL (fndecl) = pph_in_tree (stream);
   pph_in_lang_specific (stream, fndecl);
   DECL_SAVED_TREE (fndecl) = pph_in_tree (stream);
-  DECL_STRUCT_FUNCTION (fndecl) = pph_in_struct_function (stream, fndecl);
   DECL_CHAIN (fndecl) = pph_in_tree (stream);
-  if (DECL_SAVED_TREE (fndecl))
-    VEC_safe_push (tree, gc, stream->fns_to_expand, fndecl);
 }
 
 
diff --git a/gcc/cp/pph-streamer-out.c b/gcc/cp/pph-streamer-out.c
index c3d6dc2..ee294df 100644
--- a/gcc/cp/pph-streamer-out.c
+++ b/gcc/cp/pph-streamer-out.c
@@ -31,12 +31,19 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "version.h"
 #include "cppbuiltin.h"
+#include "cgraph.h"
 
 /* FIXME pph.  This holds the FILE handle for the current PPH file
    that we are writing.  It is necessary because the LTO callbacks do
    not allow passing a FILE handle to them.  */
 static FILE *current_pph_file = NULL;
 
+/* List of declarations to register with the middle end.  This is
+   collected as the compiler instantiates symbols and functions.  Once
+   we finish parsing the header file, this array is written out to the
+   PPH image.  This way, the reader will be able to instantiate these
+   symbols in the same order that they were instantiated originally.  */
+static VEC(tree,heap) *decls_to_register = NULL;
 
 /* Callback for packing value fields in ASTs.  BP is the bitpack 
    we are packing into.  EXPR is the tree to pack.  */
@@ -603,24 +610,19 @@ pph_out_chained_tree (pph_stream *stream, tree t, bool ref_p)
 
 /* Output a chain of nodes to STREAM starting with FIRST.  Skip any
    nodes that do not match FILTER.  REF_P is true if nodes in the chain
-   should be emitted as references.  Stream the chain in the reverse order
-   if REVERSE is true.*/
+   should be emitted as references.  */
 
 static void
 pph_out_chain_filtered (pph_stream *stream, tree first, bool ref_p,
-			   enum chain_filter filter, bool reverse_p)
+			   enum chain_filter filter)
 {
   unsigned count;
-  int i;
   tree t;
-  VEC(tree,gc) *reverse_list = NULL;
 
   /* Special case.  If the caller wants no filtering, it is much
      faster to just call pph_out_chain directly.  */
   if (filter == NONE)
     {
-      if (reverse_p)
-	nreverse (first);
       pph_out_chain (stream, first, ref_p);
       return;
     }
@@ -634,15 +636,6 @@ pph_out_chain_filtered (pph_stream *stream, tree first, bool ref_p,
     }
   pph_out_uint (stream, count);
 
-  /* We cannot use the actual chain and simply reverse that before
-     streaming out below as there are other chains being streamed out
-     as part of streaming the trees in the current chain and this
-     creates conflicts. Thus, we will create an array containing all
-     the trees we want to stream out and stream that backwards without
-     altering the chain itself.  */
-  if (reverse_p && count > 0)
-    reverse_list = VEC_alloc (tree, gc, count);
-
   /* Output all the nodes that match the filter.  */
   for (t = first; t; t = TREE_CHAIN (t))
     {
@@ -650,15 +643,8 @@ pph_out_chain_filtered (pph_stream *stream, tree first, bool ref_p,
       if (filter == NO_BUILTINS && DECL_P (t) && DECL_IS_BUILTIN (t))
 	continue;
 
-      if (reverse_p)
-	VEC_quick_push (tree, reverse_list, t);
-      else
-	pph_out_chained_tree (stream, t, ref_p);
-    }
-
-  if (reverse_p && count > 0)
-    FOR_EACH_VEC_ELT_REVERSE (tree, reverse_list, i, t)
       pph_out_chained_tree (stream, t, ref_p);
+    }
 }
 
 
@@ -676,14 +662,13 @@ pph_out_binding_level (pph_stream *stream, cp_binding_level *bl, bool ref_p)
   if (!pph_out_start_record (stream, bl))
     return;
 
-  pph_out_chain_filtered (stream, bl->names, ref_p, NO_BUILTINS, true);
-  pph_out_chain_filtered (stream, bl->namespaces, ref_p, NO_BUILTINS, true);
+  pph_out_chain_filtered (stream, bl->names, ref_p, NO_BUILTINS);
+  pph_out_chain_filtered (stream, bl->namespaces, ref_p, NO_BUILTINS);
 
   pph_out_tree_vec (stream, bl->static_decls, ref_p);
 
-  pph_out_chain_filtered (stream, bl->usings, ref_p, NO_BUILTINS, true);
-  pph_out_chain_filtered (stream, bl->using_directives, ref_p, NO_BUILTINS,
-			  true);
+  pph_out_chain_filtered (stream, bl->usings, ref_p, NO_BUILTINS);
+  pph_out_chain_filtered (stream, bl->using_directives, ref_p, NO_BUILTINS);
 
   pph_out_uint (stream, VEC_length (cp_class_binding, bl->class_shadowed));
   FOR_EACH_VEC_ELT (cp_class_binding, bl->class_shadowed, i, cs)
@@ -853,6 +838,7 @@ pph_out_struct_function (pph_stream *stream, struct function *fn, bool ref_p)
   if (!pph_out_start_record (stream, fn))
     return;
 
+  pph_out_tree (stream, fn->decl, ref_p);
   output_struct_function_base (stream->ob, fn);
 
   /* struct eh_status *eh;					-- ignored */
@@ -1225,18 +1211,70 @@ pph_out_identifiers (pph_stream *stream, cpp_idents_used *identifiers)
 }
 
 
+/* Emit symbol table MARKER to STREAM.  */
+
+static inline void
+pph_out_symtab_marker (pph_stream *stream, enum pph_symtab_marker marker)
+{
+  pph_out_uchar (stream, marker);
+}
+
+
+/* Emit the symbol table for STREAM.  When this image is read into
+   another translation unit, we want to guarantee that the IL
+   instances taken from this image are instantiated in the same order
+   that they were instantiated when we generated this image.
+
+   With this, we can generate code in the same order out of the
+   original header files and out of PPH images.
+
+   REF_P is as in pph_out_tree.  */
+
+static void
+pph_out_symtab (pph_stream *stream, bool ref_p)
+{
+  tree decl;
+  unsigned i;
+
+  pph_out_uint (stream, VEC_length (tree, decls_to_register));
+  FOR_EACH_VEC_ELT (tree, decls_to_register, i, decl)
+    if (TREE_CODE (decl) == FUNCTION_DECL && DECL_STRUCT_FUNCTION (decl))
+      {
+	if (DECL_SAVED_TREE (decl))
+	  pph_out_symtab_marker (stream, PPH_SYMTAB_FUNCTION_BODY);
+	else
+	  pph_out_symtab_marker (stream, PPH_SYMTAB_FUNCTION);
+	pph_out_struct_function (stream, DECL_STRUCT_FUNCTION (decl), ref_p);
+      }
+    else
+      {
+	pph_out_symtab_marker (stream, PPH_SYMTAB_DECL);
+	pph_out_tree (stream, decl, ref_p);
+      }
+
+  VEC_free (tree, heap, decls_to_register);
+}
+
+
 /* Write PPH output symbols and IDENTS_USED to STREAM as an object.  */
 
 static void
 pph_write_file_contents (pph_stream *stream, cpp_idents_used *idents_used)
 { 
+  /* Emit all the identifiers and symbols in the global namespace.  */
   pph_out_identifiers (stream, idents_used);
   pph_out_scope_chain (stream, scope_chain, false);
   if (flag_pph_dump_tree)
     pph_dump_namespace (pph_logfile, global_namespace);
+
+  /* Emit other global state kept by the parser.  FIXME pph, these
+     globals should be fields in struct cp_parser.  */
   pph_out_tree (stream, keyed_classes, false);
   pph_out_tree_vec (stream, unemitted_tinfo_decls, false);
   pph_out_tree (stream, static_aggregates, false);
+
+  /* Emit the symbol table.  */
+  pph_out_symtab (stream, false);
 }
 
 
@@ -1282,13 +1320,19 @@ pph_out_tree_header (struct output_block *ob, tree expr)
 static void
 pph_out_function_decl (pph_stream *stream, tree fndecl, bool ref_p)
 {
+  /* Note that we do not output DECL_STRUCT_FUNCTION here.  This is
+     emitted at the end of the PPH file in pph_out_symtab.
+     This way, we will be able to re-instantiate them in the same
+     order when reading the image (the allocation of
+     DECL_STRUCT_FUNCTION has the side effect of generating function
+     sequence numbers (function.funcdef_no).  */
   pph_out_tree_or_ref_1 (stream, DECL_INITIAL (fndecl), ref_p, 3);
   pph_out_lang_specific (stream, fndecl, ref_p);
   pph_out_tree_or_ref_1 (stream, DECL_SAVED_TREE (fndecl), ref_p, 3);
-  pph_out_struct_function (stream, DECL_STRUCT_FUNCTION (fndecl), ref_p);
   pph_out_tree_or_ref_1 (stream, DECL_CHAIN (fndecl), ref_p, 3);
 }
 
+
 /* Callback for writing ASTs to a stream.  This writes all the fields
    that are not processed by default by the common tree pickler.
    OB and REF_P are as in lto_write_tree.  EXPR is the tree to write.  */
@@ -1612,3 +1656,14 @@ pph_write_tree (struct output_block *ob, tree expr, bool ref_p)
                  tree_code_name[TREE_CODE (expr)]);
     }
 }
+
+
+/* Add DECL to the list of symbols that need to be registered with the
+   middle end when reading current_pph_stream.  */
+
+void
+pph_add_decl_to_register (tree decl)
+{
+  if (decl)
+    VEC_safe_push (tree, heap, decls_to_register, decl);
+}
diff --git a/gcc/cp/pph-streamer.h b/gcc/cp/pph-streamer.h
index 2fe4266..36711fd 100644
--- a/gcc/cp/pph-streamer.h
+++ b/gcc/cp/pph-streamer.h
@@ -31,6 +31,19 @@ enum pph_record_marker {
   PPH_RECORD_SHARED
 };
 
+/* Symbol table markers.  These are all the symbols that need to be 
+   registered with the middle end.  */
+enum pph_symtab_marker {
+  /* A FUNCTION_DECL with DECL_STRUCT_FUNCTION but no body.  */
+  PPH_SYMTAB_FUNCTION = 0x01,
+
+  /* A FUNCTION_DECL with DECL_STRUCT_FUNCTION and a body.  */
+  PPH_SYMTAB_FUNCTION_BODY,
+
+  /* All other symbols.  */
+  PPH_SYMTAB_DECL
+};
+
 /* Number of sections in a PPH file.  FIXME, currently only one section
    is supported.  To add more, it will also be necessary to handle
    section names in pph_get_section_data and pph_free_section_data.  */
@@ -116,10 +129,6 @@ typedef struct pph_stream {
 
   /* Nonzero if the stream was opened for writing.  */
   unsigned int write_p : 1;
-
-  /* List of functions with bodies that need to be expanded after
-     reading the PPH file.  */
-  VEC(tree,gc) *fns_to_expand;
 } pph_stream;
 
 /* Filter values for pph_out_chain_filtered.  */
@@ -146,6 +155,7 @@ void pph_write_tree (struct output_block *, tree, bool ref_p);
 void pph_pack_value_fields (struct bitpack_d *, tree);
 void pph_out_tree_header (struct output_block *, tree);
 void pph_write_file (void);
+void pph_add_decl_to_register (tree);
 
 /* In name-lookup.c.  */
 struct binding_table_s;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index fadef4d..86dc67a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -8830,7 +8830,7 @@ maybe_add_lambda_conv_op (tree type)
   SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR);
   grokclassfn (type, fn, NO_SPECIAL);
   set_linkage_according_to_type (type, fn);
-  rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
+  cp_rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
   DECL_IN_AGGR_P (fn) = 1;
   DECL_ARTIFICIAL (fn) = 1;
   DECL_NOT_REALLY_EXTERN (fn) = 1;
@@ -8859,7 +8859,7 @@ maybe_add_lambda_conv_op (tree type)
     DECL_ALIGN (fn) = 2 * BITS_PER_UNIT;
   grokclassfn (type, fn, NO_SPECIAL);
   set_linkage_according_to_type (type, fn);
-  rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
+  cp_rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
   DECL_IN_AGGR_P (fn) = 1;
   DECL_ARTIFICIAL (fn) = 1;
   DECL_NOT_REALLY_EXTERN (fn) = 1;
diff --git a/gcc/testsuite/g++.dg/pph/c1attr-warn-unused.cc b/gcc/testsuite/g++.dg/pph/c1attr-warn-unused.cc
index 1c83f57..d83ee63 100644
--- a/gcc/testsuite/g++.dg/pph/c1attr-warn-unused.cc
+++ b/gcc/testsuite/g++.dg/pph/c1attr-warn-unused.cc
@@ -1,3 +1,2 @@
 /* { dg-options "-w" } */
-// pph asm xdiff
 #include "c0attr-warn-unused.h"
diff --git a/gcc/testsuite/g++.dg/pph/c1pr44948-1a.cc b/gcc/testsuite/g++.dg/pph/c1pr44948-1a.cc
index 0340dc5..c13ee87 100644
--- a/gcc/testsuite/g++.dg/pph/c1pr44948-1a.cc
+++ b/gcc/testsuite/g++.dg/pph/c1pr44948-1a.cc
@@ -1,3 +1,3 @@
 // { dg-xfail-if "INFINITE" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "internal compiler error: in lto_get_pickled_tree, at lto-streamer-in.c" "" { xfail *-*-* } 0 }
+// { dg-bogus "internal compiler error: in lto_streamer_cache_get, at lto-streamer.c" "" { xfail *-*-* } 0 }
 #include "c0pr44948-1a.h"
diff --git a/gcc/testsuite/g++.dg/pph/c4meteor-contest.cc b/gcc/testsuite/g++.dg/pph/c4meteor-contest.cc
index 2b6cb4f..d82b203 100644
--- a/gcc/testsuite/g++.dg/pph/c4meteor-contest.cc
+++ b/gcc/testsuite/g++.dg/pph/c4meteor-contest.cc
@@ -1,5 +1,4 @@
 /* { dg-options "-w" }  */
-// pph asm xdiff
 
 #include "p4meteor-contest.h"
 
diff --git a/gcc/testsuite/g++.dg/pph/x0hardlookup.h b/gcc/testsuite/g++.dg/pph/x0hardlookup.h
index d0822a3..a40677e 100644
--- a/gcc/testsuite/g++.dg/pph/x0hardlookup.h
+++ b/gcc/testsuite/g++.dg/pph/x0hardlookup.h
@@ -1,6 +1,7 @@
 #ifndef X0HARDLOOKUP_H
 #define X0HARDLOOKUP_H
 struct V { int a; static int b;};
+float X;
 namespace N {
    int V;
    struct C { };
diff --git a/gcc/testsuite/g++.dg/pph/x1globalref.cc b/gcc/testsuite/g++.dg/pph/x1globalref.cc
index a986fd4..3a39a07 100644
--- a/gcc/testsuite/g++.dg/pph/x1globalref.cc
+++ b/gcc/testsuite/g++.dg/pph/x1globalref.cc
@@ -1,5 +1,3 @@
-// pph asm xdiff
-
 #include "x0globalref.h"
 
 type x = 2;
diff --git a/gcc/testsuite/g++.dg/pph/x1hardlookup.cc b/gcc/testsuite/g++.dg/pph/x1hardlookup.cc
index 7147420..fd81207 100644
--- a/gcc/testsuite/g++.dg/pph/x1hardlookup.cc
+++ b/gcc/testsuite/g++.dg/pph/x1hardlookup.cc
@@ -1,11 +1,9 @@
-// pph asm xdiff
-
 #include "x0hardlookup.h"
 
 D P;
 
 int I(int arg)
-{ return arg + V; }
+{ return arg + V - int(X); }
 
 int F() {
    return I(N::V + N::O);

--
This patch is available for review at http://codereview.appspot.com/4732043



More information about the Gcc-patches mailing list