Index: gcc/testsuite/ChangeLog.pph

2011-06-14  Lawrence Crowl <crowl@google.com>

	* g++.dg/pph/x1tmplfunc.cc: Replace ICE xfail with an assembly diff
        xfail.

Index: gcc/cp/ChangeLog.pph

2011-06-14  Lawrence Crowl <crowl@google.com>

	* pph-streamer-out.c (pph_out_struct_function): New.
	(pph_out_used_types_slot): New for pph_out_struct_function.
	(struct pph_tree_info): New for pph_out_struct_function.
	(pph_write_tree): Save DECL_STRUCT_FUNCTION of FUNCTION_DECL with
	pph_out_struct_function.
	* pph-streamer-in.c (pph_in_struct_function): New.
	(pph_read_tree): Load DECL_STRUCT_FUNCTION of FUNCTION_DECL with
	pph_in_struct_function.

Index: gcc/ChangeLog.pph

2011-06-14  Lawrence Crowl  <crowl@google.com>

	* lto-streamer.h (extern output_struct_function_base): New.
	(extern input_struct_function_base): New.
	* lto-streamer-out.c (lto_output_ts_function_decl_tree_pointers):
	Update comment.
	(output_struct_function_base): New.
	(output_function): Factor out code common with PPH into
	output_struct_function_base.
	* lto-streamer-in.c (input_struct_function_base): New.
	(input_function): Factor out common code with PPH into
	input_struct_function_base.


Index: gcc/testsuite/g++.dg/pph/x1tmplfunc.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x1tmplfunc.cc	(revision 175056)
+++ gcc/testsuite/g++.dg/pph/x1tmplfunc.cc	(working copy)
@@ -1,6 +1,4 @@
-// { dg-xfail-if "ICE" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "x1tmplfunc.h:8:16: internal compiler error: Segmentation fault" "" { xfail *-*-* } 0 }
-// { dg-prune-output "In file included from " }
+// pph asm xdiff
 
 #include "x1tmplfunc.h"
 
Index: gcc/cp/pph-streamer-in.c
===================================================================
--- gcc/cp/pph-streamer-in.c	(revision 175056)
+++ gcc/cp/pph-streamer-in.c	(working copy)
@@ -608,6 +608,88 @@ pph_in_ld_fn (pph_stream *stream, struct
 }
 
 
