[pph] Support simple C++ programs (issue4630074)

Diego Novillo dnovillo@google.com
Wed Jun 29 07:50:00 GMT 2011


This patch adds support for emitting functions read from a PPH image.
With this, we can now run some simple C++ programs whose header has
been reconstructed from a single PPH image.

The core problem it fixes was in the saving and restoring of functions
with a body.

1- When the parser wants to register a function for code
   generation, it calls expand_or_defer_fn().  When reading from the
   pph image, we were not calling this, so the callgraph manager was
   tossing these functions out.

2- Even when we call expand_or_defer_fn, we need to take care of
   another side-effect.  In the writer, the call to expand_or_defer_fn
   sets DECL_EXTERNAL to 1 (for reasons that I'm not too sure I
   understand).  At the same time, it remembers that it forced
   DECL_EXTERNAL by setting DECL_NOT_REALLY_EXTERN.  Since I don't
   think I understand why it does this, I'm simply using
   DECL_NOT_REALLY_EXTERN in the reader to recognize that the decl is
   should have DECL_EXTERNAL set to 0.  Jason, does this make any
   sense?

This fixed a whole bunch of tests: c1builtin-object-size-2.cc,
c1funcstatic.cc, c1return-5.cc, c1simple.cc, x1autometh.cc,
x1funcstatic.cc, x1struct1.cc, x1ten-hellos.cc and x1tmplfunc.cc.

It also exposed other bugs in c c1attr-warn-unused-result.cc and
x1template.cc. Lawrence, Gab, I think this affects some of the
failures you were looking at today.  Please double check.

I also added support for 'dg-do run' tests to support x1ten-hellos.cc
which now actually works (though it is not completely bug-free, I see
that the counter it initializes starts with a bogus value).

Tested on x86_64.  Committed to branch.


cp/ChangeLog.pph
2011-06-28   Diego Novillo  <dnovillo@google.com>

	* pph-streamer-in.c (pph_in_ld_fn): Instantiate
	DECL_STRUCT_FUNCTION by calling allocate_struct_function.
	Remove assertion for stream->data_in.
	(pph_in_function_decl): Factor out of ...
	(pph_read_tree): ... here.
	* pph-streamer-out.c (pph_out_function_decl): Factor out of ...
	(pph_write_tree): ... here.

testsuite/ChangeLog.pph
	* g++.dg/pph/c1attr-warn-unused-result.cc: Expect an ICE.
	* g++.dg/pph/x1template.cc: Likewise.
	* g++.dg/pph/c1builtin-object-size-2.cc: Expect no asm difference.
	* g++.dg/pph/c1funcstatic.cc: Likewise.
	* g++.dg/pph/c1return-5.cc: Likewise.
	* g++.dg/pph/c1simple.cc: Likewise.
	* g++.dg/pph/x1autometh.cc: Likewise.
	* g++.dg/pph/x1funcstatic.cc: Likewise.
	* g++.dg/pph/x1struct1.cc: Likewise.
	* g++.dg/pph/x1ten-hellos.cc: Likewise.
	* g++.dg/pph/x1tmplfunc.cc: Likewise.
	* g++.dg/pph/c1meteor-contest.cc: Adjust timeout.
	* g++.dg/pph/x1dynarray1.cc: Adjust expected ICE.
	* g++.dg/pph/x1namespace.cc: Likewise.
	* lib/dg-pph.exp: Do not compare assembly output if the test
	is marked 'dg-do run'.

diff --git a/gcc/cp/pph-streamer-in.c b/gcc/cp/pph-streamer-in.c
index 7f70b65..1dabcf1 100644
--- a/gcc/cp/pph-streamer-in.c
+++ b/gcc/cp/pph-streamer-in.c
@@ -767,18 +767,17 @@ pph_in_ld_fn (pph_stream *stream, struct lang_decl_fn *ldf)
 }
 
 
-/* Read applicable fields of struct function instance FN from STREAM.  */
+/* Read applicable fields of struct function from STREAM.  Associate
+   the read structure to DECL.  */
 
 static struct function *
