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 <dnovi...@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