+/* Read applicable fields of struct function instance FN from STREAM.  */
+
+static struct function *
+pph_in_struct_function (pph_stream *stream)
+{
+  size_t count, i;
+  unsigned ix;
+  enum pph_record_marker marker;
+  struct function *fn;
+
+  gcc_assert (stream->data_in != NULL);
+
+  marker = pph_start_record (stream, &ix);
+  if (marker == PPH_RECORD_END)
+    return NULL;
+
+  /* Since struct function is embedded in every decl, fn cannot be shared.  */
+  gcc_assert (marker != PPH_RECORD_SHARED);
+
+  fn = ggc_alloc_cleared_function ();
+
+  input_struct_function_base (fn, stream->data_in, stream->ib);
+
+  /* struct eh_status *eh;					-- zero init */
+  /* struct control_flow_graph *cfg;				-- zero init */
+  /* struct gimple_seq_d *gimple_body;				-- zero init */
+  /* struct gimple_df *gimple_df;				-- zero init */
+  /* struct loops *x_current_loops;				-- zero init */
+  /* struct stack_usage *su;					-- zero init */
+  /* htab_t value_histograms;					-- zero init */
+  /* tree decl;							-- zero init */
+  /* tree static_chain_decl;					-- in base */
+  /* tree nonlocal_goto_save_area;				-- in base */
+  /* tree local_decls;						-- in base */
+  /* struct machine_function * machine;				-- zero init */
+
+  fn->language = pph_in_language_function (stream);
+
+  count = pph_in_uint (stream);
+  if ( count > 0 )
+    {
+      fn->used_types_hash = htab_create_ggc (37, htab_hash_pointer,
+					     htab_eq_pointer, NULL);
+      for (i = 0; i < count;  i++)
+	{
+	  void **slot;
+	  tree type = pph_in_tree (stream);
+	  slot = htab_find_slot (fn->used_types_hash, type, INSERT);
+	  if (*slot == NULL)
+	    *slot = type;
+	}
+    }
+  /* else zero initialized */
+
+  /* int last_stmt_uid;						-- zero init */
+  /* int funcdef_no;						-- zero init */
+  /* location_t function_start_locus;				-- in base */
+  /* location_t function_end_locus;				-- in base */
+  /* unsigned int curr_properties;				-- in base */
+  /* unsigned int last_verified;				-- zero init */
+  /* const char *cannot_be_copied_reason;			-- zero init */
+
+  /* unsigned int va_list_gpr_size : 8;				-- in base */
+  /* unsigned int va_list_fpr_size : 8;				-- in base */
+  /* unsigned int calls_setjmp : 1;				-- in base */
+  /* unsigned int calls_alloca : 1;				-- in base */
+  /* unsigned int has_nonlocal_label : 1;			-- in base */
+  /* unsigned int cannot_be_copied_set : 1;			-- zero init */
+  /* unsigned int stdarg : 1;					-- in base */
+  /* unsigned int after_inlining : 1;				-- in base */
+  /* unsigned int always_inline_functions_inlined : 1;		-- in base */
+  /* unsigned int can_throw_non_call_exceptions : 1;		-- in base */
+  /* unsigned int returns_struct : 1;				-- in base */
+  /* unsigned int returns_pcc_struct : 1;			-- in base */
+  /* unsigned int after_tree_profile : 1;			-- in base */
+  /* unsigned int has_local_explicit_reg_vars : 1;		-- in base */
+  /* unsigned int is_thunk : 1;					-- in base */
+
+  return fn;
+}
+
+
 /* Read all the fields of lang_decl_ns instance LDNS from STREAM.  */
 
 static void