-pph_in_struct_function (pph_stream *stream)
+pph_in_struct_function (pph_stream *stream, tree decl)
 {
   size_t count, i;
   unsigned ix;
   enum pph_record_marker marker;
   struct function *fn;
 
-  gcc_assert (stream->data_in != NULL);
-
   marker = pph_in_start_record (stream, &ix);
   if (marker == PPH_RECORD_END)
     return NULL;
@@ -786,7 +785,8 @@ pph_in_struct_function (pph_stream *stream)
   /* Since struct function is embedded in every decl, fn cannot be shared.  */
   gcc_assert (marker != PPH_RECORD_SHARED);
 
-  fn = ggc_alloc_cleared_function ();
+  allocate_struct_function (decl, false);
+  fn = DECL_STRUCT_FUNCTION (decl);
 
   input_struct_function_base (fn, stream->data_in, stream->ib);
 
@@ -1355,6 +1355,35 @@ pph_read_file (const char *filename)
 }
 
 
+/* Read the attributes for a FUNCTION_DECL FNDECL.  If FNDECL had
+   a body, mark it for expansion.  */
+
+static void
+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))
+    {
+      /* 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);
+    }
+}
+
+
 /* Callback for reading ASTs from a stream.  This reads all the fields
    that are not processed by default by the common tree pickler.
    IB, DATA_IN are as in lto_read_tree.  EXPR is the partially materialized
@@ -1394,11 +1423,7 @@ pph_read_tree (struct lto_input_block *ib ATTRIBUTE_UNUSED,
       break;
 
     case FUNCTION_DECL:
-      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);
-      DECL_CHAIN (expr) = pph_in_tree (stream);
+      pph_in_function_decl (stream, expr);
       break;
 
     case TYPE_DECL:
diff --git a/gcc/cp/pph-streamer-out.c b/gcc/cp/pph-streamer-out.c
index 045f68a..acc0352 100644
--- a/gcc/cp/pph-streamer-out.c
+++ b/gcc/cp/pph-streamer-out.c
@@ -1241,6 +1241,19 @@ pph_out_tree_header (struct output_block *ob, tree expr)
 }
 
 
+/* Emit the fields of FUNCTION_DECL FNDECL to STREAM.  REF_P is as
+   in pph_write_tree.  */
+
+static void
+pph_out_function_decl (pph_stream *stream, tree fndecl, bool ref_p)
+{
+  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.  */
@@ -1278,11 +1291,7 @@ pph_write_tree (struct output_block *ob, tree expr, bool ref_p)
       break;
 
     case FUNCTION_DECL:
-      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);
-      pph_out_tree_or_ref_1 (stream, DECL_CHAIN (expr), ref_p, 3);
+      pph_out_function_decl (stream, expr, ref_p);
       break;
 
     case TYPE_DECL:
diff --git a/gcc/testsuite/g++.dg/pph/c1attr-warn-unused-result.cc b/gcc/testsuite/g++.dg/pph/c1attr-warn-unused-result.cc
index da75561..4633106 100644
--- a/gcc/testsuite/g++.dg/pph/c1attr-warn-unused-result.cc
+++ b/gcc/testsuite/g++.dg/pph/c1attr-warn-unused-result.cc
@@ -1,3 +1,6 @@
+/* { dg-xfail-if "ICE" { "*-*-*" } { "-fpph-map=pph.map" } } */
+// { dg-bogus "internal compiler error: Segmentation fault" "" { xfail *-*-* } 0 }
+// { dg-prune-output "In file included from" }
 /* { dg-options "-w" } */
 // pph asm xdiff
 #include "c1attr-warn-unused-result.h"
diff --git a/gcc/testsuite/g++.dg/pph/c1builtin-object-size-2.cc b/gcc/testsuite/g++.dg/pph/c1builtin-object-size-2.cc
index 17fe707..615e7da 100644
--- a/gcc/testsuite/g++.dg/pph/c1builtin-object-size-2.cc
+++ b/gcc/testsuite/g++.dg/pph/c1builtin-object-size-2.cc
@@ -1,3 +1,2 @@
 /* { dg-options "-O2 -w -fpermissive" } */
-// pph asm xdiff
 #include "c1builtin-object-size-2.h"
diff --git a/gcc/testsuite/g++.dg/pph/c1funcstatic.cc b/gcc/testsuite/g++.dg/pph/c1funcstatic.cc
index 05a487c..b6cd27e 100644
--- a/gcc/testsuite/g++.dg/pph/c1funcstatic.cc
+++ b/gcc/testsuite/g++.dg/pph/c1funcstatic.cc
@@ -1,3 +1,2 @@
-// pph asm xdiff
 #include "c1funcstatic.h"
 int g() { return f(); }
diff --git a/gcc/testsuite/g++.dg/pph/c1meteor-contest.cc b/gcc/testsuite/g++.dg/pph/c1meteor-contest.cc
index 58d2c89..e745afe 100644
--- a/gcc/testsuite/g++.dg/pph/c1meteor-contest.cc
+++ b/gcc/testsuite/g++.dg/pph/c1meteor-contest.cc
@@ -1,4 +1,4 @@
-/* { dg-timeout 5 { target *-*-* } }  */
+/* { dg-timeout 2 { target *-*-* } }  */
 // { dg-xfail-if "INFINITE" { "*-*-*" } { "-fpph-map=pph.map" } }
 /* { dg-options "-w" }  */
 #include "c1meteor-contest.h"
diff --git a/gcc/testsuite/g++.dg/pph/c1return-5.cc b/gcc/testsuite/g++.dg/pph/c1return-5.cc
index aa7dfe4..a29c8a9 100644
--- a/gcc/testsuite/g++.dg/pph/c1return-5.cc
+++ b/gcc/testsuite/g++.dg/pph/c1return-5.cc
@@ -1,5 +1,4 @@
 // { dg-options "-mpreferred-stack-boundary=4" }
 // { dg-final { scan-assembler-not "and\[lq\]?\[^\\n\]*-64,\[^\\n\]*sp" } }
-// pph asm xdiff
 
 #include "c1return-5.h"
diff --git a/gcc/testsuite/g++.dg/pph/c1simple.cc b/gcc/testsuite/g++.dg/pph/c1simple.cc
index f4d8f1b..60aed2e 100644
--- a/gcc/testsuite/g++.dg/pph/c1simple.cc
+++ b/gcc/testsuite/g++.dg/pph/c1simple.cc
@@ -1,5 +1,3 @@
-// pph asm xdiff
-
 /* comment */
 
 #include "c1simple2.h"
diff --git a/gcc/testsuite/g++.dg/pph/x1autometh.cc b/gcc/testsuite/g++.dg/pph/x1autometh.cc
index 783c667..0c31028 100644
--- a/gcc/testsuite/g++.dg/pph/x1autometh.cc
+++ b/gcc/testsuite/g++.dg/pph/x1autometh.cc
@@ -1,5 +1,3 @@
-// pph asm xdiff
-
 #include "x1autometh.h"
 
 void function() {
diff --git a/gcc/testsuite/g++.dg/pph/x1dynarray1.cc b/gcc/testsuite/g++.dg/pph/x1dynarray1.cc
index 6fa12df..19f5b4c 100644
--- a/gcc/testsuite/g++.dg/pph/x1dynarray1.cc
+++ b/gcc/testsuite/g++.dg/pph/x1dynarray1.cc
@@ -1,5 +1,5 @@
 // { dg-xfail-if "ICE" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "x1dynarray1.cc:1:0: internal compiler error: in pph_in_lang_specific, at cp/pph-streamer-in.c:887" "" { xfail *-*-* } 0 }
+// { dg-bogus "internal compiler error: Segmentation fault" "" { xfail *-*-* } 0 }
 
 #include "x1dynarray1.h"
 #include <iostream>
diff --git a/gcc/testsuite/g++.dg/pph/x1funcstatic.cc b/gcc/testsuite/g++.dg/pph/x1funcstatic.cc
index a920c5a..31166f6 100644
--- a/gcc/testsuite/g++.dg/pph/x1funcstatic.cc
+++ b/gcc/testsuite/g++.dg/pph/x1funcstatic.cc
@@ -1,3 +1,2 @@
-// pph asm xdiff
 #include "c1funcstatic.h"
 int a = f();
diff --git a/gcc/testsuite/g++.dg/pph/x1namespace.cc b/gcc/testsuite/g++.dg/pph/x1namespace.cc
index 547150c..16afff9 100644
--- a/gcc/testsuite/g++.dg/pph/x1namespace.cc
+++ b/gcc/testsuite/g++.dg/pph/x1namespace.cc
@@ -1,5 +1,5 @@
 // { dg-xfail-if "ICE" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "x1namespace.h:18:13: internal compiler error: in resume_scope" "" { xfail *-*-* } 0 }
+// { dg-bogus "internal compiler error: Segmentation fault" "" { xfail *-*-* } 0 }
 // { dg-prune-output "In file included from " }
 
 #include "x1namespace.h"
diff --git a/gcc/testsuite/g++.dg/pph/x1struct1.cc b/gcc/testsuite/g++.dg/pph/x1struct1.cc
index 5a4fbd6..69aed1b 100644
--- a/gcc/testsuite/g++.dg/pph/x1struct1.cc
+++ b/gcc/testsuite/g++.dg/pph/x1struct1.cc
@@ -1,5 +1,3 @@
-// pph asm xdiff
-
 #include "x1struct1.h"
 
 type D::method()
diff --git a/gcc/testsuite/g++.dg/pph/x1template.cc b/gcc/testsuite/g++.dg/pph/x1template.cc
index a50abb0..fbcb1bf 100644
--- a/gcc/testsuite/g++.dg/pph/x1template.cc
+++ b/gcc/testsuite/g++.dg/pph/x1template.cc
@@ -1,3 +1,6 @@
+/* { dg-xfail-if "ICE" { "*-*-*" } { "-fpph-map=pph.map" } } */
+// { dg-bogus "internal compiler error: Segmentation fault" "" { xfail *-*-* } 0 }
+// { dg-prune-output "In file included from" }
 // pph asm xdiff
 #include "x1template.h"
 
diff --git a/gcc/testsuite/g++.dg/pph/x1ten-hellos.cc b/gcc/testsuite/g++.dg/pph/x1ten-hellos.cc
index 4ca7273..865b149 100644
--- a/gcc/testsuite/g++.dg/pph/x1ten-hellos.cc
+++ b/gcc/testsuite/g++.dg/pph/x1ten-hellos.cc
@@ -1,6 +1,4 @@
 // { dg-do run }
-// { dg-xfail-if "LINK ERROR" { "*-*-*" } { "-fpph-map=pph.map" } }
-// pph asm xdiff
 #include "x1ten-hellos.h"
 
 int main(void)
diff --git a/gcc/testsuite/g++.dg/pph/x1tmplfunc.cc b/gcc/testsuite/g++.dg/pph/x1tmplfunc.cc
index 35b4cab..dc1c413 100644
--- a/gcc/testsuite/g++.dg/pph/x1tmplfunc.cc
+++ b/gcc/testsuite/g++.dg/pph/x1tmplfunc.cc
@@ -1,5 +1,3 @@
-// pph asm xdiff
-
 #include "x1tmplfunc.h"
 
 type val = 3;
diff --git a/gcc/testsuite/lib/dg-pph.exp b/gcc/testsuite/lib/dg-pph.exp
index c773aa0..39a24b7 100644
--- a/gcc/testsuite/lib/dg-pph.exp
+++ b/gcc/testsuite/lib/dg-pph.exp
@@ -93,8 +93,10 @@ proc dg-pph-pos { subdir test options mapflag suffix } {
 
     # Quit if it did not compile successfully.
     if { ![file_on_host exists "$bname.s"] } {
-	# Expect assembly to be missing when the compile is an expected fail.
-	if { ![llength [grep $test "dg-xfail-if.*-fpph-map"]] } {
+	# Expect assembly to be missing when the compile is an
+	# expected fail or when this was an executable test.
+	if { ![string compare "dg-do-what" "run"] \
+	     && ![llength [grep $test "dg-xfail-if.*-fpph-map"]] } {
 	    fail "$nshort $options (pph assembly missing)"
 	}
 	return

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



More information about the Gcc-patches mailing list