@@ -932,6 +1014,7 @@ pph_read_tree (struct lto_input_block *i
       DECL_INITIAL (expr) = pph_in_tree (stream);
       pph_in_lang_specific (stream, expr);
       DECL_SAVED_TREE (expr) = pph_in_tree (stream);
+      DECL_STRUCT_FUNCTION (expr) = pph_in_struct_function (stream);
       break;
 
     case TYPE_DECL:
Index: gcc/cp/pph-streamer-out.c
===================================================================
--- gcc/cp/pph-streamer-out.c	(revision 175056)
+++ gcc/cp/pph-streamer-out.c	(working copy)
@@ -599,6 +599,89 @@ pph_out_ld_fn (pph_stream *stream, struc
 }
 
 
+/* A callback of htab_traverse. Just extracts a (type) tree from SLOT
+   and writes it out for PPH. */
+
+struct pph_tree_info {
+  pph_stream *stream;
+  bool ref_p;
+};
+
+static int
+pph_out_used_types_slot (void **slot, void *aux)
+{
+  struct pph_tree_info *pti = (struct pph_tree_info *)aux;
+  pph_out_tree_or_ref (pti->stream, (tree) *slot, pti->ref_p);
+  return 1;
+}
+
+
+/* Write applicable fields of struct function instance FN to STREAM.
+   If REF_P is true, all tree fields should be written as references.  */
+
+static void
+pph_out_struct_function (pph_stream *stream, struct function *fn, bool ref_p)
+{
+  struct pph_tree_info pti;
+
+  if (!pph_start_record (stream, fn))
+    return;
+
+  output_struct_function_base (stream->ob, fn);
+
+  /* struct eh_status *eh;					-- ignored */
+  gcc_assert (fn->cfg == NULL);
+  gcc_assert (fn->gimple_body == NULL);
+  gcc_assert (fn->gimple_df == NULL);
+  gcc_assert (fn->x_current_loops == NULL);
+  gcc_assert (fn->su == NULL);
+  /* htab_t value_histograms;					-- ignored */
+  /* tree decl;							-- ignored */
+  /* tree static_chain_decl;					-- in base */
+  /* tree nonlocal_goto_save_area;				-- in base */
+  /* VEC(tree,gc) *local_decls;					-- in base */
+  /* struct machine_function *machine;				-- ignored */
+  pph_out_language_function (stream, fn->language, ref_p);
+
+  /*FIXME pph: We would like to detect improper sharing here.  */
+  if (fn->used_types_hash)
+    {
+      /*FIXME pph: This write may be unstable.  */
+      pph_out_uint (stream, htab_elements (fn->used_types_hash));
+      pti.stream = stream;
+      pti.ref_p = ref_p;
+      htab_traverse_noresize (fn->used_types_hash,
+			      pph_out_used_types_slot, &pti);
+    }
+  else
+    pph_out_uint (stream, 0);
+
+  gcc_assert (fn->last_stmt_uid == 0);
+  /* int funcdef_no;						-- ignored */
+  /* location_t function_start_locus;				-- in base */
+  /* location_t function_end_locus;				-- in base */
+  /* unsigned int curr_properties;				-- in base */
+  /* unsigned int last_verified;				-- ignored */
+  /* const char *cannot_be_copied_reason;			-- ignored */
+
+  /* unsigned int va_list_gpr_size : 8;				-- in base */
+  /* unsigned int va_list_fpr_size : 8;				-- in base */
+  /* unsigned int calls_setjmp : 1;				-- in base */
+  /* unsigned int calls_alloca : 1;				-- in base */
+  /* unsigned int has_nonlocal_label : 1;			-- in base */
+  /* unsigned int cannot_be_copied_set : 1;			-- ignored */
+  /* unsigned int stdarg : 1;					-- in base */
+  /* unsigned int after_inlining : 1;				-- in base */
+  /* unsigned int always_inline_functions_inlined : 1;		-- in base */
+  /* unsigned int can_throw_non_call_exceptions : 1;		-- in base */
+  /* unsigned int returns_struct : 1;				-- in base */
+  /* unsigned int returns_pcc_struct : 1;			-- in base */
+  /* unsigned int after_tree_profile : 1;			-- in base */
+  /* unsigned int has_local_explicit_reg_vars : 1;		-- in base */
+  /* unsigned int is_thunk : 1;					-- in base */
+}
+
+
 /* Write all the fields of lang_decl_ns instance LDNS to STREAM.  If REF_P
    is true, all tree fields should be written as references.  */
 
@@ -883,6 +966,7 @@ pph_write_tree (struct output_block *ob,
       pph_out_tree_or_ref_1 (stream, DECL_INITIAL (expr), ref_p, 3);
       pph_out_lang_specific (stream, expr, ref_p);
       pph_out_tree_or_ref_1 (stream, DECL_SAVED_TREE (expr), ref_p, 3);
+      pph_out_struct_function (stream, DECL_STRUCT_FUNCTION (expr), ref_p);
       break;
 
     case TYPE_DECL:
Index: gcc/lto-streamer-out.c
===================================================================
--- gcc/lto-streamer-out.c	(revision 175056)
+++ gcc/lto-streamer-out.c	(working copy)
@@ -967,8 +967,8 @@ static void
 lto_output_ts_function_decl_tree_pointers (struct output_block *ob, tree expr,
 					   bool ref_p)
 {
-  /* DECL_STRUCT_FUNCTION is handled by lto_output_function.  FIXME lto,
-     maybe it should be handled here?  */
+  /* DECL_STRUCT_FUNCTION is handled by lto_streamer-out.c:output_function
+     or by pph-specific code.  */
   lto_output_tree_or_ref (ob, DECL_FUNCTION_PERSONALITY (expr), ref_p);
   lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_TARGET (expr), ref_p);
   lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr),
@@ -1974,36 +1974,48 @@ produce_asm (struct output_block *ob, tr
 }
 
 
-/* Output the body of function NODE->DECL.  */
+/* Output the base body of struct function FN using output block OB.  */
 
-static void
-output_function (struct cgraph_node *node)
+void
+output_struct_function_base (struct output_block *ob, struct function *fn)
 {
   struct bitpack_d bp;
-  tree function;
-  struct function *fn;
-  basic_block bb;
-  struct output_block *ob;
   unsigned i;
   tree t;
 
-  function = node->decl;
-  fn = DECL_STRUCT_FUNCTION (function);
-  ob = create_output_block (LTO_section_function_body);
+  /* struct eh_status *eh;				-- maybe elsewhere */
+  /* struct control_flow_graph *cfg;			-- maybe elsewhere */
+  /* struct gimple_seq_d *gimple_body;			-- maybe elsewhere */
+  /* struct gimple_df *gimple_df;			-- maybe elsewhere */
+  /* struct loops *x_current_loops;			-- maybe elsewhere */
+  /* struct stack_usage *su;				-- maybe elsewhere */
+  /* htab_t value_histograms;				-- ignored */
+  /* tree decl;						-- ignored */
 
-  clear_line_info (ob);
-  ob->cgraph_node = node;
+  /* Output the static chain and non-local goto save area.  */
+  lto_output_tree_ref (ob, fn->static_chain_decl);
+  lto_output_tree_ref (ob, fn->nonlocal_goto_save_area);
 
-  gcc_assert (current_function_decl == NULL_TREE && cfun == NULL);
+  /* Output all the local variables in the function.  */
+  output_sleb128 (ob, VEC_length (tree, fn->local_decls));
+  FOR_EACH_VEC_ELT (tree, fn->local_decls, i, t)
+    lto_output_tree_ref (ob, t);
 
-  /* Set current_function_decl and cfun.  */
-  current_function_decl = function;
-  push_cfun (fn);
+  /* struct machine_function * machine;			-- ignored */
+  /* struct language_function * language;		-- maybe elsewhere */
+  /* htab_t used_types_hash;				-- maybe elsewhere */
+  /* int last_stmt_uid;					-- maybe elsewhere */
+  /* int funcdef_no;					-- maybe elsewhere */
 
-  /* Make string 0 be a NULL string.  */
-  lto_output_1_stream (ob->string_stream, 0);
+  /* Output the function start and end loci.  */
+  lto_output_location (ob, fn->function_start_locus);
+  lto_output_location (ob, fn->function_end_locus);
 
-  output_record_start (ob, LTO_function);
+  /* Output current IL state of the function.  */
+  output_uleb128 (ob, fn->curr_properties);
+
+  /* unsigned int last_verified;			-- ignored */
+  /* const char *cannot_be_copied_reason;		-- ignored */
 
   /* Write all the attributes for FN.  */
   bp = bitpack_create (ob->main_stream);
@@ -2016,28 +2028,45 @@ output_function (struct cgraph_node *nod
   bp_pack_value (&bp, fn->always_inline_functions_inlined, 1);
   bp_pack_value (&bp, fn->after_inlining, 1);
   bp_pack_value (&bp, fn->stdarg, 1);
+  /* unsigned int cannot_be_copied_set : 1;		-- ignored */
   bp_pack_value (&bp, fn->has_nonlocal_label, 1);
   bp_pack_value (&bp, fn->calls_alloca, 1);
   bp_pack_value (&bp, fn->calls_setjmp, 1);
   bp_pack_value (&bp, fn->va_list_fpr_size, 8);
   bp_pack_value (&bp, fn->va_list_gpr_size, 8);
   lto_output_bitpack (&bp);
+}
 
-  /* Output the function start and end loci.  */
-  lto_output_location (ob, fn->function_start_locus);
-  lto_output_location (ob, fn->function_end_locus);
 
-  /* Output current IL state of the function.  */
-  output_uleb128 (ob, fn->curr_properties);
+/* Output the body of function NODE->DECL.  */
 
-  /* Output the static chain and non-local goto save area.  */
-  lto_output_tree_ref (ob, fn->static_chain_decl);
-  lto_output_tree_ref (ob, fn->nonlocal_goto_save_area);
+static void
+output_function (struct cgraph_node *node)
+{
+  tree function;
+  struct function *fn;
+  basic_block bb;
+  struct output_block *ob;
 
-  /* Output all the local variables in the function.  */
-  output_sleb128 (ob, VEC_length (tree, fn->local_decls));
-  FOR_EACH_VEC_ELT (tree, fn->local_decls, i, t)
-    lto_output_tree_ref (ob, t);
+  function = node->decl;
+  fn = DECL_STRUCT_FUNCTION (function);
+  ob = create_output_block (LTO_section_function_body);
+
+  clear_line_info (ob);
+  ob->cgraph_node = node;
+
+  gcc_assert (current_function_decl == NULL_TREE && cfun == NULL);
+
+  /* Set current_function_decl and cfun.  */
+  current_function_decl = function;
+  push_cfun (fn);
+
+  /* Make string 0 be a NULL string.  */
+  lto_output_1_stream (ob->string_stream, 0);
+
+  output_record_start (ob, LTO_function);
+
+  output_struct_function_base (ob, fn);
 
   /* Output the head of the arguments list.  */
   lto_output_tree_ref (ob, DECL_ARGUMENTS (function));
Index: gcc/lto-streamer-in.c
===================================================================
--- gcc/lto-streamer-in.c	(revision 175056)
+++ gcc/lto-streamer-in.c	(working copy)
@@ -1242,27 +1242,55 @@ fixup_call_stmt_edges (struct cgraph_nod
       }
 }
 
-/* Read the body of function FN_DECL from DATA_IN using input block IB.  */
 
-static void
-input_function (tree fn_decl, struct data_in *data_in,
-		struct lto_input_block *ib)
+/* Input the base body of struct function FN from DATA_IN
+   using input block IB.  */
+
+void
+input_struct_function_base (struct function *fn, struct data_in *data_in,
+                            struct lto_input_block *ib)
 {
-  struct function *fn;
-  enum LTO_tags tag;
-  gimple *stmts;
-  basic_block bb;
   struct bitpack_d bp;
-  struct cgraph_node *node;
-  tree args, narg, oarg;
   int len;
 
-  fn = DECL_STRUCT_FUNCTION (fn_decl);
-  tag = input_record_start (ib);
-  clear_line_info (data_in);
+  /* struct eh_status *eh;				-- maybe elsewhere */
+  /* struct control_flow_graph *cfg;			-- maybe elsewhere */
+  /* struct gimple_seq_d *gimple_body;			-- maybe elsewhere */
+  /* struct gimple_df *gimple_df;			-- maybe elsewhere */
+  /* struct loops *x_current_loops;			-- maybe elsewhere */
+  /* struct stack_usage *su;				-- maybe elsewhere */
+  /* htab_t value_histograms;				-- ignored */
+  /* tree decl;						-- ignored */
 
-  gimple_register_cfg_hooks ();
-  lto_tag_check (tag, LTO_function);
+  /* Read the static chain and non-local goto save area.  */
+  fn->static_chain_decl = lto_input_tree (ib, data_in);
+  fn->nonlocal_goto_save_area = lto_input_tree (ib, data_in);
+
+  /* Read all the local symbols.  */
+  len = lto_input_sleb128 (ib);
+  if (len > 0)
+    {
+      int i;
+      VEC_safe_grow (tree, gc, fn->local_decls, len);
+      for (i = 0; i < len; i++)
+	{
+	  tree t = lto_input_tree (ib, data_in);
+	  VEC_replace (tree, fn->local_decls, i, t);
+	}
+    }
+
+  /* struct machine_function * machine;			-- ignored */
+  /* struct language_function * language;		-- maybe elsewhere */
+  /* htab_t used_types_hash;				-- maybe elsewhere */
+  /* int last_stmt_uid;					-- maybe elsewhere */
+  /* int funcdef_no;					-- maybe elsewhere */
+
+  /* Input the function start and end loci.  */
+  fn->function_start_locus = lto_input_location (ib, data_in);
+  fn->function_end_locus = lto_input_location (ib, data_in);
+
+  /* Input the current IL state of the function.  */
+  fn->curr_properties = lto_input_uleb128 (ib);
 
   /* Read all the attributes for FN.  */
   bp = lto_input_bitpack (ib);
@@ -1280,30 +1308,30 @@ input_function (tree fn_decl, struct dat
   fn->calls_setjmp = bp_unpack_value (&bp, 1);
   fn->va_list_fpr_size = bp_unpack_value (&bp, 8);
   fn->va_list_gpr_size = bp_unpack_value (&bp, 8);
+}
 
-  /* Input the function start and end loci.  */
-  fn->function_start_locus = lto_input_location (ib, data_in);
-  fn->function_end_locus = lto_input_location (ib, data_in);
 
-  /* Input the current IL state of the function.  */
-  fn->curr_properties = lto_input_uleb128 (ib);
+/* Read the body of function FN_DECL from DATA_IN using input block IB.  */
 
-  /* Read the static chain and non-local goto save area.  */
-  fn->static_chain_decl = lto_input_tree (ib, data_in);
-  fn->nonlocal_goto_save_area = lto_input_tree (ib, data_in);
+static void
+input_function (tree fn_decl, struct data_in *data_in,
+		struct lto_input_block *ib)
+{
+  struct function *fn;
+  enum LTO_tags tag;
+  gimple *stmts;
+  basic_block bb;
+  struct cgraph_node *node;
+  tree args, narg, oarg;
 
-  /* Read all the local symbols.  */
-  len = lto_input_sleb128 (ib);
-  if (len > 0)
-    {
-      int i;
-      VEC_safe_grow (tree, gc, fn->local_decls, len);
-      for (i = 0; i < len; i++)
-	{
-	  tree t = lto_input_tree (ib, data_in);
-	  VEC_replace (tree, fn->local_decls, i, t);
-	}
-    }
+  fn = DECL_STRUCT_FUNCTION (fn_decl);
+  tag = input_record_start (ib);
+  clear_line_info (data_in);
+
+  gimple_register_cfg_hooks ();
+  lto_tag_check (tag, LTO_function);
+
+  input_struct_function_base (fn, data_in, ib);
 
   /* Read all function arguments.  We need to re-map them here to the
      arguments of the merged function declaration.  */
Index: gcc/lto-streamer.h
===================================================================
--- gcc/lto-streamer.h	(revision 175056)
+++ gcc/lto-streamer.h	(working copy)
@@ -963,6 +963,9 @@ extern void lto_input_cgraph (struct lto
 extern void lto_reader_init (void);
 extern tree lto_input_tree (struct lto_input_block *, struct data_in *);
 extern tree lto_input_chain (struct lto_input_block *, struct data_in *);
+extern void input_struct_function_base (struct function *fn,
+					struct data_in *data_in,
+					struct lto_input_block *ib);
 extern void lto_input_function_body (struct lto_file_decl_data *, tree,
 				     const char *);
 extern void lto_input_constructors_and_inits (struct lto_file_decl_data *,
@@ -985,6 +988,8 @@ extern void destroy_output_block (struct
 extern void lto_output_tree (struct output_block *, tree, bool);
 extern void lto_output_tree_or_ref (struct output_block *, tree, bool);
 extern void lto_output_chain (struct output_block *, tree, bool);
+extern void output_struct_function_base (struct output_block *ob,
+					 struct function *fn);
 extern void produce_asm (struct output_block *ob, tree fn);
 void lto_output_decl_state_streams (struct output_block *,
 				    struct lto_out_decl_state *);
