From patchwork Wed Nov 30 05:09:39 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lawrence Crowl X-Patchwork-Id: 128404 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 14C5BB6F65 for ; Wed, 30 Nov 2011 16:11:06 +1100 (EST) Received: (qmail 29724 invoked by alias); 30 Nov 2011 05:11:02 -0000 Received: (qmail 29650 invoked by uid 22791); 30 Nov 2011 05:10:34 -0000 X-SWARE-Spam-Status: No, hits=-1.2 required=5.0 tests=AWL, BAYES_50, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, TW_BJ, TW_CP, TW_CX, TW_FN, TW_JC, TW_TJ, TW_TM X-Spam-Check-By: sourceware.org Received: from mail-gx0-f201.google.com (HELO mail-gx0-f201.google.com) (209.85.161.201) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 30 Nov 2011 05:09:44 +0000 Received: by ggnv5 with SMTP id v5so745ggn.2 for ; Tue, 29 Nov 2011 21:09:42 -0800 (PST) Received: by 10.101.15.15 with SMTP id s15mr165991ani.16.1322629782898; Tue, 29 Nov 2011 21:09:42 -0800 (PST) Received: by 10.101.15.15 with SMTP id s15mr165975ani.16.1322629782688; Tue, 29 Nov 2011 21:09:42 -0800 (PST) Received: from wpzn4.hot.corp.google.com (216-239-44-65.google.com [216.239.44.65]) by gmr-mx.google.com with ESMTPS id r27si265389yhm.4.2011.11.29.21.09.42 (version=TLSv1/SSLv3 cipher=AES128-SHA); Tue, 29 Nov 2011 21:09:42 -0800 (PST) Received: from wpaz9.hot.corp.google.com (wpaz9.hot.corp.google.com [172.24.198.73]) by wpzn4.hot.corp.google.com (Postfix) with ESMTPS id 913A91E004D; Tue, 29 Nov 2011 21:09:42 -0800 (PST) Received: from jade.mtv.corp.google.com (jade.mtv.corp.google.com [172.18.110.116]) by wpaz9.hot.corp.google.com with ESMTP id pAU59eV8012660; Tue, 29 Nov 2011 21:09:40 -0800 Received: by jade.mtv.corp.google.com (Postfix, from userid 21482) id DCF3F2225CA; Tue, 29 Nov 2011 21:09:39 -0800 (PST) To: reply@codereview.appspotmail.com, dnovillo@google.com, gcc-patches@gcc.gnu.org Subject: [pph] Merge and rename pph sources. (issue5440063) Message-Id: <20111130050939.DCF3F2225CA@jade.mtv.corp.google.com> Date: Tue, 29 Nov 2011 21:09:39 -0800 (PST) From: crowl@google.com (Lawrence Crowl) X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Merge pph.c and pph-streamer.c into pph-core.c. Shorten pph-streamer-in.c to pph-in.c. Shorten pph-streamer-out.c to pph-out.c. Reduce redundancies in make dependences. --- This patch is available for review at http://codereview.appspot.com/5440063 Index: gcc/cp/ChangeLog.pph 2011-11-29 Lawrence Crowl * pph-streamer.c: Renamed pph-core.c. * pph.c: Contents moved into pph-core.c. (pph_dump_min_decl): Removed unused. (flatten_name): Rename pph_flatten_name. * pph-streamer-in.c: Renamed pph-in.c. * pph-streamer-out.c: Renamed pph-out.c. * pph-streamer.h: Adjust to reflect above. Remove unneeded decls. * pph.h: Adjust to reflect above. * config-lang.in: Adjust to reflect above. * Make-lang.in: Adjust to reflect above. (CXX_PPH_STREAMER_H): Remove redundancies. (CXX_PPH_COMMON_H): New. (CXX_PPH_COMMON_H): New. (cp/pph-core.o): Remove redundancies. (cp/pph-in.o): Remove redundancies. (cp/pph-out.o): Remove redundancies. (cp/pt.o): Add depndence on CXX_PPH_H. * pt.c: Remove redundant #include "pph-streamer.h". Index: gcc/cp/pph-core.c =================================================================== --- gcc/cp/pph-core.c (revision 181815) +++ gcc/cp/pph-core.c (working copy) @@ -1,6 +1,8 @@ -/* Routines for streaming PPH data. - Copyright (C) 2011 Free Software Foundation, Inc. - Contributed by Diego Novillo . +/* Factored pre-parsed header (PPH) support for C++. + Common routines for streaming PPH data. + Copyright (C) 2010, 2011 Free Software Foundation, Inc. + Contributed by Lawrence Crowl and + Diego Novillo . This file is part of GCC. @@ -18,320 +20,131 @@ You should have received a copy of the G along with GCC; see the file COPYING3. If not see . */ + #include "config.h" #include "system.h" #include "coretypes.h" #include "pph.h" +#include "cpplib.h" +#include "toplev.h" #include "tree.h" +#include "cp-tree.h" #include "langhooks.h" +#include "timevar.h" #include "tree-iterator.h" #include "tree-pretty-print.h" #include "lto-streamer.h" #include "pph-streamer.h" +#include "pointer-set.h" +#include "fixed-value.h" +#include "md5.h" #include "tree-pass.h" +#include "tree-dump.h" +#include "tree-inline.h" +#include "tree-pretty-print.h" +#include "cxx-pretty-print.h" +#include "parser.h" #include "version.h" #include "cppbuiltin.h" #include "streamer-hooks.h" -/* List of PPH images opened for reading. Images opened during #include - processing and opened from pph_in_includes cannot be closed - immediately after reading, because the pickle cache contained in - them may be referenced from other images. We delay closing all of - them until the end of parsing (when pph_streamer_finish is called). */ -static VEC(pph_stream_ptr, heap) *pph_read_images = NULL; - -/* A cache of pre-loaded common tree nodes. */ -static pph_cache *pph_preloaded_cache; - -/* Pre-load common tree nodes into CACHE. These nodes are always built by the - front end, so there is no need to pickle them. */ - -static void -pph_cache_preload (pph_cache *cache) -{ - unsigned i; - - for (i = itk_char; i < itk_none; i++) - pph_cache_add (cache, integer_types[i], NULL, - pph_tree_code_to_tag (integer_types[i])); - - for (i = 0; i < TYPE_KIND_LAST; i++) - pph_cache_add (cache, sizetype_tab[i], NULL, - pph_tree_code_to_tag (sizetype_tab[i])); - - /* global_trees[] can have NULL entries in it. Skip them. */ - for (i = 0; i < TI_MAX; i++) - if (global_trees[i]) - pph_cache_add (cache, global_trees[i], NULL, - pph_tree_code_to_tag (global_trees[i])); - - /* c_global_trees[] can have NULL entries in it. Skip them. */ - for (i = 0; i < CTI_MAX; i++) - if (c_global_trees[i]) - pph_cache_add (cache, c_global_trees[i], NULL, - pph_tree_code_to_tag (c_global_trees[i])); - - /* cp_global_trees[] can have NULL entries in it. Skip them. */ - for (i = 0; i < CPTI_MAX; i++) - { - /* Also skip trees which are generated while parsing. */ - if (i == CPTI_KEYED_CLASSES) - continue; - - if (cp_global_trees[i]) - pph_cache_add (cache, cp_global_trees[i], NULL, - pph_tree_code_to_tag (cp_global_trees[i])); - } - - /* Add other well-known nodes that should always be taken from the - current compilation context. */ - pph_cache_add (cache, global_namespace, NULL, - pph_tree_code_to_tag (global_namespace)); - pph_cache_add (cache, DECL_CONTEXT (global_namespace), NULL, - pph_tree_code_to_tag (DECL_CONTEXT (global_namespace))); -} - - -/* Callback for writing ASTs to a stream. Write EXPR to the PPH stream - in OB. */ - -static void -pph_write_tree (struct output_block *ob, tree expr, bool ref_p ATTRIBUTE_UNUSED) -{ - pph_out_tree ((pph_stream *) ob->sdata, expr); -} - - -/* Callback for reading ASTs from a stream. Instantiate and return a - new tree from the PPH stream in DATA_IN. */ -static tree -pph_read_tree (struct lto_input_block *ib ATTRIBUTE_UNUSED, - struct data_in *data_in) -{ - return pph_in_tree ((pph_stream *) data_in->sdata); -} - - -/* Callback for streamer_hooks.input_location. An offset is applied to - the location_t read in according to the properties of the merged - line_table. IB and DATA_IN are as in lto_input_location. This function - should only be called after pph_in_and_merge_line_table was called as - we expect pph_loc_offset to be set. */ - -static location_t -pph_input_location (struct lto_input_block *ib ATTRIBUTE_UNUSED, - struct data_in *data_in) -{ - return pph_in_location ((pph_stream *) data_in->sdata); -} - - -/* Callback for streamer_hooks.output_location. Output the LOC directly, - an offset will be applied on input after rebuilding the line_table. - OB and LOC are as in lto_output_location. */ - -static void -pph_output_location (struct output_block *ob, location_t loc) -{ - pph_out_location ((pph_stream *) ob->sdata, loc); -} - - -/* Initialize all the streamer hooks used for streaming ASTs. */ - -static void -pph_hooks_init (void) -{ - streamer_hooks_init (); - streamer_hooks.write_tree = pph_write_tree; - streamer_hooks.read_tree = pph_read_tree; - streamer_hooks.input_location = pph_input_location; - streamer_hooks.output_location = pph_output_location; -} +/*************************************************************** pph logging */ -/* Initialize an empty pickle CACHE. */ - -static void -pph_cache_init (pph_cache *cache) -{ - cache->v = NULL; - cache->m = pointer_map_create (); -} +/* Log file where PPH analysis is written to. Controlled by + -fpph_logfile. If this flag is not given, stdout is used. */ +FILE *pph_logfile = NULL; -/* Initialize the pre-loaded cache. This contains all the common - tree nodes built by the compiler on startup. */ +/* Convert a checked tree_code CODE to a string. */ -static void -pph_init_preloaded_cache (void) +const char * +pph_tree_code_text (enum tree_code code) { - pph_preloaded_cache = XCNEW (pph_cache); - pph_cache_init (pph_preloaded_cache); - pph_cache_preload (pph_preloaded_cache); + gcc_assert (code < MAX_TREE_CODES); + return tree_code_name[code]; } -/* Initialize the streamer. */ +/* Dump a location LOC to FILE. */ void -pph_streamer_init (void) +pph_dump_location (FILE *file, location_t loc) { - pph_hooks_init (); - pph_init_preloaded_cache (); + expanded_location xloc = expand_location (loc); + fprintf (file, "%s:%d", xloc.file, xloc.line); } -/* Finalize the streamer. */ +/* Dump a complicated name for tree T to FILE using FLAGS. + See TDF_* in tree-pass.h for flags. */ void -pph_streamer_finish (void) +pph_dump_tree_name (FILE *file, tree t, int flags) { - unsigned i; - pph_stream *image; - - /* Finalize the writer. */ - pph_writer_finish (); - - /* Finalize the reader. */ - pph_reader_finish (); - - /* Close any images read during parsing. */ - FOR_EACH_VEC_ELT (pph_stream_ptr, pph_read_images, i, image) - pph_stream_close (image); - - VEC_free (pph_stream_ptr, heap, pph_read_images); + enum tree_code code = TREE_CODE (t); + const char *text = pph_tree_code_text (code); + if (DECL_P (t)) + fprintf (file, "%s %s\n", text, decl_as_string (t, flags)); + else if (TYPE_P (t)) + fprintf (file, "%s %s\n", text, type_as_string (t, flags)); + else if (EXPR_P (t)) + fprintf (file, "%s %s\n", text, expr_as_string (t, flags)); + else + { + fprintf (file, "%s ", text ); + print_generic_expr (file, t, flags); + fprintf (file, "\n"); + } } -/* If FILENAME has already been read, return the stream associated with it. */ - -static pph_stream * -pph_find_stream_for (const char *filename) -{ - pph_stream *include; - unsigned i; - - /* FIXME pph, implement a hash map to avoid this linear search. */ - FOR_EACH_VEC_ELT (pph_stream_ptr, pph_read_images, i, include) - if (strcmp (include->name, filename) == 0) - return include; - - return NULL; -} +static void +pph_dump_binding (FILE *file, cp_binding_level *level); -/* Add STREAM to the list of read images. */ +/* Dump namespace NS for PPH. */ void -pph_mark_stream_read (pph_stream *stream) +pph_dump_namespace (FILE *file, tree ns) { - stream->in_memory_p = true; - VEC_safe_push (pph_stream_ptr, heap, pph_read_images, stream); + fprintf (file, "namespace "); + pph_dump_tree_name (file, ns, 0); + fprintf (file, "{\n"); + pph_dump_binding (file, NAMESPACE_LEVEL (ns)); + fprintf (file, "}\n"); } -/* Create a new PPH stream to be stored on the file called NAME. - MODE is passed to fopen directly. */ +/* Dump a CHAIN for PPH. */ -pph_stream * -pph_stream_open (const char *name, const char *mode) +static void +pph_dump_chain (FILE *file, tree chain) { - pph_stream *stream; - FILE *f; - - /* If we have already opened a PPH stream named NAME, just return - its associated stream. */ - stream = pph_find_stream_for (name); - if (stream) + tree t, next; + for (t = chain; t; t = next) { - gcc_assert (stream->in_memory_p); - return stream; + next = DECL_CHAIN (t); + if (!DECL_IS_BUILTIN (t)) + pph_dump_tree_name (file, t, 0); } - - f = fopen (name, mode); - if (!f) - return NULL; - - stream = XCNEW (pph_stream); - stream->file = f; - stream->name = xstrdup (name); - stream->write_p = (strchr (mode, 'w') != NULL); - pph_cache_init (&stream->cache); - stream->preloaded_cache = pph_preloaded_cache; - if (stream->write_p) - pph_init_write (stream); - else - pph_init_read (stream); - - return stream; } - -/* Close PPH stream STREAM. */ +/* Dump cp_binding_level LEVEL for PPH. */ void -pph_stream_close (pph_stream *stream) +pph_dump_binding (FILE *file, cp_binding_level *level) { - /* STREAM can be NULL if it could not be properly opened. An error - has already been emitted, so avoid crashing here. */ - if (stream == NULL) - return; - - if (flag_pph_tracer >= 1) - fprintf (pph_logfile, "PPH: Closing %s\n", stream->name); - - /* If we were writing to STREAM, flush all the memory buffers. This - does the actual writing of all the pickled data structures. */ - if (stream->write_p) - pph_flush_buffers (stream); - - fclose (stream->file); - - /* Deallocate all memory used. */ - stream->file = NULL; - VEC_free (pph_cache_entry, heap, stream->cache.v); - pointer_map_destroy (stream->cache.m); - VEC_free (pph_symtab_entry, heap, stream->symtab.v); - VEC_free (pph_stream_ptr, heap, stream->includes); - - if (stream->write_p) - { - destroy_output_block (stream->encoder.w.ob); - free (stream->encoder.w.decl_state_stream); - lto_delete_out_decl_state (stream->encoder.w.out_state); - } - else + tree t, next; + pph_dump_chain (file, level->names); + for (t = level->namespaces; t; t = next) { - unsigned i; - - free (stream->encoder.r.ib); - lto_data_in_delete (stream->encoder.r.data_in); - for (i = 0; i < PPH_NUM_SECTIONS; i++) - free (stream->encoder.r.pph_sections[i]); - free (stream->encoder.r.pph_sections); - free (stream->encoder.r.file_data); + next = DECL_CHAIN (t); + if (!DECL_IS_BUILTIN (t)) + pph_dump_namespace (file, t); } - - free (stream); -} - - -/* Add INCLUDE, and the images included by it, to the list of files - included by STREAM. */ - -void -pph_add_include (pph_stream *stream, pph_stream *include) -{ - pph_stream *include_child; - unsigned i; - - include->parent = stream; - VEC_safe_push (pph_stream_ptr, heap, stream->includes, include); - FOR_EACH_VEC_ELT (pph_stream_ptr, include->includes, i, include_child) - VEC_safe_push (pph_stream_ptr, heap, stream->includes, include_child); } @@ -367,6 +180,10 @@ static const char *tag_strings[] = "PPH_sorted_fields_type" }; + +/* Trace print a MARKER and TAG. */ + + void pph_trace_marker (enum pph_record_marker marker, enum pph_tag tag) { @@ -456,6 +273,84 @@ pph_trace_tree (tree t, enum pph_trace_e } +/************************************************* pph pointer mapping cache */ + + +/* Initialize an empty pickle CACHE. */ + +static void +pph_cache_init (pph_cache *cache) +{ + cache->v = NULL; + cache->m = pointer_map_create (); +} + + +/* A cache of pre-loaded common tree nodes. */ +static pph_cache *pph_preloaded_cache; + + +/* Pre-load common tree nodes into CACHE. These nodes are always built by the + front end, so there is no need to pickle them. */ + +static void +pph_cache_preload (pph_cache *cache) +{ + unsigned i; + + for (i = itk_char; i < itk_none; i++) + pph_cache_add (cache, integer_types[i], NULL, + pph_tree_code_to_tag (integer_types[i])); + + for (i = 0; i < TYPE_KIND_LAST; i++) + pph_cache_add (cache, sizetype_tab[i], NULL, + pph_tree_code_to_tag (sizetype_tab[i])); + + /* global_trees[] can have NULL entries in it. Skip them. */ + for (i = 0; i < TI_MAX; i++) + if (global_trees[i]) + pph_cache_add (cache, global_trees[i], NULL, + pph_tree_code_to_tag (global_trees[i])); + + /* c_global_trees[] can have NULL entries in it. Skip them. */ + for (i = 0; i < CTI_MAX; i++) + if (c_global_trees[i]) + pph_cache_add (cache, c_global_trees[i], NULL, + pph_tree_code_to_tag (c_global_trees[i])); + + /* cp_global_trees[] can have NULL entries in it. Skip them. */ + for (i = 0; i < CPTI_MAX; i++) + { + /* Also skip trees which are generated while parsing. */ + if (i == CPTI_KEYED_CLASSES) + continue; + + if (cp_global_trees[i]) + pph_cache_add (cache, cp_global_trees[i], NULL, + pph_tree_code_to_tag (cp_global_trees[i])); + } + + /* Add other well-known nodes that should always be taken from the + current compilation context. */ + pph_cache_add (cache, global_namespace, NULL, + pph_tree_code_to_tag (global_namespace)); + pph_cache_add (cache, DECL_CONTEXT (global_namespace), NULL, + pph_tree_code_to_tag (DECL_CONTEXT (global_namespace))); +} + + +/* Initialize the pre-loaded cache. This contains all the common + tree nodes built by the compiler on startup. */ + +static void +pph_init_preloaded_cache (void) +{ + pph_preloaded_cache = XCNEW (pph_cache); + pph_cache_init (pph_preloaded_cache); + pph_cache_preload (pph_preloaded_cache); +} + + /* Insert DATA in CACHE at slot IX. TAG represents the data structure pointed-to by DATA. As a restriction to prevent stomping on cache entries, this will not allow inserting into the same slot more than @@ -485,6 +380,30 @@ pph_cache_insert_at (pph_cache *cache, v } +/* Add pointer DATA with data type TAG to CACHE. If IX_P is not NULL, + on exit *IX_P will contain the slot number where DATA is stored. + Return the newly added entry. */ + +pph_cache_entry * +pph_cache_add (pph_cache *cache, void *data, unsigned *ix_p, enum pph_tag tag) +{ + unsigned ix; + pph_cache_entry *e; + + e = pph_cache_lookup (cache, data, &ix, tag); + if (e == NULL) + { + ix = VEC_length (pph_cache_entry, cache->v); + e = pph_cache_insert_at (cache, data, ix, tag); + } + + if (ix_p) + *ix_p = ix; + + return e; +} + + /* If DATA exists in CACHE, return the cache entry holding it. If IX_P is not NULL, store the cache slot where DATA resides in *IX_P (or (unsigned)-1 if DATA is not found). If CACHE is NULL use @@ -591,28 +510,7 @@ pph_cache_lookup_in_includes (pph_stream } -/* Add pointer DATA with data type TAG to CACHE. If IX_P is not NULL, - on exit *IX_P will contain the slot number where DATA is stored. - Return the newly added entry. */ - -pph_cache_entry * -pph_cache_add (pph_cache *cache, void *data, unsigned *ix_p, enum pph_tag tag) -{ - unsigned ix; - pph_cache_entry *e; - - e = pph_cache_lookup (cache, data, &ix, tag); - if (e == NULL) - { - ix = VEC_length (pph_cache_entry, cache->v); - e = pph_cache_insert_at (cache, data, ix, tag); - } - - if (ix_p) - *ix_p = ix; - - return e; -} +/*************************************************** tree contents signature */ /* Associate signature CRC with the first NBYTES of the area memory @@ -672,3 +570,511 @@ pph_get_signature (tree t, size_t *nbyte return crc; } + + +/****************************************************** pph include handling */ + + +/* Return true if PPH image NAME can be used at the point of inclusion + (given by LOC). */ + +static bool +pph_is_valid_here (const char *name, location_t loc) +{ + /* If we are inside a scope, reject the image. We could be inside a + namespace or a structure which changes the parsing context for + the original text file. */ + if (scope_chain->x_brace_nesting > 0) + { + error_at (loc, "PPH file %s not included at global scope", name); + return false; + } + + return true; +} + + +/* Record a #include or #include_next for PPH. + READER is the main pre-processor object, LOC is the location where + the #include is being emitted from, DNAME is the name of the + #include directive used, NAME is the canonical name of the file being + included, ANGLE_BRACKETS is non-zero if this #include uses <> and + TOK_P is a pointer to the current token being pre-processed. */ + +static bool +pph_include_handler (cpp_reader *reader, + location_t loc, + const unsigned char *dname, + const char *name, + int angle_brackets, + const cpp_token **tok_p ATTRIBUTE_UNUSED) +{ + const char *pph_file; + bool read_text_file_p; + + if (flag_pph_tracer >= 1) + { + fprintf (pph_logfile, "PPH: #%s", dname); + fprintf (pph_logfile, " %c", angle_brackets ? '<' : '"'); + fprintf (pph_logfile, "%s", name); + fprintf (pph_logfile, "%c\n", angle_brackets ? '>' : '"'); + } + + read_text_file_p = true; + pph_file = query_pph_include_map (name); + if (pph_file != NULL + && pph_is_valid_here (name, loc) + && !cpp_included_before (reader, name, input_location)) + { + pph_stream *include; + + /* Hack. We do this to mimic what the non-pph compiler does in + _cpp_stack_include as our goal is to have identical line_tables. */ + line_table->highest_location--; + + include = pph_read_file (pph_file); + + /* If we are generating a new PPH image, add the stream we just + read to the list of includes. This way, the parser will be + able to resolve references to symbols in INCLUDE and its + children. */ + if (pph_writer_enabled_p ()) + pph_writer_add_include (include); + + read_text_file_p = false; + } + + return read_text_file_p; +} + + +/* PPH include tree dumper. Each entry in this file has the format: + + DEPTH|SYSP|DNAME|CANONICAL-NAME|FULL-NAME|PPH-NAME + + Where: + DEPTH is the include depth of the file. + SYSP 1 for a system header + 2 for a C system header that needs 'extern "C"' + 0 otherwise. + DNAME name of the #include directive used. + CANONICAL-NAME is the name of the file as specified by the + #include directive. + FULL-NAME is the full path name where the included file + was found by the pre-processor. + PPH-NAME is the name of the associated PPH file. */ + +typedef struct { + /* Name of current #include directive. */ + const unsigned char *dname; + + /* Canonical name of file being included. */ + const char *name; + + /* Previous libcpp #include handler. */ + void (*prev_file_change) (cpp_reader *, const struct line_map *); + + /* Previous libcpp file change handler. */ + bool (*prev_include) (cpp_reader *, source_location, const unsigned char *, + const char *, int, const cpp_token **); +} pph_include_tree_dumper; + +static pph_include_tree_dumper tree_dumper; + + +/* #include handler for libcpp. READER is the main pre-processor object, + LOC is the location where the #include is being emitted from, DNAME + is the name of the #include directive used, NAME is the canonical + name of the file being included, ANGLE_BRACKETS is non-zero if this + #include uses <> and TOK_P is a pointer to the current token being + pre-processed. */ + +static bool +pph_include_handler_for_map (cpp_reader *reader, + location_t loc, + const unsigned char *dname, + const char *name, + int angle_brackets, + const cpp_token **tok_p) +{ + bool retval = true; + + if (tree_dumper.prev_include) + retval &= tree_dumper.prev_include (reader, loc, dname, name, + angle_brackets, tok_p); + tree_dumper.dname = dname; + tree_dumper.name = name; + + return retval; +} + + +/* Return a copy of NAME with the characters '/' and '.' replaced with + '_'. The caller is reponsible for freeing the returned string. */ + +static char * +pph_flatten_name (const char *name) +{ + char *str = xstrdup (name); + size_t i; + + for (i = 0; i < strlen (str); i++) + if (str[i] == DIR_SEPARATOR || str[i] == '.') + str[i] = '_'; + + return str; +} + + +/* File change handler for libcpp. READER is the main pre-processor object, + MAP is the line map entry for the file that we are entering into. */ + +static void +pph_file_change_handler (cpp_reader *reader, const struct line_map *map) +{ + char *flat; + + if (tree_dumper.prev_file_change) + tree_dumper.prev_file_change (reader, map); + + /* We are only interested in line maps that describe a new file being + entered. */ + if (map == NULL || map->reason != LC_ENTER) + return; + + /* Emit a line to the map file with the format: + + DEPTH|SYSP|DNAME|CANONICAL-NAME|FULL-NAME|PPH-NAME + */ + flat = pph_flatten_name (map->d.ordinary.to_file); + fprintf (stderr, "%d|%d|%s|%s|%s|%s.pph\n", line_table->depth, + map->d.ordinary.sysp, tree_dumper.dname, tree_dumper.name, + map->d.ordinary.to_file, flat); + free (flat); + tree_dumper.dname = NULL; + tree_dumper.name = NULL; +} + + +/* Initialize the #include tree dumper. */ + +void +pph_init_include_tree (void) +{ + cpp_callbacks *cb; + + memset (&tree_dumper, 0, sizeof (tree_dumper)); + + if (pph_enabled_p ()) + fatal_error ("do not use -fpph-map-gen with any other PPH flag"); + + /* Set up the libcpp handler for file change events. Each event + will generate a new entry in the map file. */ + cb = cpp_get_callbacks (parse_in); + + tree_dumper.prev_file_change = cb->file_change; + cb->file_change = pph_file_change_handler; + + tree_dumper.prev_include = cb->include; + cb->include = pph_include_handler_for_map; +} + + +/* Add INCLUDE, and the images included by it, to the list of files + included by STREAM. */ + +void +pph_add_include (pph_stream *stream, pph_stream *include) +{ + pph_stream *include_child; + unsigned i; + + include->parent = stream; + VEC_safe_push (pph_stream_ptr, heap, stream->includes, include); + FOR_EACH_VEC_ELT (pph_stream_ptr, include->includes, i, include_child) + VEC_safe_push (pph_stream_ptr, heap, stream->includes, include_child); +} + + +/*********************************************************** stream handling */ + + +/* List of PPH images opened for reading. Images opened during #include + processing and opened from pph_in_includes cannot be closed + immediately after reading, because the pickle cache contained in + them may be referenced from other images. We delay closing all of + them until the end of parsing (when pph_streamer_finish is called). */ +static VEC(pph_stream_ptr, heap) *pph_read_images = NULL; + + +/* If FILENAME has already been read, return the stream associated with it. */ + +static pph_stream * +pph_find_stream_for (const char *filename) +{ + pph_stream *include; + unsigned i; + + /* FIXME pph, implement a hash map to avoid this linear search. */ + FOR_EACH_VEC_ELT (pph_stream_ptr, pph_read_images, i, include) + if (strcmp (include->name, filename) == 0) + return include; + + return NULL; +} + + +/* Add STREAM to the list of read images. */ + +void +pph_mark_stream_read (pph_stream *stream) +{ + stream->in_memory_p = true; + VEC_safe_push (pph_stream_ptr, heap, pph_read_images, stream); +} + + +/* Create a new PPH stream to be stored on the file called NAME. + MODE is passed to fopen directly. */ + +pph_stream * +pph_stream_open (const char *name, const char *mode) +{ + pph_stream *stream; + FILE *f; + + /* If we have already opened a PPH stream named NAME, just return + its associated stream. */ + stream = pph_find_stream_for (name); + if (stream) + { + gcc_assert (stream->in_memory_p); + return stream; + } + + f = fopen (name, mode); + if (!f) + return NULL; + + stream = XCNEW (pph_stream); + stream->file = f; + stream->name = xstrdup (name); + stream->write_p = (strchr (mode, 'w') != NULL); + pph_cache_init (&stream->cache); + stream->preloaded_cache = pph_preloaded_cache; + if (stream->write_p) + pph_init_write (stream); + else + pph_init_read (stream); + + return stream; +} + + +/* Close PPH stream STREAM. */ + +void +pph_stream_close (pph_stream *stream) +{ + /* STREAM can be NULL if it could not be properly opened. An error + has already been emitted, so avoid crashing here. */ + if (stream == NULL) + return; + + if (flag_pph_tracer >= 1) + fprintf (pph_logfile, "PPH: Closing %s\n", stream->name); + + /* If we were writing to STREAM, flush all the memory buffers. This + does the actual writing of all the pickled data structures. */ + if (stream->write_p) + pph_flush_buffers (stream); + + fclose (stream->file); + + /* Deallocate all memory used. */ + stream->file = NULL; + VEC_free (pph_cache_entry, heap, stream->cache.v); + pointer_map_destroy (stream->cache.m); + VEC_free (pph_symtab_entry, heap, stream->symtab.v); + VEC_free (pph_stream_ptr, heap, stream->includes); + + if (stream->write_p) + { + destroy_output_block (stream->encoder.w.ob); + free (stream->encoder.w.decl_state_stream); + lto_delete_out_decl_state (stream->encoder.w.out_state); + } + else + { + unsigned i; + + free (stream->encoder.r.ib); + lto_data_in_delete (stream->encoder.r.data_in); + for (i = 0; i < PPH_NUM_SECTIONS; i++) + free (stream->encoder.r.pph_sections[i]); + free (stream->encoder.r.pph_sections); + free (stream->encoder.r.file_data); + } + + free (stream); +} + + +/********************************************************** stream callbacks */ + + +/* Callback for writing ASTs to a stream. Write EXPR to the PPH stream + in OB. */ + +static void +pph_write_tree (struct output_block *ob, tree expr, bool ref_p ATTRIBUTE_UNUSED) +{ + pph_out_tree ((pph_stream *) ob->sdata, expr); +} + + +/* Callback for reading ASTs from a stream. Instantiate and return a + new tree from the PPH stream in DATA_IN. */ + +static tree +pph_read_tree (struct lto_input_block *ib ATTRIBUTE_UNUSED, + struct data_in *data_in) +{ + return pph_in_tree ((pph_stream *) data_in->sdata); +} + + +/* Callback for streamer_hooks.input_location. An offset is applied to + the location_t read in according to the properties of the merged + line_table. IB and DATA_IN are as in lto_input_location. This function + should only be called after pph_in_and_merge_line_table was called as + we expect pph_loc_offset to be set. */ + +static location_t +pph_input_location (struct lto_input_block *ib ATTRIBUTE_UNUSED, + struct data_in *data_in) +{ + return pph_in_location ((pph_stream *) data_in->sdata); +} + + +/* Callback for streamer_hooks.output_location. Output the LOC directly, + an offset will be applied on input after rebuilding the line_table. + OB and LOC are as in lto_output_location. */ + +static void +pph_output_location (struct output_block *ob, location_t loc) +{ + pph_out_location ((pph_stream *) ob->sdata, loc); +} + + +/******************************************************** pph initialization */ + + +/* Initialize all the streamer hooks used for streaming ASTs. */ + +static void +pph_hooks_init (void) +{ + streamer_hooks_init (); + streamer_hooks.write_tree = pph_write_tree; + streamer_hooks.read_tree = pph_read_tree; + streamer_hooks.input_location = pph_input_location; + streamer_hooks.output_location = pph_output_location; +} + + +/* Initialize the streamer. */ + +static void +pph_streamer_init (void) +{ + pph_hooks_init (); + pph_init_preloaded_cache (); +} + + +/* The initial order of the size of the lexical lookaside table, + which will accomodate as many as half of its slots in use. */ + +static const unsigned int cpp_lt_order = /* 2 to the power of */ 9; + +/* Initialize PPH support. */ + +void +pph_init (void) +{ + cpp_callbacks *cb; + cpp_lookaside *table; + + if (flag_pph_logfile) + { + pph_logfile = fopen (flag_pph_logfile, "w"); + if (!pph_logfile) + fatal_error ("Cannot create %s for writing: %m", flag_pph_logfile); + } + else + pph_logfile = stdout; + + if (flag_pph_tracer >= 1) + fprintf (pph_logfile, "PPH: Initializing.\n"); + + /* Set up the libcpp handler for #include. */ + cb = cpp_get_callbacks (parse_in); + cb->include = pph_include_handler; + + table = cpp_lt_exchange (parse_in, + cpp_lt_create (cpp_lt_order, flag_pph_debug/2)); + gcc_assert (table == NULL); + + pph_streamer_init (); + + /* If we are generating a PPH file, initialize the writer. */ + if (pph_writer_enabled_p ()) + pph_writer_init (); + + pph_reader_init (); +} + + +/********************************************************** pph finalization */ + + +/* Finalize the streamer. */ + +static void +pph_streamer_finish (void) +{ + unsigned i; + pph_stream *image; + + /* Finalize the writer. */ + pph_writer_finish (); + + /* Finalize the reader. */ + pph_reader_finish (); + + /* Close any images read during parsing. */ + FOR_EACH_VEC_ELT (pph_stream_ptr, pph_read_images, i, image) + pph_stream_close (image); + + VEC_free (pph_stream_ptr, heap, pph_read_images); +} + + +/* Finalize PPH support. */ + +void +pph_finish (void) +{ + /* Finalize the streamer. */ + pph_streamer_finish (); + + /* Close log files. */ + if (flag_pph_tracer >= 1) + fprintf (pph_logfile, "PPH: Finishing.\n"); + + if (flag_pph_logfile) + fclose (pph_logfile); +} Index: gcc/cp/Make-lang.in =================================================================== --- gcc/cp/Make-lang.in (revision 181815) +++ gcc/cp/Make-lang.in (working copy) @@ -82,8 +82,8 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl. cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \ cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \ cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \ - cp/cp-gimplify.o cp/pph.o cp/pph-streamer.o cp/pph-streamer-out.o \ - cp/pph-streamer-in.o tree-mudflap.o $(CXX_C_OBJS) + cp/cp-gimplify.o cp/pph-core.o cp/pph-out.o cp/pph-in.o \ + tree-mudflap.o $(CXX_C_OBJS) # Language-specific object files for C++. CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS) @@ -265,8 +265,10 @@ CXX_TREE_H = $(TREE_H) cp/name-lookup.h CXX_PARSER_H = tree.h c-family/c-pragma.h cp/parser.h CXX_PRETTY_PRINT_H = cp/cxx-pretty-print.h $(C_PRETTY_PRINT_H) CXX_PPH_H = $(CXX_TREE_H) cp/pph.h -CXX_PPH_STREAMER_H = $(LTO_STREAMER_H) $(DATA_STREAMER_H) $(TREE_STREAMER_H) \ - $(TREE_H) $(CXX_PPH_H) cp/pph-streamer.h +CXX_PPH_STREAMER_H = $(CXX_PPH_H) $(DATA_STREAMER_H) $(TREE_STREAMER_H) \ + cp/pph-streamer.h +CXX_PPH_COMMON_H = $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CXX_PPH_STREAMER_H) \ + $(TREE_PASS_H) tree-iterator.h version.h cppbuiltin.h $(CXX_PARSER_H) cp/lex.o: cp/lex.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \ $(C_PRAGMA_H) output.h input.h cp/operators.def $(TM_P_H) \ @@ -349,19 +351,8 @@ cp/name-lookup.o: cp/name-lookup.c $(CON $(CXX_PPH_H) pointer-set.h cp/cxx-pretty-print.o: cp/cxx-pretty-print.c $(CXX_PRETTY_PRINT_H) \ $(CONFIG_H) $(SYSTEM_H) $(TM_H) coretypes.h $(CXX_TREE_H) tree-pretty-print.h -cp/pph.o: cp/pph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) \ - toplev.h $(TREE_H) $(CXX_TREE_H) $(TIMEVAR_H) pointer-set.h \ - fixed-value.h $(TREE_PASS_H) $(TREE_INLINE_H) tree-pretty-print.h \ - $(CXX_PARSER_H) $(CXX_PPH_H) $(CXX_PPH_STREAMER_H) -cp/pph-streamer.o: cp/pph-streamer.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 \ - $(STREAMER_HOOKS_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 \ - $(CXX_PARSER_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 \ - $(CXX_PARSER_H) cppbuiltin.h tree-iterator.h toplev.h +cp/pph-core.o: cp/pph-core.c $(CXX_PPH_COMMON_H) $(CPPLIB_H) $(TIMEVAR_H) \ + $(TREE_INLINE_H) tree-pretty-print.h fixed-value.h pointer-set.h \ + toplev.h +cp/pph-out.o: cp/pph-out.c $(CXX_PPH_COMMON_H) $(CGRAPH_H) +cp/pph-in.o: cp/pph-in.c $(CXX_PPH_COMMON_H) pointer-set.h toplev.h Index: gcc/cp/pph.c =================================================================== --- gcc/cp/pph.c (revision 181815) +++ gcc/cp/pph.c (working copy) @@ -1,403 +0,0 @@ -/* Factored pre-parsed header (PPH) support for C++ - Copyright (C) 2010, 2011 Free Software Foundation, Inc. - Contributed by Lawrence Crowl and - Diego Novillo . - - This file is part of GCC. - - GCC is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - GCC is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "pph.h" -#include "cpplib.h" -#include "toplev.h" -#include "tree.h" -#include "cp-tree.h" -#include "timevar.h" -#include "pointer-set.h" -#include "fixed-value.h" -#include "md5.h" -#include "tree-pass.h" -#include "tree-dump.h" -#include "tree-inline.h" -#include "tree-pretty-print.h" -#include "cxx-pretty-print.h" -#include "parser.h" -#include "pph-streamer.h" - -/* Log file where PPH analysis is written to. Controlled by - -fpph_logfile. If this flag is not given, stdout is used. */ -FILE *pph_logfile = NULL; - -/* Convert a checked tree_code CODE to a string. */ - -const char * -pph_tree_code_text (enum tree_code code) -{ - gcc_assert (code < MAX_TREE_CODES); - return tree_code_name[code]; -} - - -/* Dump a location LOC to FILE. */ - -void -pph_dump_location (FILE *file, location_t loc) -{ - expanded_location xloc = expand_location (loc); - fprintf (file, "%s:%d", xloc.file, xloc.line); -} - -/* Dump identifying information for a minimal DECL to FILE. */ - -void -pph_dump_min_decl (FILE *file, tree decl) -{ - print_generic_expr (file, DECL_NAME (decl), 0); - print_generic_expr (file, DECL_CONTEXT (decl), 0); - pph_dump_location (file, DECL_SOURCE_LOCATION (decl)); -} - -/* Dump a complicated name for tree T to FILE using FLAGS. - See TDF_* in tree-pass.h for flags. */ - -void -pph_dump_tree_name (FILE *file, tree t, int flags) -{ - enum tree_code code = TREE_CODE (t); - const char *text = pph_tree_code_text (code); - if (DECL_P (t)) - fprintf (file, "%s %s\n", text, decl_as_string (t, flags)); - else if (TYPE_P (t)) - fprintf (file, "%s %s\n", text, type_as_string (t, flags)); - else if (EXPR_P (t)) - fprintf (file, "%s %s\n", text, expr_as_string (t, flags)); - else - { - fprintf (file, "%s ", text ); - print_generic_expr (file, t, flags); - fprintf (file, "\n"); - } -} - - -/* Dump namespace NS for PPH. */ - -void -pph_dump_namespace (FILE *file, tree ns) -{ - fprintf (file, "namespace "); - pph_dump_tree_name (file, ns, 0); - fprintf (file, "{\n"); - pph_dump_binding (file, NAMESPACE_LEVEL (ns)); - fprintf (file, "}\n"); -} - - -/* Dump cp_binding_level LEVEL for PPH. */ - -void -pph_dump_binding (FILE *file, cp_binding_level *level) -{ - tree t, next; - pph_dump_chain (file, level->names); - for (t = level->namespaces; t; t = next) - { - next = DECL_CHAIN (t); - if (!DECL_IS_BUILTIN (t)) - pph_dump_namespace (file, t); - } -} - - -/* Dump a CHAIN for PPH. */ - -void -pph_dump_chain (FILE *file, tree chain) -{ - tree t, next; - for (t = chain; t; t = next) - { - next = DECL_CHAIN (t); - if (!DECL_IS_BUILTIN (t)) - pph_dump_tree_name (file, t, 0); - } -} - - -/* Return true if PPH image NAME can be used at the point of inclusion - (given by LOC). */ - -static bool -pph_is_valid_here (const char *name, location_t loc) -{ - /* If we are inside a scope, reject the image. We could be inside a - namespace or a structure which changes the parsing context for - the original text file. */ - if (scope_chain->x_brace_nesting > 0) - { - error_at (loc, "PPH file %s not included at global scope", name); - return false; - } - - return true; -} - - -/* Record a #include or #include_next for PPH. - READER is the main pre-processor object, LOC is the location where - the #include is being emitted from, DNAME is the name of the - #include directive used, NAME is the canonical name of the file being - included, ANGLE_BRACKETS is non-zero if this #include uses <> and - TOK_P is a pointer to the current token being pre-processed. */ - -static bool -pph_include_handler (cpp_reader *reader, - location_t loc, - const unsigned char *dname, - const char *name, - int angle_brackets, - const cpp_token **tok_p ATTRIBUTE_UNUSED) -{ - const char *pph_file; - bool read_text_file_p; - - if (flag_pph_tracer >= 1) - { - fprintf (pph_logfile, "PPH: #%s", dname); - fprintf (pph_logfile, " %c", angle_brackets ? '<' : '"'); - fprintf (pph_logfile, "%s", name); - fprintf (pph_logfile, "%c\n", angle_brackets ? '>' : '"'); - } - - read_text_file_p = true; - pph_file = query_pph_include_map (name); - if (pph_file != NULL - && pph_is_valid_here (name, loc) - && !cpp_included_before (reader, name, input_location)) - { - pph_stream *include; - - /* Hack. We do this to mimic what the non-pph compiler does in - _cpp_stack_include as our goal is to have identical line_tables. */ - line_table->highest_location--; - - include = pph_read_file (pph_file); - - /* If we are generating a new PPH image, add the stream we just - read to the list of includes. This way, the parser will be - able to resolve references to symbols in INCLUDE and its - children. */ - if (pph_writer_enabled_p ()) - pph_writer_add_include (include); - - read_text_file_p = false; - } - - return read_text_file_p; -} - - -/* The initial order of the size of the lexical lookaside table, - which will accomodate as many as half of its slots in use. */ - -static const unsigned int cpp_lt_order = /* 2 to the power of */ 9; - -/* Initialize PPH support. */ - -void -pph_init (void) -{ - cpp_callbacks *cb; - cpp_lookaside *table; - - if (flag_pph_logfile) - { - pph_logfile = fopen (flag_pph_logfile, "w"); - if (!pph_logfile) - fatal_error ("Cannot create %s for writing: %m", flag_pph_logfile); - } - else - pph_logfile = stdout; - - if (flag_pph_tracer >= 1) - fprintf (pph_logfile, "PPH: Initializing.\n"); - - /* Set up the libcpp handler for #include. */ - cb = cpp_get_callbacks (parse_in); - cb->include = pph_include_handler; - - table = cpp_lt_exchange (parse_in, - cpp_lt_create (cpp_lt_order, flag_pph_debug/2)); - gcc_assert (table == NULL); - - pph_streamer_init (); - - /* If we are generating a PPH file, initialize the writer. */ - if (pph_writer_enabled_p ()) - pph_writer_init (); - - pph_reader_init (); -} - - -/* Finalize PPH support. */ - -void -pph_finish (void) -{ - /* Finalize the streamer. */ - pph_streamer_finish (); - - /* Close log files. */ - if (flag_pph_tracer >= 1) - fprintf (pph_logfile, "PPH: Finishing.\n"); - - if (flag_pph_logfile) - fclose (pph_logfile); -} - - -/* PPH include tree dumper. Each entry in this file has the format: - - DEPTH|SYSP|DNAME|CANONICAL-NAME|FULL-NAME|PPH-NAME - - Where: - DEPTH is the include depth of the file. - SYSP 1 for a system header - 2 for a C system header that needs 'extern "C"' - 0 otherwise. - DNAME name of the #include directive used. - CANONICAL-NAME is the name of the file as specified by the - #include directive. - FULL-NAME is the full path name where the included file - was found by the pre-processor. - PPH-NAME is the name of the associated PPH file. */ -typedef struct { - /* Name of current #include directive. */ - const unsigned char *dname; - - /* Canonical name of file being included. */ - const char *name; - - /* Previous libcpp #include handler. */ - void (*prev_file_change) (cpp_reader *, const struct line_map *); - - /* Previous libcpp file change handler. */ - bool (*prev_include) (cpp_reader *, source_location, const unsigned char *, - const char *, int, const cpp_token **); -} pph_include_tree_dumper; - -static pph_include_tree_dumper tree_dumper; - - -/* Return a copy of NAME with the characters '/' and '.' replaced with - '_'. The caller is reponsible for freeing the returned string. */ - -static char * -flatten_name (const char *name) -{ - char *str = xstrdup (name); - size_t i; - - for (i = 0; i < strlen (str); i++) - if (str[i] == DIR_SEPARATOR || str[i] == '.') - str[i] = '_'; - - return str; -} - - -/* File change handler for libcpp. READER is the main pre-processor object, - MAP is the line map entry for the file that we are entering into. */ - -static void -pph_file_change_handler (cpp_reader *reader, const struct line_map *map) -{ - char *flat; - - if (tree_dumper.prev_file_change) - tree_dumper.prev_file_change (reader, map); - - /* We are only interested in line maps that describe a new file being - entered. */ - if (map == NULL || map->reason != LC_ENTER) - return; - - /* Emit a line to the map file with the format: - - DEPTH|SYSP|DNAME|CANONICAL-NAME|FULL-NAME|PPH-NAME - */ - flat = flatten_name (map->d.ordinary.to_file); - fprintf (stderr, "%d|%d|%s|%s|%s|%s.pph\n", line_table->depth, - map->d.ordinary.sysp, tree_dumper.dname, tree_dumper.name, - map->d.ordinary.to_file, flat); - free (flat); - tree_dumper.dname = NULL; - tree_dumper.name = NULL; -} - - -/* #include handler for libcpp. READER is the main pre-processor object, - LOC is the location where the #include is being emitted from, DNAME - is the name of the #include directive used, NAME is the canonical - name of the file being included, ANGLE_BRACKETS is non-zero if this - #include uses <> and TOK_P is a pointer to the current token being - pre-processed. */ - -static bool -pph_include_handler_for_map (cpp_reader *reader, - location_t loc, - const unsigned char *dname, - const char *name, - int angle_brackets, - const cpp_token **tok_p) -{ - bool retval = true; - - if (tree_dumper.prev_include) - retval &= tree_dumper.prev_include (reader, loc, dname, name, - angle_brackets, tok_p); - tree_dumper.dname = dname; - tree_dumper.name = name; - - return retval; -} - - -/* Initialize the #include tree dumper. */ - -void -pph_init_include_tree (void) -{ - cpp_callbacks *cb; - - memset (&tree_dumper, 0, sizeof (tree_dumper)); - - if (pph_enabled_p ()) - fatal_error ("do not use -fpph-map-gen with any other PPH flag"); - - /* Set up the libcpp handler for file change events. Each event - will generate a new entry in the map file. */ - cb = cpp_get_callbacks (parse_in); - - tree_dumper.prev_file_change = cb->file_change; - cb->file_change = pph_file_change_handler; - - tree_dumper.prev_include = cb->include; - cb->include = pph_include_handler_for_map; -} Index: gcc/cp/pph.h =================================================================== --- gcc/cp/pph.h (revision 181815) +++ gcc/cp/pph.h (working copy) @@ -137,14 +137,14 @@ extern FILE *pph_logfile; /* Extern functions. */ -/* In pph.c */ +/* In pph-core.c */ extern void pph_init (void); extern void pph_finish (void); extern void pph_dump_location (FILE *file, location_t loc); extern void pph_dump_tree_name (FILE *file, tree t, int flags); extern void pph_init_include_tree (void); -/* In pph-streamer-out.c. */ +/* In pph-out.c. */ extern void pph_out_uint (pph_stream *stream, unsigned int value); extern void pph_out_location (pph_stream *stream, location_t loc); extern void pph_out_tree (pph_stream *stream, tree t); @@ -152,7 +152,7 @@ extern void pph_out_record_marker (pph_s enum pph_record_marker marker, enum pph_tag tag); void pph_add_decl_to_symtab (tree, enum pph_symtab_action, bool, bool); -/* In pph-streamer-in.c. */ +/* In pph-in.c. */ extern unsigned int pph_in_uint (pph_stream *stream); extern location_t pph_in_location (pph_stream *stream); extern tree pph_in_tree (pph_stream *stream); Index: gcc/cp/pph-streamer-in.c =================================================================== --- gcc/cp/pph-streamer-in.c (revision 181815) +++ gcc/cp/pph-streamer-in.c (working copy) @@ -1,2728 +0,0 @@ -/* Routines for reading PPH data. - Copyright (C) 2011 Free Software Foundation, Inc. - Contributed by Diego Novillo . - - This file is part of GCC. - - GCC is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - GCC is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "pph.h" -#include "tree.h" -#include "langhooks.h" -#include "tree-iterator.h" -#include "tree-pretty-print.h" -#include "lto-streamer.h" -#include "pph-streamer.h" -#include "tree-pass.h" -#include "version.h" -#include "cppbuiltin.h" -#include "toplev.h" -#include "parser.h" -#include "pointer-set.h" - - -/********************************************************* type declarations */ - - -typedef char *char_p; -DEF_VEC_P(char_p); -DEF_VEC_ALLOC_P(char_p,heap); - - -/****************************************************** forward declarations */ - - -/* Forward declarations to avoid circularity. */ -static tree pph_in_merge_key_tree (pph_stream *, tree *); - - -/***************************************************** stream initialization */ - - -/* String tables for all input streams. These are allocated separately - from streams because they cannot be deallocated after the streams - have been read (string streaming works by pointing into these - tables). - - Each stream will create a new entry in this table of tables. The - memory will remain allocated until the end of compilation. */ -static VEC(char_p,heap) *string_tables = NULL; - - -/* Read into memory the contents of the file in STREAM. Initialize - internal tables and data structures needed to re-construct the - ASTs in the file. */ - -void -pph_init_read (pph_stream *stream) -{ - struct stat st; - size_t i, bytes_read, strtab_size, body_size; - int retcode; - pph_file_header *header; - const char *strtab, *body; - char *new_strtab; - - /* Read STREAM->NAME into the memory buffer stream->encoder.r.file_data. */ - retcode = fstat (fileno (stream->file), &st); - gcc_assert (retcode == 0); - stream->encoder.r.file_size = (size_t) st.st_size; - stream->encoder.r.file_data = XCNEWVEC (char, stream->encoder.r.file_size); - bytes_read = fread (stream->encoder.r.file_data, 1, - stream->encoder.r.file_size, stream->file); - gcc_assert (bytes_read == stream->encoder.r.file_size); - - /* Set up the file sections, header, body and string table for the - low-level streaming routines. */ - stream->encoder.r.pph_sections = XCNEWVEC (struct lto_file_decl_data *, - PPH_NUM_SECTIONS); - for (i = 0; i < PPH_NUM_SECTIONS; i++) - stream->encoder.r.pph_sections[i] = XCNEW (struct lto_file_decl_data); - - header = (pph_file_header *) stream->encoder.r.file_data; - strtab = (const char *) header + sizeof (pph_file_header); - strtab_size = header->strtab_size; - body = strtab + strtab_size; - gcc_assert (stream->encoder.r.file_size - >= strtab_size + sizeof (pph_file_header)); - body_size = stream->encoder.r.file_size - - strtab_size - sizeof (pph_file_header); - - /* Create a new string table for STREAM. This table is not part of - STREAM because it needs to remain around until the end of - compilation (all the string streaming routines work by pointing - into the string table, so we cannot deallocate it after reading - STREAM). */ - new_strtab = XNEWVEC (char, strtab_size); - memcpy (new_strtab, strtab, strtab_size); - VEC_safe_push (char_p, heap, string_tables, new_strtab); - - /* Create an input block structure pointing right after the string - table. */ - stream->encoder.r.ib = XCNEW (struct lto_input_block); - LTO_INIT_INPUT_BLOCK_PTR (stream->encoder.r.ib, body, 0, body_size); - stream->encoder.r.data_in - = lto_data_in_create (stream->encoder.r.pph_sections[0], - new_strtab, strtab_size, NULL); - - /* Associate STREAM with STREAM->ENCODER.R.DATA_IN so we can recover - it from the streamer hooks. */ - stream->encoder.r.data_in->sdata = (void *) stream; -} - - -/********************************************************** primitive values */ - - -/* Read an unsigned char VALUE to STREAM. */ - -static unsigned char -pph_in_uchar (pph_stream *stream) -{ - unsigned char n = streamer_read_uchar (stream->encoder.r.ib); - return n; -} - - -/* Read a HOST_WIDE_INT from STREAM. */ - -static inline HOST_WIDE_INT -pph_in_hwi (pph_stream *stream) -{ - return streamer_read_hwi (stream->encoder.r.ib); -} - - -/* Read an int from STREAM. */ - -static inline int -pph_in_int (pph_stream *stream) -{ - HOST_WIDE_INT n = streamer_read_hwi (stream->encoder.r.ib); - gcc_assert (n == (int) n); - return (int) n; -} - - -/* Read an unsigned HOST_WIDE_INT from STREAM. */ - -static inline unsigned HOST_WIDE_INT -pph_in_uhwi (pph_stream *stream) -{ - return streamer_read_uhwi (stream->encoder.r.ib); -} - - -/* Read an unsigned integer from STREAM. */ - -unsigned int -pph_in_uint (pph_stream *stream) -{ - HOST_WIDE_INT unsigned n = streamer_read_uhwi (stream->encoder.r.ib); - gcc_assert (n == (unsigned) n); - return (unsigned) n; -} - - -/* Read N bytes from STREAM into P. The caller is responsible for - allocating a sufficiently large buffer. */ - -static void -pph_in_bytes (pph_stream *stream, void *p, size_t n) -{ - lto_input_data_block (stream->encoder.r.ib, p, n); -} - - -/* Read and return a string from STREAM. */ - -static const char * -pph_in_string (pph_stream *stream) -{ - const char *s = streamer_read_string (stream->encoder.r.data_in, - stream->encoder.r.ib); - return s; -} - - -/* Read a bitpack from STREAM. */ - -static struct bitpack_d -pph_in_bitpack (pph_stream *stream) -{ - struct bitpack_d bp = streamer_read_bitpack (stream->encoder.r.ib); - return bp; -} - - -/******************************************************** source information */ - - -/* Set in pph_in_and_merge_line_table. Represents the source_location offset - which every streamed in token must add to it's serialized source_location. - - FIXME pph: Ideally this would be in pph_stream.encoder.r, but for that we - first need to get rid of the dependency to the streamer_hook for locations. - */ -static int pph_loc_offset; - - -/* Read a linenum_type from STREAM. */ - -static inline linenum_type -pph_in_linenum_type (pph_stream *stream) -{ - return (linenum_type) pph_in_uint (stream); -} - - -/* Read a source_location from STREAM. */ - -static inline source_location -pph_in_source_location (pph_stream *stream) -{ - return (source_location) pph_in_uint (stream); -} - - -/* Read a line table marker from STREAM. */ - -static inline enum pph_linetable_marker -pph_in_linetable_marker (pph_stream *stream) -{ - enum pph_linetable_marker m = - (enum pph_linetable_marker) pph_in_uchar (stream); - gcc_assert (m == PPH_LINETABLE_ENTRY - || m == PPH_LINETABLE_REFERENCE - || m == PPH_LINETABLE_END); - return m; -} - - - -/* Read all the fields of struct line_map LM from STREAM. LM is assumed - to be an ordinary line map. */ - -static void -pph_in_line_map_ordinary (pph_stream *stream, struct line_map *lm) -{ - struct bitpack_d bp; - - ORDINARY_MAP_FILE_NAME (lm) = pph_in_string (stream); - ORDINARY_MAP_STARTING_LINE_NUMBER (lm) = pph_in_linenum_type (stream); - - /* Note that this index is an offset indicating the distance from LM - to the line map entry for LM's includer. It needs to be adjusted - while reading the line table in pph_in_line_table_and_includes. */ - ORDINARY_MAP_INCLUDER_FILE_INDEX (lm) = pph_in_int (stream); - bp = pph_in_bitpack (stream); - ORDINARY_MAP_IN_SYSTEM_HEADER_P (lm) - = (unsigned char) bp_unpack_value (&bp, CHAR_BIT); - ORDINARY_MAP_NUMBER_OF_COLUMN_BITS (lm) = bp_unpack_value (&bp, - COLUMN_BITS_BIT); -} - - -/* Read a line_map from STREAM into LM. */ - -static void -pph_in_line_map (pph_stream *stream, struct line_map *lm) -{ - struct lto_input_block *ib = stream->encoder.r.ib; - - lm->start_location = pph_in_source_location (stream); - lm->reason = streamer_read_enum (ib, lc_reason, LC_ENTER_MACRO); - - /* FIXME pph. We currently do not support location tracking for - macros in PPH images. */ - gcc_assert (lm->reason != LC_ENTER_MACRO); - pph_in_line_map_ordinary (stream, lm); -} - - -/* Read in from STREAM and merge a referenced include into the current parsing - context. */ - -static void -pph_in_include (pph_stream *stream) -{ - int old_loc_offset; - const char *include_name; - pph_stream *include_stream; - source_location prev_start_loc = pph_in_source_location (stream); - - /* Simulate highest_location to be as it would be at this point in a non-pph - compilation. */ - line_table->highest_location = (prev_start_loc - 1) + pph_loc_offset; - - /* FIXME pph: If we move pph_loc_offset to pph_stream.encoder.r, we could - have an independent offset for each stream and not have to save and - restore the state of a global pph_loc_offset as we are doing here. */ - old_loc_offset = pph_loc_offset; - - include_name = pph_in_string (stream); - include_stream = pph_read_file (include_name); - - /* Add INCLUDE_STREAM, and the images included by it, to the list - of included images for STREAM. */ - pph_add_include (stream, include_stream); - - pph_loc_offset = old_loc_offset; -} - - -/* Read the line_table from STREAM and merge it in the current - line_table. At the same time load includes in the order they were - originally included by loading them at the point they were - referenced in the line_table. - - Returns the source_location of line 1 / col 0 for this include. */ - -static source_location -pph_in_line_table_and_includes (pph_stream *stream) -{ - unsigned int used_before, old_depth; - bool first; - enum pph_linetable_marker next_lt_marker; - int top_includer_ix; - - used_before = LINEMAPS_ORDINARY_USED (line_table); - first = true; - - /* All line map entries that have -1 as the includer, will now be - relocated to the current last line map entry in the line table. */ - top_includer_ix = used_before - 1; - - for (next_lt_marker = pph_in_linetable_marker (stream); - next_lt_marker != PPH_LINETABLE_END; - next_lt_marker = pph_in_linetable_marker (stream)) - { - if (next_lt_marker == PPH_LINETABLE_REFERENCE) - { - gcc_assert (!first); - pph_in_include (stream); - } - else - { - struct line_map *lm; - int last_entry_ix; - - lm = linemap_new_map (line_table, LC_ENTER); - pph_in_line_map (stream, lm); - - /* All the entries that we read from STREAM will be appended - to the end of line_table. Calculate the index for the - last entry so that we can resolve the relative indices - for all the includer file index entries we read from - STREAM. Note that LAST_ENTRY_IX is the index of the line - map LM that we have just read. */ - last_entry_ix = LINEMAPS_ORDINARY_USED (line_table) - 1; - - if (first) - { - first = false; - pph_loc_offset = (line_table->highest_location + 1) - - lm->start_location; - gcc_assert (ORDINARY_MAP_INCLUDER_FILE_INDEX (lm) == -1); - } - - /* Relocate the includer file index. For most entries, the - writer wrote ORDINARY_MAP_INCLUDER_FILE_INDEX as a - relative offset between this entry and the original - includer file index (see pph_out_line_map_ordinary). - Convert that relative index into an absolute index in the - current line_table. - - A relocation value of -1 means that line map LM is - included by the current top includer (i.e., STREAM), so - we use the value TOP_INCLUDER_IX for it. */ - if (ORDINARY_MAP_INCLUDER_FILE_INDEX (lm) == -1) - ORDINARY_MAP_INCLUDER_FILE_INDEX (lm) = top_includer_ix; - else - ORDINARY_MAP_INCLUDER_FILE_INDEX (lm) -= last_entry_ix; - - lm->start_location += pph_loc_offset; - } - } - - /* We used to expect exactly the same number of entries, but files - included from this PPH file may sometimes not be needed. For - example, - - #include "2.pph" - #include "foo.pph" - +--> #include "1.pph" - #include "2.pph" - #include "3.pph" - - When foo.pph was originally created, the line table was built - with inclusions of 1.pph, 2.pph and 3.pph. But when compiling - the main translation unit, we include 2.pph before foo.pph, so - the inclusion of 2.pph from foo.pph does nothing. Leaving the - line table in a different shape than the original compilation. - - Instead of insisting on getting EXPECTED_IN entries, we expect at - most EXPECTED_IN entries. */ - { - unsigned int expected = pph_in_uint (stream); - gcc_assert (LINEMAPS_ORDINARY_USED (line_table) - used_before <= expected); - } - - line_table->highest_location = pph_loc_offset + pph_in_uint (stream); - line_table->highest_line = pph_loc_offset + pph_in_uint (stream); - - /* The MAX_COLUMN_HINT can be directly overwritten. */ - line_table->max_column_hint = pph_in_uint (stream); - - /* The line_table doesn't store the last LC_LEAVE in any given compilation; - thus we need to replay the LC_LEAVE for the header now. For that same - reason, the line_table should currently be in a state representing a depth - one include deeper then the depth at which this pph was included. The - LC_LEAVE replay will then bring the depth back to what it was before - calling this function. */ - old_depth = line_table->depth++; - linemap_add (line_table, LC_LEAVE, 0, NULL, 0); - gcc_assert (line_table->depth == old_depth); - - return MAP_START_LOCATION (LINEMAPS_ORDINARY_MAP_AT (line_table, used_before)); -} - - -/*********************************************************** record handling */ - - -/* Wrapper for memory allocation calls that should have their results - registered in the PPH streamer cache. DATA is the pointer returned - by the memory allocation call in ALLOC_EXPR. IX is the cache slot - in CACHE where the newly allocated DATA should be registered at. */ -#define ALLOC_AND_REGISTER(CACHE, IX, TAG, DATA, ALLOC_EXPR) \ - do { \ - (DATA) = (ALLOC_EXPR); \ - pph_cache_insert_at (CACHE, DATA, IX, TAG); \ - } while (0) - - -/* Read and return a record marker from STREAM. On return, *TAG_P will - contain the tag for the data type stored in this record. */ -enum pph_record_marker -pph_in_record_marker (pph_stream *stream, enum pph_tag *tag_p) -{ - enum pph_record_marker m = (enum pph_record_marker) pph_in_uchar (stream); - gcc_assert (m == PPH_RECORD_START - || m == PPH_RECORD_START_NO_CACHE - || m == PPH_RECORD_START_MUTATED - || m == PPH_RECORD_START_MERGE_KEY - || m == PPH_RECORD_START_MERGE_BODY - || m == PPH_RECORD_END - || m == PPH_RECORD_IREF - || m == PPH_RECORD_XREF - || m == PPH_RECORD_PREF); - - *tag_p = (enum pph_tag) pph_in_uint (stream); - gcc_assert ((unsigned) *tag_p < (unsigned) PPH_NUM_TAGS); - - if (flag_pph_tracer >= 5) - pph_trace_marker (m, *tag_p); - - return m; -} - - -/* Read and return a record header from STREAM. EXPECTED_TAG indicates - the data type that should be stored in this record. When a - PPH_RECORD_START marker is read, the next word read is an index - into the streamer cache where the rematerialized data structure - should be stored. When the writer stored this data structure for - the first time, it added it to its own streamer cache at slot - number *CACHE_IX_P. - - This way, if the same data structure was written a second time to - the stream, instead of writing the whole structure again, only the - index *CACHE_IX_P is written as a PPH_RECORD_IREF record. - - Therefore, when reading a PPH_RECORD_START marker, *CACHE_IX_P will - contain the slot number where the materialized data should be - cached at. When reading a PPH_RECORD_IREF marker, *CACHE_IX_P will - contain the slot number the reader can find the previously - materialized structure. - - If the record starts with PPH_RECORD_XREF, this means that the data - we are about to read is located in the pickle cache of one of - STREAM's included images. In this case, the record consists of two - indices: the first one (*INCLUDE_IX_P) indicates which included - image contains the data (it is an index into STREAM->INCLUDES), the - second one indicates which slot in that image's pickle cache we can - find the data. */ - -static inline enum pph_record_marker -pph_in_start_record (pph_stream *stream, unsigned *include_ix_p, - unsigned *cache_ix_p, enum pph_tag expected_tag) -{ - enum pph_tag read_tag; - enum pph_record_marker marker = pph_in_record_marker (stream, &read_tag); - - /* If the caller expects any tree, make sure we get a valid tree code. */ - if (expected_tag == PPH_any_tree) - gcc_assert (read_tag < PPH_any_tree); - else - gcc_assert (read_tag == expected_tag); - - *include_ix_p = (unsigned) -1; - *cache_ix_p = (unsigned) -1; - - /* For PPH_RECORD_START and PPH_RECORD_IREF markers, read the - streamer cache slot where we should store or find the - rematerialized data structure (see description above). - Also read the preloaded cache slot in IX for PPH_RECORD_PREF. */ - if (marker == PPH_RECORD_START - || marker == PPH_RECORD_IREF - || marker == PPH_RECORD_PREF - || marker == PPH_RECORD_START_MERGE_BODY - || marker == PPH_RECORD_START_MERGE_KEY) - *cache_ix_p = pph_in_uint (stream); - else if (marker == PPH_RECORD_XREF - || marker == PPH_RECORD_START_MUTATED) - { - *include_ix_p = pph_in_uint (stream); - *cache_ix_p = pph_in_uint (stream); - } - else if (marker == PPH_RECORD_END || marker == PPH_RECORD_START_NO_CACHE) - ; /* Nothing to do. This record will not need cache updates. */ - else - gcc_unreachable (); - - return marker; -} - - -/********************************************************** lexical elements */ - - -/* Read and return a location_t from STREAM. */ - -location_t -pph_in_location (pph_stream *stream) -{ - struct bitpack_d bp; - bool is_builtin; - unsigned HOST_WIDE_INT n; - location_t old_loc; - - bp = pph_in_bitpack (stream); - is_builtin = bp_unpack_value (&bp, 1); - - n = pph_in_uhwi (stream); - old_loc = (location_t) n; - gcc_assert (old_loc == n); - - return is_builtin ? old_loc : old_loc + pph_loc_offset; -} - - -/* Load the tree value associated with TOKEN from STREAM. */ - -static void -pph_in_token_value (pph_stream *stream, cp_token *token) -{ - switch (token->type) - { - case CPP_TEMPLATE_ID: - case CPP_NESTED_NAME_SPECIFIER: - /* FIXME pph - Need to handle struct tree_check. */ - break; - - case CPP_KEYWORD: - token->u.value = ridpointers[token->keyword]; - break; - - case CPP_NAME: - case CPP_CHAR: - case CPP_WCHAR: - case CPP_CHAR16: - case CPP_CHAR32: - case CPP_NUMBER: - case CPP_STRING: - case CPP_WSTRING: - case CPP_STRING16: - case CPP_STRING32: - token->u.value = pph_in_tree (stream); - break; - - case CPP_PRAGMA: - /* Nothing to do. Field pragma_kind has already been loaded. */ - break; - - default: - pph_in_bytes (stream, &token->u.value, sizeof (token->u.value)); - gcc_assert (token->u.value == NULL); - } -} - - -/* Read and return a token from STREAM. */ - -static cp_token * -pph_in_token (pph_stream *stream) -{ - cp_token *token = ggc_alloc_cleared_cp_token (); - - /* Do not read the whole structure, the token value has - dynamic size as it contains swizzled pointers. - FIXME pph, restructure to allow bulk reads of the whole - section. */ - pph_in_bytes (stream, token, sizeof (cp_token) - sizeof (void *)); - - /* FIXME pph. Use an arbitrary (but valid) location to avoid - confusing the rest of the compiler for now. */ - token->location = input_location; - - /* FIXME pph: verify that pph_in_token_value works with no tokens. */ - pph_in_token_value (stream, token); - - return token; -} - - -/* Read and return a cp_token_cache instance from STREAM. */ - -static cp_token_cache * -pph_in_token_cache (pph_stream *stream) -{ - unsigned i, num; - cp_token *first, *last; - - num = pph_in_uint (stream); - for (last = first = NULL, i = 0; i < num; i++) - { - last = pph_in_token (stream); - if (first == NULL) - first = last; - } - - return cp_token_cache_new (first, last); -} - - -/******************************************************************* vectors */ - - -/* Read and return a gc VEC of trees from STREAM. */ - -static VEC(tree,gc) * -pph_in_tree_vec (pph_stream *stream) -{ - HOST_WIDE_INT i, num; - VEC(tree,gc) *v; - - num = pph_in_hwi (stream); - v = NULL; - for (i = 0; i < num; i++) - { - tree t = pph_in_tree (stream); - VEC_safe_push (tree, gc, v, t); - } - - return v; -} - - -/* Read and return a gc VEC of qualified_typedef_usage_t from STREAM. */ - -static VEC(qualified_typedef_usage_t,gc) * -pph_in_qual_use_vec (pph_stream *stream) -{ - unsigned i, num; - VEC(qualified_typedef_usage_t,gc) *v; - - num = pph_in_uint (stream); - v = NULL; - for (i = 0; i < num; i++) - { - qualified_typedef_usage_t q; - q.typedef_decl = pph_in_tree (stream); - q.context = pph_in_tree (stream); - q.locus = pph_in_location (stream); - VEC_safe_push (qualified_typedef_usage_t, gc, v, &q); - } - - return v; -} - - -/* Read the vector V of tree_pair_s instances from STREAM. */ - -static VEC(tree_pair_s,gc) * -pph_in_tree_pair_vec (pph_stream *stream) -{ - unsigned i, num; - VEC(tree_pair_s,gc) *v; - - num = pph_in_uint (stream); - for (i = 0, v = NULL; i < num; i++) - { - tree_pair_s p; - p.purpose = pph_in_tree (stream); - p.value = pph_in_tree (stream); - VEC_safe_push (tree_pair_s, gc, v, &p); - } - - return v; -} - - -/* Test whether tree T is an element of vector V. */ - -static bool -pph_is_tree_element_of_vec (tree t, VEC(tree,gc) *v) -{ - unsigned i; - tree s; - FOR_EACH_VEC_ELT (tree, v, i, s) - if (s == t) - return true; - return false; -} - - -/* Return the union of two tree vecs. The argument vectors are unmodified. */ - -static VEC(tree,gc) * -pph_union_two_tree_vecs (VEC(tree,gc) *left, VEC(tree,gc) *right) -{ - /* FIXME pph: This O(left)+O(left*right) union may become a problem. - In the long run, we probably want to copy both into a hash table - and then copy the table into the result. */ - unsigned i; - tree t; - VEC(tree,gc) *unioned = VEC_copy (tree, gc, left); - FOR_EACH_VEC_ELT (tree, right, i, t) - { - if (!pph_is_tree_element_of_vec (t, left)) - VEC_safe_push (tree, gc, unioned, t); - } - return unioned; -} - - -/* Union FROM one tree vec with and INTO a tree vec. The INTO argument will - have an updated value. The FROM argument is no longer valid. */ - -static void -pph_union_into_tree_vec (VEC(tree,gc) **into, VEC(tree,gc) *from) -{ - if (!VEC_empty (tree, from)) - { - if (*into == NULL) - *into = from; - else if (VEC_empty (tree, *into)) - { - VEC_free (tree, gc, *into); - *into = from; - } - else - { - VEC(tree,gc) *unioned = pph_union_two_tree_vecs (*into, from); - VEC_free (tree, gc, *into); - VEC_free (tree, gc, from); - *into = unioned; - } - } -} - - -/******************************************************************** chains */ - - -/* Read a chain of ASTs from STREAM. */ - -static tree -pph_in_chain (pph_stream *stream) -{ - return streamer_read_chain (stream->encoder.r.ib, stream->encoder.r.data_in); -} - - -/* Read a chain of AST merge keys from STREAM. Merge each tree - into *CHAIN. */ - -static void -pph_in_merge_key_chain (pph_stream *stream, tree *chain) -{ - unsigned i; - HOST_WIDE_INT count; - - count = pph_in_hwi (stream); - for (i = 0; i < count; i++) - pph_in_merge_key_tree (stream, chain); -} - - -/* Read a chain of AST merge bodies from STREAM. */ - -static void -pph_in_merge_body_chain (pph_stream *stream) -{ - unsigned i; - HOST_WIDE_INT count; - - count = pph_in_hwi (stream); - for (i = 0; i < count; i++) - pph_in_tree (stream); -} - - -/* Merge table of contents. This TOC is used to decide whether a - symbol has already been merged into a given compilation context. - Compilation contexts are usually tree chains (e.g., - scope_chain->bindings->names), but they can be any stable memory - address. - - This TOC is indexed by two values: the merge key read by - pph_in_merge_key_tree and the context in which we are doing this - merge. */ -static htab_t merge_toc = NULL; - -/* Table of contents entry. */ -typedef struct { - /* Tree being matched. */ - tree expr; - - /* Context where this tree should be inserted into. */ - tree *context; - - /* Name of the tree (from pph_merge_name). */ - const char *name; -} merge_toc_entry; - - -/* Hash and equivalence functions for the merge TOC. */ - -static hashval_t -htab_merge_key_hash (const void *p) -{ - const merge_toc_entry *key = (const merge_toc_entry *) p; - hashval_t context_val = htab_hash_pointer (key->context); - hashval_t name_val = htab_hash_string (key->name); - hashval_t id_val = iterative_hash_hashval_t (name_val, TREE_CODE (key->expr)); - return iterative_hash_hashval_t (context_val, id_val); -} - -static int -htab_merge_key_eq (const void *p1, const void *p2) -{ - const merge_toc_entry *key1 = (const merge_toc_entry *) p1; - const merge_toc_entry *key2 = (const merge_toc_entry *) p2; - - if (key1->context != key2->context) - return false; - - if (TREE_CODE (key1->expr) != TREE_CODE (key2->expr)) - return false; - - if (key1->name == NULL || key2->name == NULL) - return false; - - return strcmp (key1->name, key2->name) == 0; -} - - -/* Look in TOC for an existing tree matching KEY. */ - -static tree -pph_toc_lookup (htab_t toc, merge_toc_entry *key) -{ - void *slot = htab_find (toc, key); - tree expr = NULL; - - if (slot) - { - merge_toc_entry *e = (merge_toc_entry *) slot; - expr = e->expr; - } - - return expr; -} - - -/* Insert KEY into TOC. */ - -static void -pph_toc_add (htab_t toc, merge_toc_entry *key) -{ - void **slot; - merge_toc_entry *entry; - - slot = htab_find_slot (toc, key, INSERT); - gcc_assert (*slot == NULL); - - entry = XCNEW (merge_toc_entry); - memcpy (entry, key, sizeof (*key)); - *slot = (void *) entry; -} - - -/* Prepend a tree EXPR to a CHAIN. */ - -static tree -pph_prepend_to_chain (tree expr, tree *chain) -{ - DECL_CHAIN (expr) = *chain; - *chain = expr; - return expr; -} - - -/* Merge the just-read header for tree EXPR with NAME onto the CHAIN. */ - -static tree -pph_merge_into_chain (tree expr, const char *name, tree *chain) -{ - merge_toc_entry key; - tree found; - - key.expr = expr; - key.context = chain; - key.name = name; - found = pph_toc_lookup (merge_toc, &key); - if (!found) - { - pph_toc_add (merge_toc, &key); - - if (flag_pph_debug >= 3) - fprintf (pph_logfile, "PPH: %s NOT found on chain\n", name); - - /* Types (as opposed to type decls) are not on a chain. */ - if (chain) - return pph_prepend_to_chain (expr, chain); - else - return expr; - } - - if (flag_pph_debug >= 3) - fprintf (pph_logfile, "PPH: %s FOUND on chain\n", name); - - gcc_assert (TREE_CODE (found) == TREE_CODE (expr)); - - return found; -} - - -/****************************************************************** bindings */ - - -/* Forward declaration to break cyclic dependencies. */ -static cp_binding_level *pph_in_binding_level (pph_stream *); - -/* Helper for pph_in_cxx_binding. Read and return a cxx_binding - instance from STREAM. */ - -static cxx_binding * -pph_in_cxx_binding_1 (pph_stream *stream) -{ - struct bitpack_d bp; - cxx_binding *cb; - tree value, type; - enum pph_record_marker marker; - unsigned ix, image_ix; - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_cxx_binding); - if (marker == PPH_RECORD_END) - return NULL; - else if (pph_is_reference_marker (marker)) - return (cxx_binding *) pph_cache_find (stream, marker, image_ix, ix, - PPH_cxx_binding); - - value = pph_in_tree (stream); - type = pph_in_tree (stream); - ALLOC_AND_REGISTER (&stream->cache, ix, PPH_cxx_binding, cb, - cxx_binding_make (value, type)); - cb->scope = pph_in_binding_level (stream); - bp = pph_in_bitpack (stream); - cb->value_is_inherited = bp_unpack_value (&bp, 1); - cb->is_local = bp_unpack_value (&bp, 1); - - return cb; -} - - -/* Read and return an instance of cxx_binding from STREAM. */ - -static cxx_binding * -pph_in_cxx_binding (pph_stream *stream) -{ - cxx_binding *curr, *prev, *cb; - - /* Read the current binding first. */ - cb = pph_in_cxx_binding_1 (stream); - - /* Read the list of previous bindings. */ - for (curr = cb; curr; curr = prev) - { - prev = pph_in_cxx_binding_1 (stream); - curr->previous = prev; - } - - return cb; -} - - -/* Read all the fields of cp_class_binding instance CB to STREAM. */ - -static cp_class_binding * -pph_in_class_binding (pph_stream *stream) -{ - cp_class_binding *cb; - enum pph_record_marker marker; - unsigned image_ix, ix; - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_cp_class_binding); - if (marker == PPH_RECORD_END) - return NULL; - else if (pph_is_reference_marker (marker)) - return (cp_class_binding *) pph_cache_find (stream, marker, image_ix, ix, - PPH_cp_class_binding); - - ALLOC_AND_REGISTER (&stream->cache, ix, PPH_cp_class_binding, cb, - ggc_alloc_cleared_cp_class_binding ()); - cb->base = pph_in_cxx_binding (stream); - cb->identifier = pph_in_tree (stream); - - return cb; -} - - -/* Read and return an instance of cp_label_binding from STREAM. */ - -static cp_label_binding * -pph_in_label_binding (pph_stream *stream) -{ - cp_label_binding *lb; - enum pph_record_marker marker; - unsigned image_ix, ix; - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_cp_label_binding); - if (marker == PPH_RECORD_END) - return NULL; - else if (pph_is_reference_marker (marker)) - return (cp_label_binding *) pph_cache_find (stream, marker, image_ix, ix, - PPH_cp_label_binding); - - ALLOC_AND_REGISTER (&stream->cache, ix, PPH_cp_label_binding, lb, - ggc_alloc_cleared_cp_label_binding ()); - lb->label = pph_in_tree (stream); - lb->prev_value = pph_in_tree (stream); - - return lb; -} - - -/* Read the contents of binding level BL from STREAM. */ - -static void -pph_in_binding_level_1 (pph_stream *stream, cp_binding_level *bl) -{ - unsigned i, num; - struct bitpack_d bp; - - bl->this_entity = pph_in_tree (stream); - - num = pph_in_uint (stream); - bl->class_shadowed = NULL; - for (i = 0; i < num; i++) - { - cp_class_binding *cb = pph_in_class_binding (stream); - VEC_safe_push (cp_class_binding, gc, bl->class_shadowed, cb); - } - - bl->type_shadowed = pph_in_tree (stream); - - num = pph_in_uint (stream); - bl->shadowed_labels = NULL; - for (i = 0; i < num; i++) - { - cp_label_binding *sl = pph_in_label_binding (stream); - VEC_safe_push (cp_label_binding, gc, bl->shadowed_labels, sl); - } - - bl->blocks = pph_in_tree (stream); - bl->level_chain = pph_in_binding_level (stream); - bl->dead_vars_from_for = pph_in_tree_vec (stream); - bl->statement_list = pph_in_chain (stream); - bl->binding_depth = pph_in_uint (stream); - - bp = pph_in_bitpack (stream); - bl->kind = (enum scope_kind) bp_unpack_value (&bp, 4); - bl->keep = bp_unpack_value (&bp, 1); - bl->more_cleanups_ok = bp_unpack_value (&bp, 1); - bl->have_cleanups = bp_unpack_value (&bp, 1); -} - - -/* Read the start of a binding level. Return true when processing is done. */ - -static bool -pph_in_binding_level_start (pph_stream *stream, cp_binding_level **blp, - unsigned *ixp) -{ - unsigned image_ix; - enum pph_record_marker marker; - - marker = pph_in_start_record (stream, &image_ix, ixp, PPH_cp_binding_level); - if (marker == PPH_RECORD_END) - { - *blp = NULL; - return true; - } - else if (pph_is_reference_marker (marker)) - { - *blp = (cp_binding_level *) - pph_cache_find (stream, marker, image_ix, *ixp, PPH_cp_binding_level); - return true; - } - return false; -} - - -/* Read and return an instance of cp_binding_level from STREAM. - This function is for use when we will not be merging the binding level. */ - -static cp_binding_level * -pph_in_binding_level (pph_stream *stream) -{ - unsigned ix; - cp_binding_level *bl; - - if (pph_in_binding_level_start (stream, &bl, &ix)) - return bl; - - bl = ggc_alloc_cleared_cp_binding_level (); - pph_cache_insert_at (&stream->cache, bl, ix, PPH_cp_binding_level); - - bl->names = pph_in_chain (stream); - bl->namespaces = pph_in_chain (stream); - bl->usings = pph_in_chain (stream); - bl->using_directives = pph_in_chain (stream); - bl->static_decls = pph_in_tree_vec (stream); - pph_in_binding_level_1 (stream, bl); - - return bl; -} - - -/* Read all the merge keys from STREAM into the cp_binding_level BL. */ - -static void -pph_in_binding_merge_keys (pph_stream *stream, cp_binding_level *bl) -{ - /* Read all the merge keys and merge into the bindings. */ - pph_in_merge_key_chain (stream, &bl->names); - pph_in_merge_key_chain (stream, &bl->namespaces); - pph_in_merge_key_chain (stream, &bl->usings); - pph_in_merge_key_chain (stream, &bl->using_directives); -} - - -/* Read all the merge bodies from STREAM into the cp_binding_level BL. */ - -static void -pph_in_binding_merge_bodies_1 (pph_stream *stream, cp_binding_level *bl) -{ - pph_in_merge_body_chain (stream); - pph_in_merge_body_chain (stream); - pph_in_merge_body_chain (stream); - pph_in_merge_body_chain (stream); - pph_union_into_tree_vec (&bl->static_decls, pph_in_tree_vec (stream)); - /* FIXME pph: The following is probably too aggressive in overwriting. */ - pph_in_binding_level_1 (stream, bl); -} - - -/* Read all the merge bodies from STREAM into the cp_binding_level BL. */ - -static void -pph_in_binding_merge_bodies (pph_stream *stream, cp_binding_level *bl) -{ - unsigned ix; - cp_binding_level *new_bl; - - if (pph_in_binding_level_start (stream, &new_bl, &ix)) - { - gcc_assert (new_bl == bl); - return; - } - - /* The binding level is already allocated. */ - pph_cache_insert_at (&stream->cache, bl, ix, PPH_cp_binding_level); - pph_in_binding_merge_bodies_1 (stream, bl); -} - - -/********************************************************** tree aux classes */ - - -/* Read and return an instance of struct language_function from STREAM. */ - -static struct language_function * -pph_in_language_function (pph_stream *stream) -{ - struct bitpack_d bp; - struct language_function *lf; - enum pph_record_marker marker; - unsigned image_ix, ix; - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_language_function); - if (marker == PPH_RECORD_END) - return NULL; - else if (pph_is_reference_marker (marker)) - return (struct language_function *) pph_cache_find (stream, marker, - image_ix, ix, - PPH_language_function); - - ALLOC_AND_REGISTER (&stream->cache, ix, PPH_language_function, lf, - ggc_alloc_cleared_language_function ()); - lf->base.x_stmt_tree.x_cur_stmt_list = pph_in_tree_vec (stream); - lf->base.x_stmt_tree.stmts_are_full_exprs_p = pph_in_uint (stream); - lf->x_cdtor_label = pph_in_tree (stream); - lf->x_current_class_ptr = pph_in_tree (stream); - lf->x_current_class_ref = pph_in_tree (stream); - lf->x_eh_spec_block = pph_in_tree (stream); - lf->x_in_charge_parm = pph_in_tree (stream); - lf->x_vtt_parm = pph_in_tree (stream); - lf->x_return_value = pph_in_tree (stream); - bp = pph_in_bitpack (stream); - lf->returns_value = bp_unpack_value (&bp, 1); - lf->returns_null = bp_unpack_value (&bp, 1); - lf->returns_abnormally = bp_unpack_value (&bp, 1); - lf->x_in_function_try_handler = bp_unpack_value (&bp, 1); - lf->x_in_base_initializer = bp_unpack_value (&bp, 1); - lf->can_throw = bp_unpack_value (&bp, 1); - - /* FIXME pph. We are not reading lf->x_named_labels. */ - - lf->bindings = pph_in_binding_level (stream); - lf->x_local_names = pph_in_tree_vec (stream); - - /* FIXME pph. We are not reading lf->extern_decl_map. */ - - return lf; -} - - -/* Read applicable fields of struct function from STREAM. Associate - the read structure to DECL. */ - -static void -pph_in_struct_function (pph_stream *stream, tree decl) -{ - size_t count, i; - unsigned image_ix, ix; - enum pph_record_marker marker; - struct function *fn; - tree t; - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_function); - if (marker == PPH_RECORD_END) - return; - else if (pph_is_reference_marker (marker)) - { - fn = (struct function *) pph_cache_find (stream, marker, image_ix, ix, - PPH_function); - gcc_assert (DECL_STRUCT_FUNCTION (decl) == fn); - return; - } - - /* Possibly allocate a new DECL_STRUCT_FUNCTION for DECL. */ - t = pph_in_tree (stream); - gcc_assert (t == decl); - fn = DECL_STRUCT_FUNCTION (decl); - if (!fn) - { - /* The DECL_STRUCT_FUNCTION does not already already exists, - which implies that we are reading an entirely new function - and not merging into an existing function. */ - /* We would normally use ALLOC_AND_REGISTER, - but allocate_struct_function does not return a pointer. */ - allocate_struct_function (decl, false); - fn = DECL_STRUCT_FUNCTION (decl); - } - - /* Now register it. */ - pph_cache_insert_at (&stream->cache, fn, ix, PPH_function); - - /* FIXME pph: For now, accept the new version of the fields when merging. */ - - input_struct_function_base (fn, stream->encoder.r.data_in, - stream->encoder.r.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 */ -} - - -/* Read all fields in lang_decl_base instance LDB from STREAM. */ - -static void -pph_in_ld_base (pph_stream *stream, struct lang_decl_base *ldb) -{ - struct bitpack_d bp; - - bp = pph_in_bitpack (stream); - ldb->selector = bp_unpack_value (&bp, 16); - ldb->language = (enum languages) bp_unpack_value (&bp, 4); - ldb->use_template = bp_unpack_value (&bp, 2); - ldb->not_really_extern = bp_unpack_value (&bp, 1); - ldb->initialized_in_class = bp_unpack_value (&bp, 1); - ldb->repo_available_p = bp_unpack_value (&bp, 1); - ldb->threadprivate_or_deleted_p = bp_unpack_value (&bp, 1); - ldb->anticipated_p = bp_unpack_value (&bp, 1); - ldb->friend_attr = bp_unpack_value (&bp, 1); - ldb->template_conv_p = bp_unpack_value (&bp, 1); - ldb->odr_used = bp_unpack_value (&bp, 1); - ldb->u2sel = bp_unpack_value (&bp, 1); -} - - -/* Read all the fields in lang_decl_min instance LDM from STREAM. */ - -static void -pph_in_ld_min (pph_stream *stream, struct lang_decl_min *ldm) -{ - ldm->template_info = pph_in_tree (stream); - if (ldm->base.u2sel == 0) - ldm->u2.access = pph_in_tree (stream); - else if (ldm->base.u2sel == 1) - ldm->u2.discriminator = pph_in_uint (stream); - else - gcc_unreachable (); -} - - -/* Read all the fields of lang_decl_fn instance LDF from STREAM. */ - -static void -pph_in_ld_fn (pph_stream *stream, struct lang_decl_fn *ldf) -{ - struct bitpack_d bp; - - /* Read all the fields in lang_decl_min. */ - pph_in_ld_min (stream, &ldf->min); - - bp = pph_in_bitpack (stream); - ldf->operator_code = (enum tree_code) bp_unpack_value (&bp, 16); - ldf->global_ctor_p = bp_unpack_value (&bp, 1); - ldf->global_dtor_p = bp_unpack_value (&bp, 1); - ldf->constructor_attr = bp_unpack_value (&bp, 1); - ldf->destructor_attr = bp_unpack_value (&bp, 1); - ldf->assignment_operator_p = bp_unpack_value (&bp, 1); - ldf->static_function = bp_unpack_value (&bp, 1); - ldf->pure_virtual = bp_unpack_value (&bp, 1); - ldf->defaulted_p = bp_unpack_value (&bp, 1); - ldf->has_in_charge_parm_p = bp_unpack_value (&bp, 1); - ldf->has_vtt_parm_p = bp_unpack_value (&bp, 1); - ldf->pending_inline_p = bp_unpack_value (&bp, 1); - ldf->nonconverting = bp_unpack_value (&bp, 1); - ldf->thunk_p = bp_unpack_value (&bp, 1); - ldf->this_thunk_p = bp_unpack_value (&bp, 1); - ldf->hidden_friend_p = bp_unpack_value (&bp, 1); - - ldf->befriending_classes = pph_in_tree (stream); - ldf->context = pph_in_tree (stream); - - if (ldf->thunk_p == 0) - ldf->u5.cloned_function = pph_in_tree (stream); - else if (ldf->thunk_p == 1) - ldf->u5.fixed_offset = pph_in_uint (stream); - else - gcc_unreachable (); - - if (ldf->pending_inline_p == 1) - ldf->u.pending_inline_info = pph_in_token_cache (stream); - else if (ldf->pending_inline_p == 0) - ldf->u.saved_language_function = pph_in_language_function (stream); -} - - -/* Read all the fields of lang_decl_ns instance LDNS from STREAM. */ - -static void -pph_in_ld_ns (pph_stream *stream, struct lang_decl_ns *ldns) -{ - if (ldns->level == NULL) - ldns->level = pph_in_binding_level (stream); - else - pph_in_binding_merge_bodies (stream, ldns->level); -} - - -/* Read all the fields of lang_decl_parm instance LDP from STREAM. */ - -static void -pph_in_ld_parm (pph_stream *stream, struct lang_decl_parm *ldp) -{ - ldp->level = pph_in_uint (stream); - ldp->index = pph_in_uint (stream); -} - - -/* Read language specific data in DECL from STREAM. */ - -static void -pph_in_lang_specific (pph_stream *stream, tree decl) -{ - struct lang_decl *ld; - struct lang_decl_base *ldb; - enum pph_record_marker marker; - unsigned image_ix, ix; - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_lang_decl); - if (marker == PPH_RECORD_END) - return; - else if (pph_is_reference_marker (marker)) - { - DECL_LANG_SPECIFIC (decl) = - (struct lang_decl *) pph_cache_find (stream, marker, image_ix, ix, - PPH_lang_decl); - return; - } - - /* Allocate a lang_decl structure for DECL, if not already present. - Namespace merge keys preallocate it. */ - ld = DECL_LANG_SPECIFIC (decl); - if (!ld) - { - retrofit_lang_decl (decl); - ld = DECL_LANG_SPECIFIC (decl); - } - - /* Now register it. We would normally use ALLOC_AND_REGISTER, - but retrofit_lang_decl does not return a pointer. */ - pph_cache_insert_at (&stream->cache, ld, ix, PPH_lang_decl); - - /* Read all the fields in lang_decl_base. */ - ldb = &ld->u.base; - pph_in_ld_base (stream, ldb); - - if (ldb->selector == 0) - { - /* Read all the fields in lang_decl_min. */ - pph_in_ld_min (stream, &ld->u.min); - } - else if (ldb->selector == 1) - { - /* Read all the fields in lang_decl_fn. */ - pph_in_ld_fn (stream, &ld->u.fn); - } - else if (ldb->selector == 2) - { - /* Read all the fields in lang_decl_ns. */ - pph_in_ld_ns (stream, &ld->u.ns); - } - else if (ldb->selector == 3) - { - /* Read all the fields in lang_decl_parm. */ - pph_in_ld_parm (stream, &ld->u.parm); - } - else - gcc_unreachable (); -} - - -/********************************************************* tree base classes */ - - -/* Read in the tree_common fields. */ - -static void -pph_in_tree_common (pph_stream *stream, tree t) -{ - /* The 'struct tree_typed typed' base class is handled in LTO. */ - TREE_CHAIN (t) = pph_in_tree (stream); -} - - -/* Read all the fields in lang_type_header instance LTH from STREAM. */ - -static void -pph_in_lang_type_header (pph_stream *stream, struct lang_type_header *lth) -{ - struct bitpack_d bp; - - bp = pph_in_bitpack (stream); - lth->is_lang_type_class = bp_unpack_value (&bp, 1); - lth->has_type_conversion = bp_unpack_value (&bp, 1); - lth->has_copy_ctor = bp_unpack_value (&bp, 1); - lth->has_default_ctor = bp_unpack_value (&bp, 1); - lth->const_needs_init = bp_unpack_value (&bp, 1); - lth->ref_needs_init = bp_unpack_value (&bp, 1); - lth->has_const_copy_assign = bp_unpack_value (&bp, 1); -} - - -/* Read a struct sorted_fields_type instance SFT to STREAM. */ - -static struct sorted_fields_type * -pph_in_sorted_fields_type (pph_stream *stream) -{ - unsigned i, num_fields; - struct sorted_fields_type *v; - enum pph_record_marker marker; - unsigned image_ix, ix; - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_sorted_fields_type); - if (marker == PPH_RECORD_END) - return NULL; - else if (pph_is_reference_marker (marker)) - return (struct sorted_fields_type *) - pph_cache_find (stream, marker, image_ix, ix, PPH_sorted_fields_type); - - num_fields = pph_in_uint (stream); - ALLOC_AND_REGISTER (&stream->cache, ix, PPH_sorted_fields_type, v, - sorted_fields_type_new (num_fields)); - for (i = 0; i < num_fields; i++) - v->elts[i] = pph_in_tree (stream); - - return v; -} - - -/* Read all the fields in lang_type_class instance LTC to STREAM. */ - -static void -pph_in_lang_type_class (pph_stream *stream, struct lang_type_class *ltc) -{ - struct bitpack_d bp; - enum pph_record_marker marker; - unsigned image_ix, ix; - - ltc->align = pph_in_uchar (stream); - - bp = pph_in_bitpack (stream); - ltc->has_mutable = bp_unpack_value (&bp, 1); - ltc->com_interface = bp_unpack_value (&bp, 1); - ltc->non_pod_class = bp_unpack_value (&bp, 1); - ltc->nearly_empty_p = bp_unpack_value (&bp, 1); - ltc->user_align = bp_unpack_value (&bp, 1); - ltc->has_copy_assign = bp_unpack_value (&bp, 1); - ltc->has_new = bp_unpack_value (&bp, 1); - ltc->has_array_new = bp_unpack_value (&bp, 1); - ltc->gets_delete = bp_unpack_value (&bp, 2); - ltc->interface_only = bp_unpack_value (&bp, 1); - ltc->interface_unknown = bp_unpack_value (&bp, 1); - ltc->contains_empty_class_p = bp_unpack_value (&bp, 1); - ltc->anon_aggr = bp_unpack_value (&bp, 1); - ltc->non_zero_init = bp_unpack_value (&bp, 1); - ltc->empty_p = bp_unpack_value (&bp, 1); - ltc->vec_new_uses_cookie = bp_unpack_value (&bp, 1); - ltc->declared_class = bp_unpack_value (&bp, 1); - ltc->diamond_shaped = bp_unpack_value (&bp, 1); - ltc->repeated_base = bp_unpack_value (&bp, 1); - ltc->being_defined = bp_unpack_value (&bp, 1); - ltc->java_interface = bp_unpack_value (&bp, 1); - ltc->debug_requested = bp_unpack_value (&bp, 1); - ltc->fields_readonly = bp_unpack_value (&bp, 1); - ltc->use_template = bp_unpack_value (&bp, 2); - ltc->ptrmemfunc_flag = bp_unpack_value (&bp, 1); - ltc->was_anonymous = bp_unpack_value (&bp, 1); - ltc->lazy_default_ctor = bp_unpack_value (&bp, 1); - ltc->lazy_copy_ctor = bp_unpack_value (&bp, 1); - ltc->lazy_copy_assign = bp_unpack_value (&bp, 1); - ltc->lazy_destructor = bp_unpack_value (&bp, 1); - ltc->has_const_copy_ctor = bp_unpack_value (&bp, 1); - ltc->has_complex_copy_ctor = bp_unpack_value (&bp, 1); - ltc->has_complex_copy_assign = bp_unpack_value (&bp, 1); - ltc->non_aggregate = bp_unpack_value (&bp, 1); - ltc->has_complex_dflt = bp_unpack_value (&bp, 1); - ltc->has_list_ctor = bp_unpack_value (&bp, 1); - ltc->non_std_layout = bp_unpack_value (&bp, 1); - ltc->is_literal = bp_unpack_value (&bp, 1); - ltc->lazy_move_ctor = bp_unpack_value (&bp, 1); - ltc->lazy_move_assign = bp_unpack_value (&bp, 1); - ltc->has_complex_move_ctor = bp_unpack_value (&bp, 1); - ltc->has_complex_move_assign = bp_unpack_value (&bp, 1); - ltc->has_constexpr_ctor = bp_unpack_value (&bp, 1); - - ltc->primary_base = pph_in_tree (stream); - ltc->vcall_indices = pph_in_tree_pair_vec (stream); - ltc->vtables = pph_in_tree (stream); - ltc->typeinfo_var = pph_in_tree (stream); - ltc->vbases = pph_in_tree_vec (stream); - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_binding_table); - if (marker == PPH_RECORD_START) - { - ltc->nested_udts = pph_in_binding_table (stream); - pph_cache_insert_at (&stream->cache, ltc->nested_udts, ix, - PPH_binding_table); - } - else if (pph_is_reference_marker (marker)) - ltc->nested_udts = (binding_table) pph_cache_find (stream, marker, - image_ix, ix, - PPH_binding_table); - - ltc->as_base = pph_in_tree (stream); - ltc->pure_virtuals = pph_in_tree_vec (stream); - ltc->friend_classes = pph_in_tree (stream); - ltc->methods = pph_in_tree_vec (stream); - ltc->key_method = pph_in_tree (stream); - ltc->decl_list = pph_in_tree (stream); - ltc->template_info = pph_in_tree (stream); - ltc->befriending_classes = pph_in_tree (stream); - ltc->objc_info = pph_in_tree (stream); - ltc->sorted_fields = pph_in_sorted_fields_type (stream); - ltc->lambda_expr = pph_in_tree (stream); -} - - -/* Read all fields of struct lang_type_ptrmem instance LTP from STREAM. */ - -static void -pph_in_lang_type_ptrmem (pph_stream *stream, - struct lang_type_ptrmem *ltp) -{ - ltp->record = pph_in_tree (stream); -} - - -/* Read all the fields in struct lang_type from STREAM. */ - -static struct lang_type * -pph_in_lang_type (pph_stream *stream) -{ - struct lang_type *lt; - enum pph_record_marker marker; - unsigned image_ix, ix; - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_lang_type); - if (marker == PPH_RECORD_END) - return NULL; - else if (pph_is_reference_marker (marker)) - return (struct lang_type *) pph_cache_find (stream, marker, image_ix, ix, - PPH_lang_type); - - ALLOC_AND_REGISTER (&stream->cache, ix, PPH_lang_type, lt, - ggc_alloc_cleared_lang_type (sizeof (struct lang_type))); - - pph_in_lang_type_header (stream, <->u.h); - if (lt->u.h.is_lang_type_class) - pph_in_lang_type_class (stream, <->u.c); - else - pph_in_lang_type_ptrmem (stream, <->u.ptrmem); - - return lt; -} - - -/* Read from STREAM the body of tcc_type node TYPE. */ - -static void -pph_in_tcc_type (pph_stream *stream, tree type) -{ - TYPE_LANG_SPECIFIC (type) = pph_in_lang_type (stream); - TYPE_POINTER_TO (type) = pph_in_tree (stream); - TYPE_REFERENCE_TO (type) = pph_in_tree (stream); - TYPE_NEXT_VARIANT (type) = pph_in_tree (stream); - /* FIXME pph - Streaming TYPE_CANONICAL generates many type comparison - failures. Why? */ - /* FIXME pph: apparently redundant. */ - TREE_CHAIN (type) = pph_in_tree (stream); - - /* The type values cache is built as constants are instantiated, - so we only stream it on the nodes that use it for - other purposes. */ - switch (TREE_CODE (type)) - { - case BOUND_TEMPLATE_TEMPLATE_PARM: - case DECLTYPE_TYPE: - case TEMPLATE_TEMPLATE_PARM: - case TEMPLATE_TYPE_PARM: - case TYPENAME_TYPE: - case TYPEOF_TYPE: - TYPE_VALUES_RAW (type) = pph_in_tree (stream); - break; - - default: - break; - } - - /* If TYPE has a METHOD_VEC, we need to resort it. Name lookup in - classes relies on the specific ordering of the class method - pointers. Since we generally instantiate them in a different - order than the original compile, the pointer values will be - different. This will cause name lookups to fail, unless we - resort the vector. */ - if (CLASS_TYPE_P (type) && CLASSTYPE_METHOD_VEC (type)) - finish_struct_methods (type); -} - - -/* Read from STREAM the body of tcc_declaration tree DECL. */ - -static void -pph_in_tcc_declaration (pph_stream *stream, tree decl) -{ - pph_in_lang_specific (stream, decl); - DECL_INITIAL (decl) = pph_in_tree (stream); - - /* The tree streamer only writes DECL_CHAIN for PARM_DECL nodes. - We need to read DECL_CHAIN for variables and functions because - they are sometimes chained together in places other than regular - tree chains. For example in BINFO_VTABLEs, the decls are chained - together). */ - if (TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL) - DECL_CHAIN (decl) = pph_in_tree (stream); - - /* Handle some individual decl nodes. */ - switch (TREE_CODE (decl)) - { - case FUNCTION_DECL: - DECL_SAVED_TREE (decl) = pph_in_tree (stream); - break; - - case TYPE_DECL: - DECL_ORIGINAL_TYPE (decl) = pph_in_tree (stream); - break; - - case TEMPLATE_DECL: - DECL_TEMPLATE_RESULT (decl) = pph_in_tree (stream); - DECL_TEMPLATE_PARMS (decl) = pph_in_tree (stream); - break; - - default: - break; - } - - /* When the declaration was compiled originally, the parser marks - it DECL_EXTERNAL, to avoid emitting it more than once. It also - remembers the true external state in DECL_NOT_REALLY_EXTERN. So, - if both bits are set, the declaration should not be considered - external. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_LANG_SPECIFIC (decl) - && DECL_NOT_REALLY_EXTERN (decl) - && DECL_EXTERNAL (decl)) - { - DECL_EXTERNAL (decl) = 0; - DECL_NOT_REALLY_EXTERN (decl) = 0; - } -} - - -/******************************************************** tree head and body */ - - -/* Read the body fields of EXPR from STREAM. */ - -static void -pph_in_tree_body (pph_stream *stream, tree expr) -{ - struct lto_input_block *ib = stream->encoder.r.ib; - struct data_in *data_in = stream->encoder.r.data_in; - bool handled_p; - - /* Read the language-independent parts of EXPR's body. */ - streamer_read_tree_body (ib, data_in, expr); - - /* Handle common tree code classes first. */ - handled_p = true; - switch (TREE_CODE_CLASS (TREE_CODE (expr))) - { - case tcc_declaration: - pph_in_tcc_declaration (stream, expr); - break; - - case tcc_type: - pph_in_tcc_type (stream, expr); - break; - - case tcc_constant: - if (TREE_CODE (expr) == PTRMEM_CST) - { - pph_in_tree_common (stream, expr); - PTRMEM_CST_MEMBER (expr) = pph_in_tree (stream); - } - break; - - case tcc_expression: - case tcc_unary: - case tcc_binary: - case tcc_vl_exp: - case tcc_reference: - case tcc_comparison: - case tcc_statement: - /* These tree classes are completely handled by the tree streamer. */ - break; - - default: - handled_p = false; - break; - } - - /* If we've already handled the tree, we are done. */ - if (handled_p) - return; - - /* Only tcc_exceptional tree codes are left to handle. */ - gcc_assert (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_exceptional); - - switch (TREE_CODE (expr)) - { - case STATEMENT_LIST: - { - HOST_WIDE_INT i, num_trees = pph_in_uint (stream); - for (i = 0; i < num_trees; i++) - { - tree stmt = pph_in_tree (stream); - append_to_statement_list_force (stmt, &expr); - } - } - break; - - case OVERLOAD: - pph_in_tree_common (stream, expr); - OVL_FUNCTION (expr) = pph_in_tree (stream); - break; - - case IDENTIFIER_NODE: - if (flag_pph_debug >= 3) - fprintf (pph_logfile, "in identifier %s\n", IDENTIFIER_POINTER (expr)); - IDENTIFIER_NAMESPACE_BINDINGS (expr) = pph_in_cxx_binding (stream); - IDENTIFIER_BINDING (expr) = pph_in_cxx_binding (stream); - IDENTIFIER_TEMPLATE (expr) = pph_in_tree (stream); - IDENTIFIER_LABEL_VALUE (expr) = pph_in_tree (stream); - REAL_IDENTIFIER_TYPE_VALUE (expr) = pph_in_tree (stream); - break; - - case BASELINK: - pph_in_tree_common (stream, expr); - BASELINK_BINFO (expr) = pph_in_tree (stream); - BASELINK_FUNCTIONS (expr) = pph_in_tree (stream); - BASELINK_ACCESS_BINFO (expr) = pph_in_tree (stream); - break; - - case TEMPLATE_INFO: - pph_in_tree_common (stream, expr); - TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (expr) - = pph_in_qual_use_vec (stream); - break; - - case DEFAULT_ARG: - pph_in_tree_common (stream, expr); - DEFARG_TOKENS (expr) = pph_in_token_cache (stream); - DEFARG_INSTANTIATIONS (expr) = pph_in_tree_vec (stream); - break; - - case STATIC_ASSERT: - pph_in_tree_common (stream, expr); - STATIC_ASSERT_CONDITION (expr) = pph_in_tree (stream); - STATIC_ASSERT_MESSAGE (expr) = pph_in_tree (stream); - STATIC_ASSERT_SOURCE_LOCATION (expr) = pph_in_location (stream); - break; - - case ARGUMENT_PACK_SELECT: - pph_in_tree_common (stream, expr); - ARGUMENT_PACK_SELECT_FROM_PACK (expr) = pph_in_tree (stream); - ARGUMENT_PACK_SELECT_INDEX (expr) = pph_in_uint (stream); - break; - - case TRAIT_EXPR: - pph_in_tree_common (stream, expr); - TRAIT_EXPR_TYPE1 (expr) = pph_in_tree (stream); - TRAIT_EXPR_TYPE2 (expr) = pph_in_tree (stream); - TRAIT_EXPR_KIND (expr) = (enum cp_trait_kind) pph_in_uint (stream); - break; - - case LAMBDA_EXPR: - pph_in_tree_common (stream, expr); - LAMBDA_EXPR_LOCATION (expr) = pph_in_location (stream); - LAMBDA_EXPR_CAPTURE_LIST (expr) = pph_in_tree (stream); - LAMBDA_EXPR_THIS_CAPTURE (expr) = pph_in_tree (stream); - LAMBDA_EXPR_RETURN_TYPE (expr) = pph_in_tree (stream); - LAMBDA_EXPR_EXTRA_SCOPE (expr) = pph_in_tree (stream); - LAMBDA_EXPR_DISCRIMINATOR (expr) = pph_in_uint (stream); - break; - - case TREE_VEC: - /* TREE_VECs hold template argument lists. */ - NON_DEFAULT_TEMPLATE_ARGS_COUNT (expr) = pph_in_tree (stream); - break; - - case PLACEHOLDER_EXPR: - TREE_TYPE (expr) = pph_in_tree (stream); - break; - - case TEMPLATE_PARM_INDEX: - pph_in_tree_common (stream, expr); - TEMPLATE_PARM_IDX (expr) = pph_in_uint (stream); - TEMPLATE_PARM_LEVEL (expr) = pph_in_uint (stream); - TEMPLATE_PARM_ORIG_LEVEL (expr) = pph_in_uint (stream); - TEMPLATE_PARM_NUM_SIBLINGS (expr) = pph_in_uint (stream); - TEMPLATE_PARM_DECL (expr) = pph_in_tree (stream); - break; - - case DEFERRED_NOEXCEPT: - DEFERRED_NOEXCEPT_PATTERN (expr) = pph_in_tree (stream); - DEFERRED_NOEXCEPT_ARGS (expr) = pph_in_tree (stream); - break; - - /* TREES ALREADY HANDLED */ - case ERROR_MARK: - case TREE_LIST: - case BLOCK: - case CONSTRUCTOR: - case SSA_NAME: - case TREE_BINFO: - break; - - /* TREES UNIMPLEMENTED */ - case OMP_CLAUSE: - case OPTIMIZATION_NODE: - case TARGET_OPTION_NODE: - fatal_error ("PPH: unimplemented tree node '%s'", - pph_tree_code_text (TREE_CODE (expr))); - break; - - /* TREES UNRECOGNIZED */ - default: - fatal_error ("PPH: unrecognized tree node '%s'", - pph_tree_code_text (TREE_CODE (expr))); - } -} - - -/* Unpack language-dependent bitfields from BP into EXPR. */ - -static void -pph_unpack_value_fields (struct bitpack_d *bp, tree expr) -{ - if (TYPE_P (expr)) - { - TYPE_LANG_FLAG_0 (expr) = bp_unpack_value (bp, 1); - TYPE_LANG_FLAG_1 (expr) = bp_unpack_value (bp, 1); - TYPE_LANG_FLAG_2 (expr) = bp_unpack_value (bp, 1); - TYPE_LANG_FLAG_3 (expr) = bp_unpack_value (bp, 1); - TYPE_LANG_FLAG_4 (expr) = bp_unpack_value (bp, 1); - TYPE_LANG_FLAG_5 (expr) = bp_unpack_value (bp, 1); - TYPE_LANG_FLAG_6 (expr) = bp_unpack_value (bp, 1); - } - else if (DECL_P (expr)) - { - DECL_LANG_FLAG_0 (expr) = bp_unpack_value (bp, 1); - DECL_LANG_FLAG_1 (expr) = bp_unpack_value (bp, 1); - DECL_LANG_FLAG_2 (expr) = bp_unpack_value (bp, 1); - DECL_LANG_FLAG_3 (expr) = bp_unpack_value (bp, 1); - DECL_LANG_FLAG_4 (expr) = bp_unpack_value (bp, 1); - DECL_LANG_FLAG_5 (expr) = bp_unpack_value (bp, 1); - DECL_LANG_FLAG_6 (expr) = bp_unpack_value (bp, 1); - DECL_LANG_FLAG_7 (expr) = bp_unpack_value (bp, 1); - DECL_LANG_FLAG_8 (expr) = bp_unpack_value (bp, 1); - } - - TREE_LANG_FLAG_0 (expr) = bp_unpack_value (bp, 1); - TREE_LANG_FLAG_1 (expr) = bp_unpack_value (bp, 1); - TREE_LANG_FLAG_2 (expr) = bp_unpack_value (bp, 1); - TREE_LANG_FLAG_3 (expr) = bp_unpack_value (bp, 1); - TREE_LANG_FLAG_4 (expr) = bp_unpack_value (bp, 1); - TREE_LANG_FLAG_5 (expr) = bp_unpack_value (bp, 1); - TREE_LANG_FLAG_6 (expr) = bp_unpack_value (bp, 1); -} - - -/* Read a tree header from STREAM and allocate a memory instance for it. - Return the new tree. */ - -static tree -pph_in_tree_header (pph_stream *stream, enum LTO_tags tag) -{ - struct lto_input_block *ib = stream->encoder.r.ib; - struct data_in *data_in = stream->encoder.r.data_in; - struct bitpack_d bp; - tree expr; - enum tree_code code; - - /* Allocate the tree. Handle C++-specific codes first. */ - code = lto_tag_to_tree_code (tag); - if (code == AGGR_INIT_EXPR) - { - unsigned nargs = pph_in_uint (stream); - expr = build_vl_exp (AGGR_INIT_EXPR, nargs + 3); - } - else - expr = streamer_alloc_tree (ib, data_in, tag); - - /* Read the language-independent bitfields for EXPR. */ - bp = streamer_read_tree_bitfields (ib, expr); - - /* Unpack all language-dependent bitfields. */ - pph_unpack_value_fields (&bp, expr); - - return expr; -} - - -/* Read a merge key from STREAM. If the merge key read from STREAM - is not found in *CHAIN, the newly allocated tree is added to it. */ - -static tree -pph_in_merge_key_tree (pph_stream *stream, tree *chain) -{ - struct lto_input_block *ib = stream->encoder.r.ib; - enum pph_record_marker marker; - unsigned image_ix, ix; - tree read_expr, expr; - enum LTO_tags tag; - const char *name; - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_any_tree); - if (marker == PPH_RECORD_END) - return NULL; - else if (pph_is_reference_marker (marker)) - return (tree) pph_cache_find (stream, marker, image_ix, ix, PPH_any_tree); - gcc_assert (marker == PPH_RECORD_START_MERGE_KEY); - - tag = streamer_read_record_start (ib); - - /* Materialize a new node from STREAM. This will also read all the - language-independent bitfields for the new tree. */ - read_expr = pph_in_tree_header (stream, tag); - gcc_assert (pph_tree_is_mergeable (read_expr)); - name = pph_in_string (stream); - - /* Look for a match in CHAIN to READ_EXPR's header. If we found a - match, EXPR will be the existing tree that matches READ_EXPR. - Otherwise, EXPR is the newly allocated READ_EXPR. */ - expr = pph_merge_into_chain (read_expr, name, chain); - - gcc_assert (expr != NULL); - - pph_cache_insert_at (&stream->cache, expr, ix, pph_tree_code_to_tag (expr)); - - if (flag_pph_tracer) - pph_trace_tree (expr, pph_trace_front, - expr == read_expr ? pph_trace_unmerged_key - : pph_trace_merged_key); - - if (DECL_P (expr)) - { - if (TREE_CODE (expr) == NAMESPACE_DECL) - { - cp_binding_level *bl; - if (DECL_LANG_SPECIFIC (expr)) - /* Merging into an existing namespace. */ - bl = NAMESPACE_LEVEL (expr); - else - { - /* This is a new namespace. */ - retrofit_lang_decl (expr); - bl = ggc_alloc_cleared_cp_binding_level (); - NAMESPACE_LEVEL (expr) = bl; - } - pph_in_binding_merge_keys (stream, bl); - } -#if 0 -/* FIXME pph: Disable type merging for the moment. */ - else if (TREE_CODE (expr) == TYPE_DECL) - /* Types are not on a chain. */ - TREE_TYPE (expr) = pph_in_merge_key_tree (stream, NULL); - } - else if (CLASS_TYPE_P (expr)) - { - pph_in_merge_key_chain (stream, &TYPE_FIELDS (expr)); - pph_in_merge_key_chain (stream, &TYPE_METHODS (expr)); - /*FIXME pph: Nested types are broken. - pph_in_binding_table (stream, &CLASSTYPE_NESTED_UTDS (expr)); - pph_in_merge_key_chain (stream, &CLASSTYPE_DECL_LIST (expr)); - */ -#endif - } - - if (flag_pph_tracer) - pph_trace_tree (expr, pph_trace_back, - expr == read_expr ? pph_trace_unmerged_key - : pph_trace_merged_key); - - return expr; -} - - -/* Read and return a tree from STREAM. */ - -tree -pph_in_tree (pph_stream *stream) -{ - struct lto_input_block *ib = stream->encoder.r.ib; - struct data_in *data_in = stream->encoder.r.data_in; - tree expr = NULL; - enum pph_record_marker marker; - unsigned image_ix, ix; - enum LTO_tags tag; - tree saved_expr_chain = NULL; - - /* Read record start and test cache. */ - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_any_tree); - if (marker == PPH_RECORD_END) - return NULL; - else if (pph_is_reference_marker (marker)) - return (tree) pph_cache_find (stream, marker, image_ix, ix, PPH_any_tree); - else if (marker == PPH_RECORD_START || marker == PPH_RECORD_START_NO_CACHE) - { - /* This is a new tree that we need to allocate. Start by - reading the header fields, so we know how to allocate it - (different tree nodes need to be allocated in different - ways). */ - tag = streamer_read_record_start (ib); - gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS); - if (tag == LTO_builtin_decl) - { - /* If we are going to read a built-in function, all we need is - the code and class. */ - gcc_assert (marker == PPH_RECORD_START_NO_CACHE); - return streamer_get_builtin_tree (ib, data_in); - } - else if (tag == lto_tree_code_to_tag (INTEGER_CST)) - { - /* For integer constants we only need the type and its hi/low - words. */ - gcc_assert (marker == PPH_RECORD_START_NO_CACHE); - return streamer_read_integer_cst (ib, data_in); - } - - /* Materialize a new node from STREAM. This will also read all the - language-independent bitfields for the new tree. */ - expr = pph_in_tree_header (stream, tag); - } - - gcc_assert (marker == PPH_RECORD_START - || marker == PPH_RECORD_START_MUTATED - || marker == PPH_RECORD_START_MERGE_BODY); - - if (marker == PPH_RECORD_START_MUTATED) - { - /* When reading a mutated tree, we only need to re-read its - body, the tree itself is already in the cache for another - PPH image. */ - expr = (tree) pph_cache_find (stream, PPH_RECORD_XREF, image_ix, ix, - PPH_any_tree); - - /* Read the internal cache slot where EXPR should be stored at. */ - ix = pph_in_uint (stream); - } - else if (marker == PPH_RECORD_START_MERGE_BODY) - { - /* When reading a merge body, the tree has already been allocated - and added to STREAM's cache. All we have to do now is read - its body. FIXME pph, this read should be a merging read; we are - overwriting EXPR's fields now. */ - expr = (tree) pph_cache_get (&stream->cache, ix); - } - - /* Add the new tree to the cache and read its body. The tree is - added to the cache before we read its body to handle circular - references and references from children nodes. If we are reading - a merge body, then the tree is already in the cache (it was added - by pph_in_merge_key_tree). */ - if (marker != PPH_RECORD_START_MERGE_BODY) - pph_cache_insert_at (&stream->cache, expr, ix, pph_tree_code_to_tag (expr)); - - if (flag_pph_tracer) - pph_trace_tree (expr, pph_trace_front, - marker == PPH_RECORD_START_MERGE_BODY ? pph_trace_merge_body - : marker == PPH_RECORD_START_MUTATED ? pph_trace_mutate - : pph_trace_normal ); - - /* If we are reading a merge body, it means that EXPR is already in - some chain. Given that EXPR may now be in a different location - in the chain, we need to make sure we do not lose it. */ - if (marker == PPH_RECORD_START_MERGE_BODY) - saved_expr_chain = TREE_CHAIN (expr); - - pph_in_tree_body (stream, expr); - - /* Restore TREE_CHAIN if necessary. FIXME pph, we should just not - save TREE_CHAIN for merge bodies. */ - if (marker == PPH_RECORD_START_MERGE_BODY) - TREE_CHAIN (expr) = saved_expr_chain; - - if (flag_pph_tracer) - pph_trace_tree (expr, pph_trace_back, - marker == PPH_RECORD_START_MERGE_BODY ? pph_trace_merge_body - : marker == PPH_RECORD_START_MUTATED ? pph_trace_mutate - : pph_trace_normal ); - - /* If needed, sign the recently materialized tree to detect - mutations. Note that we only need to compute signatures - if we are generating a PPH image. That is the only time - where we need to determine whether a tree read from PPH - was updated while parsing the header file that we are - currently generating. */ - if (pph_writer_enabled_p () && tree_needs_signature (expr)) - { - unsigned crc; - size_t nbytes; - crc = pph_get_signature (expr, &nbytes); - pph_cache_sign (&stream->cache, ix, crc, nbytes); - } - - return expr; -} - - -/************************************************************* file contents */ - - -/* Read a symbol table marker from STREAM. */ - -static inline enum pph_symtab_action -pph_in_symtab_action (pph_stream *stream) -{ - enum pph_symtab_action m = (enum pph_symtab_action) pph_in_uchar (stream); - gcc_assert (m == PPH_SYMTAB_DECLARE || m == PPH_SYMTAB_EXPAND); - return m; -} - - -/* Read and return a callgraph node from STREAM. If this is the first - time we read this node, add it to the callgraph. */ - -static struct cgraph_node * -pph_in_cgraph_node (pph_stream *stream) -{ - enum pph_record_marker marker; - unsigned image_ix, ix; - struct cgraph_node *node; - tree fndecl; - struct bitpack_d bp; - - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_cgraph_node); - if (marker == PPH_RECORD_END) - return NULL; - else if (pph_is_reference_marker (marker)) - return (struct cgraph_node *) pph_cache_find (stream, marker, image_ix, - ix, PPH_cgraph_node); - - fndecl = pph_in_tree (stream); - ALLOC_AND_REGISTER (&stream->cache, ix, PPH_cgraph_node, node, - cgraph_get_create_node (fndecl)); - - node->origin = pph_in_cgraph_node (stream); - node->nested = pph_in_cgraph_node (stream); - node->next_nested = pph_in_cgraph_node (stream); - node->next_needed = pph_in_cgraph_node (stream); - node->next_sibling_clone = pph_in_cgraph_node (stream); - node->prev_sibling_clone = pph_in_cgraph_node (stream); - node->clones = pph_in_cgraph_node (stream); - node->clone_of = pph_in_cgraph_node (stream); - node->same_comdat_group = pph_in_cgraph_node (stream); - gcc_assert (node->call_site_hash == NULL); - node->former_clone_of = pph_in_tree (stream); - gcc_assert (node->aux == NULL); - gcc_assert (VEC_empty (ipa_opt_pass, node->ipa_transforms_to_apply)); - - gcc_assert (VEC_empty (ipa_ref_t, node->ref_list.references)); - gcc_assert (VEC_empty (ipa_ref_ptr, node->ref_list.refering)); - - gcc_assert (node->local.lto_file_data == NULL); - bp = pph_in_bitpack (stream); - node->local.local = bp_unpack_value (&bp, 1); - node->local.externally_visible = bp_unpack_value (&bp, 1); - node->local.finalized = bp_unpack_value (&bp, 1); - node->local.can_change_signature = bp_unpack_value (&bp, 1); - node->local.redefined_extern_inline = bp_unpack_value (&bp, 1); - - node->global.inlined_to = pph_in_cgraph_node (stream); - - node->rtl.preferred_incoming_stack_boundary = pph_in_uint (stream); - - gcc_assert (VEC_empty (ipa_replace_map_p, node->clone.tree_map)); - node->thunk.fixed_offset = pph_in_uhwi (stream); - node->thunk.virtual_value = pph_in_uhwi (stream); - node->thunk.alias = pph_in_tree (stream); - bp = pph_in_bitpack (stream); - node->thunk.this_adjusting = bp_unpack_value (&bp, 1); - node->thunk.virtual_offset_p = bp_unpack_value (&bp, 1); - node->thunk.thunk_p = bp_unpack_value (&bp, 1); - - node->count = pph_in_uhwi (stream); - node->count_materialization_scale = pph_in_uint (stream); - - bp = pph_in_bitpack (stream); - node->needed = bp_unpack_value (&bp, 1); - node->address_taken = bp_unpack_value (&bp, 1); - node->abstract_and_needed = bp_unpack_value (&bp, 1); - node->reachable = bp_unpack_value (&bp, 1); - node->reachable_from_other_partition = bp_unpack_value (&bp, 1); - node->lowered = bp_unpack_value (&bp, 1); - node->analyzed = bp_unpack_value (&bp, 1); - node->in_other_partition = bp_unpack_value (&bp, 1); - node->process = bp_unpack_value (&bp, 1); - node->alias = bp_unpack_value (&bp, 1); - node->same_body_alias = bp_unpack_value (&bp, 1); - node->frequency = (enum node_frequency) bp_unpack_value (&bp, 2); - node->only_called_at_startup = bp_unpack_value (&bp, 1); - node->only_called_at_exit = bp_unpack_value (&bp, 1); - - return node; -} - - -/* Have we already emitted this DECL? */ - -static bool -pph_decl_already_emitted (tree decl) -{ - static struct pointer_set_t *emitted_syms = NULL; - gcc_assert (decl != NULL); - if (!emitted_syms) - emitted_syms = pointer_set_create (); - return pointer_set_insert (emitted_syms, decl) != 0; -} - - -/* Have we already emitted this cgraph NODE? */ - -static bool -pph_node_already_emitted (struct cgraph_node *node) -{ - static struct pointer_set_t *emitted_nodes = NULL; - gcc_assert (node != NULL); - if (!emitted_nodes) - emitted_nodes = pointer_set_create (); - return pointer_set_insert (emitted_nodes, node) != 0; -} - - -/* 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_action action; - tree decl; - bool top_level, at_end; - - action = pph_in_symtab_action (stream); - decl = pph_in_tree (stream); - if (action == PPH_SYMTAB_DECLARE) - { - struct bitpack_d bp; - bp = pph_in_bitpack (stream); - top_level = bp_unpack_value (&bp, 1); - at_end = bp_unpack_value (&bp, 1); - if (pph_decl_already_emitted (decl)) - continue; - - cp_rest_of_decl_compilation (decl, top_level, at_end); - } - else if (action == PPH_SYMTAB_EXPAND) - { - struct cgraph_node *node; - - pph_in_struct_function (stream, decl); - node = pph_in_cgraph_node (stream); - if (node && node->local.finalized) - { - if (pph_node_already_emitted (node)) - continue; - - /* Since the writer had finalized this cgraph node, - we have to re-play its actions. To do that, we need - to clear the finalized and reachable bits in the - node, otherwise cgraph_finalize_function will toss - out this node. */ - node->local.finalized = false; - node->reachable = false; - cgraph_finalize_function (node->decl, true); - } - } - else - gcc_unreachable (); - } -} - - -/* Wrap a macro DEFINITION for printing in an error. */ - -static char * -wrap_macro_def (const char *definition) -{ - char *string; - if (definition) - { - size_t length; - length = strlen (definition); - string = (char *) xmalloc (length+3); - string[0] = '"'; - strcpy (string + 1, definition); - string[length + 1] = '"'; - string[length + 2] = '\0'; - } - else - string = xstrdup ("undefined"); - return string; -} - - -/* Report a macro validation error in FILENAME for macro IDENT, - which should have the value EXPECTED but actually had the value FOUND. */ - -static void -report_validation_error (const char *filename, - const char *ident, const char *found, - const char *before, const char *after) -{ - char* quote_found = wrap_macro_def (found); - char* quote_before = wrap_macro_def (before); - char* quote_after = wrap_macro_def (after); - warning (0, "PPH file %s fails macro validation, " - "%s is %s and should be %s or %s\n", - filename, ident, quote_found, quote_before, quote_after); - free (quote_found); - free (quote_before); - free (quote_after); -} - - -/* Load the IDENTIFIERS for a hunk from a STREAM. */ - -static void -pph_in_identifiers (pph_stream *stream, cpp_idents_used *identifiers) -{ - unsigned int j; - unsigned int max_ident_len, max_value_len, num_entries; - unsigned int ident_len, before_len, after_len; - - max_ident_len = pph_in_uint (stream); - identifiers->max_ident_len = max_ident_len; - max_value_len = pph_in_uint (stream); - identifiers->max_value_len = max_value_len; - num_entries = pph_in_uint (stream); - identifiers->num_entries = num_entries; - identifiers->entries = XCNEWVEC (cpp_ident_use, num_entries); - identifiers->strings = XCNEW (struct obstack); - - /* Strings need no alignment. */ - _obstack_begin (identifiers->strings, 0, 0, - (void *(*) (long)) xmalloc, - (void (*) (void *)) free); - obstack_alignment_mask (identifiers->strings) = 0; - /* FIXME pph: We probably need to free all these things somewhere. */ - - /* Read the identifiers in HUNK. */ - for (j = 0; j < num_entries; ++j) - { - const char *s; - identifiers->entries[j].used_by_directive = pph_in_uint (stream); - identifiers->entries[j].expanded_to_text = pph_in_uint (stream); - s = pph_in_string (stream); - gcc_assert (s); - ident_len = strlen (s); - identifiers->entries[j].ident_len = ident_len; - identifiers->entries[j].ident_str = - (const char *) obstack_copy0 (identifiers->strings, s, ident_len); - - s = pph_in_string (stream); - if (s) - { - before_len = strlen (s); - identifiers->entries[j].before_len = before_len; - identifiers->entries[j].before_str = (const char *) - obstack_copy0 (identifiers->strings, s, before_len); - } - else - { - /* The identifier table expects NULL entries to have - a length of -1U. */ - identifiers->entries[j].before_len = -1U; - identifiers->entries[j].before_str = NULL; - } - - s = pph_in_string (stream); - if (s) - { - after_len = strlen (s); - identifiers->entries[j].after_len = after_len; - identifiers->entries[j].after_str = (const char *) - obstack_copy0 (identifiers->strings, s, after_len); - } - else - { - /* The identifier table expects NULL entries to have - a length of -1U. */ - identifiers->entries[j].after_len = -1U; - identifiers->entries[j].after_str = NULL; - } - } -} - - -/* Read global bindings from STREAM into scope_chain->bindings. Note - that this does not call pph_in_binding_level because that would - overwrite the fields merged by pph_in_merge_keys. */ - -static void -pph_in_global_binding (pph_stream *stream) -{ - unsigned image_ix, ix; - enum pph_record_marker marker; - cp_binding_level *bl; - - bl = scope_chain->bindings; - marker = pph_in_start_record (stream, &image_ix, &ix, PPH_cp_binding_level); - gcc_assert (marker != PPH_RECORD_END); - - if (pph_is_reference_marker (marker)) - { - /* If we found a reference to BL, it should be the same. This happens - when we pull BL from a nested PPH image. */ - cp_binding_level *other_bl; - other_bl = (cp_binding_level *) pph_cache_find (stream, marker, image_ix, - ix, PPH_cp_binding_level); - gcc_assert (other_bl == bl); - } - else - { - /* Note that here we do not allocate a new binding level. Since we - are reading into the global one, we register the current - scope_chain->bindings into the cache. Otherwise, we would be - associating these symbols into the global binding level from - STREAM, instead of the current translation unit. */ - pph_cache_insert_at (&stream->cache, bl, ix, PPH_cp_binding_level); - } - - /* Read the merge keys and merge them into the current compilation - context. Since we have registered scope_chain->bindings in the - same slot IX that the writer used, the trees read now will be - bound to scope_chain->bindings. */ - pph_in_binding_merge_keys (stream, bl); - pph_in_binding_merge_bodies_1 (stream, bl); -} - - -/* Helper for pph_read_file. Read contents of PPH file in STREAM. */ - -static void -pph_read_file_1 (pph_stream *stream) -{ - bool verified; - cpp_ident_use *bad_use; - const char *cur_def; - cpp_idents_used idents_used; - tree t, file_keyed_classes, file_static_aggregates; - unsigned i; - VEC(tree,gc) *file_unemitted_tinfo_decls; - source_location cpp_token_replay_loc; - - /* If we have read STREAM before, we do not need to re-read the rest - of its body. We only needed to read its line table. */ - if (stream->in_memory_p) - return; - - if (flag_pph_tracer >= 1) - fprintf (pph_logfile, "PPH: Reading %s\n", stream->name); - - /* Read in STREAM's line table and merge it in the current line table. - At the same time, read in includes in the order they were originally - read. */ - cpp_token_replay_loc = pph_in_line_table_and_includes (stream); - - /* Read all the identifiers and pre-processor symbols in the global - namespace. */ - pph_in_identifiers (stream, &idents_used); - - /* FIXME pph: This validation is weak. */ - verified = cpp_lt_verify_1 (parse_in, &idents_used, &bad_use, &cur_def, true); - if (!verified) - report_validation_error (stream->name, bad_use->ident_str, cur_def, - bad_use->before_str, bad_use->after_str); - - /* Re-instantiate all the pre-processor symbols defined by STREAM. Force - their source_location to line 1 / column 0 of the file they were included - in. This avoids shifting all of the line_table's locations as we would by - adding locations which wouldn't be there in the non-pph compile; thus - working towards an identical line_table in pph and non-pph. */ - cpp_lt_replay (parse_in, &idents_used, &cpp_token_replay_loc); - - /* Read the bindings from STREAM. */ - pph_in_global_binding (stream); - - /* 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); - - file_unemitted_tinfo_decls = pph_in_tree_vec (stream); - FOR_EACH_VEC_ELT (tree, file_unemitted_tinfo_decls, i, t) - VEC_safe_push (tree, gc, unemitted_tinfo_decls, t); - - pph_in_pending_templates_list (stream); - pph_in_spec_entry_tables (stream); - - file_static_aggregates = pph_in_tree (stream); - static_aggregates = chainon (file_static_aggregates, static_aggregates); - - /* Read and process the symbol table. */ - pph_in_symtab (stream); - - /* Mark this file as read. If other images need to access its contents, - we will not need to actually read it again. */ - pph_mark_stream_read (stream); - - if (flag_pph_dump_tree) - pph_dump_namespace (pph_logfile, global_namespace); -} - - -/* Read PPH file FILENAME. Return the in-memory pph_stream instance. */ - -pph_stream * -pph_read_file (const char *filename) -{ - pph_stream *stream = pph_stream_open (filename, "rb"); - if (stream == NULL) - fatal_error ("cannot open PPH file %s for reading: %m", filename); - - pph_read_file_1 (stream); - - return stream; -} - - -/********************************************************* stream operations */ - - -/* Initialize the reader. */ - -void -pph_reader_init (void) -{ - merge_toc = htab_create (551, htab_merge_key_hash, htab_merge_key_eq, free); -} - - -/* Finalize the reader. */ - -void -pph_reader_finish (void) -{ - htab_delete (merge_toc); -} Index: gcc/cp/pt.c =================================================================== --- gcc/cp/pt.c (revision 181815) +++ gcc/cp/pt.c (working copy) @@ -46,7 +46,6 @@ along with GCC; see the file COPYING3. #include "timevar.h" #include "tree-iterator.h" #include "vecprim.h" -#include "pph-streamer.h" /* The type of functions taking a tree, and some additional data, and returning an int. */ Index: gcc/cp/pph-streamer.c =================================================================== --- gcc/cp/pph-streamer.c (revision 181815) +++ gcc/cp/pph-streamer.c (working copy) @@ -1,674 +0,0 @@ -/* Routines for streaming PPH data. - Copyright (C) 2011 Free Software Foundation, Inc. - Contributed by Diego Novillo . - - This file is part of GCC. - - GCC is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - GCC is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "pph.h" -#include "tree.h" -#include "langhooks.h" -#include "tree-iterator.h" -#include "tree-pretty-print.h" -#include "lto-streamer.h" -#include "pph-streamer.h" -#include "tree-pass.h" -#include "version.h" -#include "cppbuiltin.h" -#include "streamer-hooks.h" - -/* List of PPH images opened for reading. Images opened during #include - processing and opened from pph_in_includes cannot be closed - immediately after reading, because the pickle cache contained in - them may be referenced from other images. We delay closing all of - them until the end of parsing (when pph_streamer_finish is called). */ -static VEC(pph_stream_ptr, heap) *pph_read_images = NULL; - -/* A cache of pre-loaded common tree nodes. */ -static pph_cache *pph_preloaded_cache; - -/* Pre-load common tree nodes into CACHE. These nodes are always built by the - front end, so there is no need to pickle them. */ - -static void -pph_cache_preload (pph_cache *cache) -{ - unsigned i; - - for (i = itk_char; i < itk_none; i++) - pph_cache_add (cache, integer_types[i], NULL, - pph_tree_code_to_tag (integer_types[i])); - - for (i = 0; i < TYPE_KIND_LAST; i++) - pph_cache_add (cache, sizetype_tab[i], NULL, - pph_tree_code_to_tag (sizetype_tab[i])); - - /* global_trees[] can have NULL entries in it. Skip them. */ - for (i = 0; i < TI_MAX; i++) - if (global_trees[i]) - pph_cache_add (cache, global_trees[i], NULL, - pph_tree_code_to_tag (global_trees[i])); - - /* c_global_trees[] can have NULL entries in it. Skip them. */ - for (i = 0; i < CTI_MAX; i++) - if (c_global_trees[i]) - pph_cache_add (cache, c_global_trees[i], NULL, - pph_tree_code_to_tag (c_global_trees[i])); - - /* cp_global_trees[] can have NULL entries in it. Skip them. */ - for (i = 0; i < CPTI_MAX; i++) - { - /* Also skip trees which are generated while parsing. */ - if (i == CPTI_KEYED_CLASSES) - continue; - - if (cp_global_trees[i]) - pph_cache_add (cache, cp_global_trees[i], NULL, - pph_tree_code_to_tag (cp_global_trees[i])); - } - - /* Add other well-known nodes that should always be taken from the - current compilation context. */ - pph_cache_add (cache, global_namespace, NULL, - pph_tree_code_to_tag (global_namespace)); - pph_cache_add (cache, DECL_CONTEXT (global_namespace), NULL, - pph_tree_code_to_tag (DECL_CONTEXT (global_namespace))); -} - - -/* Callback for writing ASTs to a stream. Write EXPR to the PPH stream - in OB. */ - -static void -pph_write_tree (struct output_block *ob, tree expr, bool ref_p ATTRIBUTE_UNUSED) -{ - pph_out_tree ((pph_stream *) ob->sdata, expr); -} - - -/* Callback for reading ASTs from a stream. Instantiate and return a - new tree from the PPH stream in DATA_IN. */ - -static tree -pph_read_tree (struct lto_input_block *ib ATTRIBUTE_UNUSED, - struct data_in *data_in) -{ - return pph_in_tree ((pph_stream *) data_in->sdata); -} - - -/* Callback for streamer_hooks.input_location. An offset is applied to - the location_t read in according to the properties of the merged - line_table. IB and DATA_IN are as in lto_input_location. This function - should only be called after pph_in_and_merge_line_table was called as - we expect pph_loc_offset to be set. */ - -static location_t -pph_input_location (struct lto_input_block *ib ATTRIBUTE_UNUSED, - struct data_in *data_in) -{ - return pph_in_location ((pph_stream *) data_in->sdata); -} - - -/* Callback for streamer_hooks.output_location. Output the LOC directly, - an offset will be applied on input after rebuilding the line_table. - OB and LOC are as in lto_output_location. */ - -static void -pph_output_location (struct output_block *ob, location_t loc) -{ - pph_out_location ((pph_stream *) ob->sdata, loc); -} - - -/* Initialize all the streamer hooks used for streaming ASTs. */ - -static void -pph_hooks_init (void) -{ - streamer_hooks_init (); - streamer_hooks.write_tree = pph_write_tree; - streamer_hooks.read_tree = pph_read_tree; - streamer_hooks.input_location = pph_input_location; - streamer_hooks.output_location = pph_output_location; -} - - -/* Initialize an empty pickle CACHE. */ - -static void -pph_cache_init (pph_cache *cache) -{ - cache->v = NULL; - cache->m = pointer_map_create (); -} - - -/* Initialize the pre-loaded cache. This contains all the common - tree nodes built by the compiler on startup. */ - -static void -pph_init_preloaded_cache (void) -{ - pph_preloaded_cache = XCNEW (pph_cache); - pph_cache_init (pph_preloaded_cache); - pph_cache_preload (pph_preloaded_cache); -} - - -/* Initialize the streamer. */ - -void -pph_streamer_init (void) -{ - pph_hooks_init (); - pph_init_preloaded_cache (); -} - - -/* Finalize the streamer. */ - -void -pph_streamer_finish (void) -{ - unsigned i; - pph_stream *image; - - /* Finalize the writer. */ - pph_writer_finish (); - - /* Finalize the reader. */ - pph_reader_finish (); - - /* Close any images read during parsing. */ - FOR_EACH_VEC_ELT (pph_stream_ptr, pph_read_images, i, image) - pph_stream_close (image); - - VEC_free (pph_stream_ptr, heap, pph_read_images); -} - - -/* If FILENAME has already been read, return the stream associated with it. */ - -static pph_stream * -pph_find_stream_for (const char *filename) -{ - pph_stream *include; - unsigned i; - - /* FIXME pph, implement a hash map to avoid this linear search. */ - FOR_EACH_VEC_ELT (pph_stream_ptr, pph_read_images, i, include) - if (strcmp (include->name, filename) == 0) - return include; - - return NULL; -} - - -/* Add STREAM to the list of read images. */ - -void -pph_mark_stream_read (pph_stream *stream) -{ - stream->in_memory_p = true; - VEC_safe_push (pph_stream_ptr, heap, pph_read_images, stream); -} - - -/* Create a new PPH stream to be stored on the file called NAME. - MODE is passed to fopen directly. */ - -pph_stream * -pph_stream_open (const char *name, const char *mode) -{ - pph_stream *stream; - FILE *f; - - /* If we have already opened a PPH stream named NAME, just return - its associated stream. */ - stream = pph_find_stream_for (name); - if (stream) - { - gcc_assert (stream->in_memory_p); - return stream; - } - - f = fopen (name, mode); - if (!f) - return NULL; - - stream = XCNEW (pph_stream); - stream->file = f; - stream->name = xstrdup (name); - stream->write_p = (strchr (mode, 'w') != NULL); - pph_cache_init (&stream->cache); - stream->preloaded_cache = pph_preloaded_cache; - if (stream->write_p) - pph_init_write (stream); - else - pph_init_read (stream); - - return stream; -} - - - -/* Close PPH stream STREAM. */ - -void -pph_stream_close (pph_stream *stream) -{ - /* STREAM can be NULL if it could not be properly opened. An error - has already been emitted, so avoid crashing here. */ - if (stream == NULL) - return; - - if (flag_pph_tracer >= 1) - fprintf (pph_logfile, "PPH: Closing %s\n", stream->name); - - /* If we were writing to STREAM, flush all the memory buffers. This - does the actual writing of all the pickled data structures. */ - if (stream->write_p) - pph_flush_buffers (stream); - - fclose (stream->file); - - /* Deallocate all memory used. */ - stream->file = NULL; - VEC_free (pph_cache_entry, heap, stream->cache.v); - pointer_map_destroy (stream->cache.m); - VEC_free (pph_symtab_entry, heap, stream->symtab.v); - VEC_free (pph_stream_ptr, heap, stream->includes); - - if (stream->write_p) - { - destroy_output_block (stream->encoder.w.ob); - free (stream->encoder.w.decl_state_stream); - lto_delete_out_decl_state (stream->encoder.w.out_state); - } - else - { - unsigned i; - - free (stream->encoder.r.ib); - lto_data_in_delete (stream->encoder.r.data_in); - for (i = 0; i < PPH_NUM_SECTIONS; i++) - free (stream->encoder.r.pph_sections[i]); - free (stream->encoder.r.pph_sections); - free (stream->encoder.r.file_data); - } - - free (stream); -} - - -/* Add INCLUDE, and the images included by it, to the list of files - included by STREAM. */ - -void -pph_add_include (pph_stream *stream, pph_stream *include) -{ - pph_stream *include_child; - unsigned i; - - include->parent = stream; - VEC_safe_push (pph_stream_ptr, heap, stream->includes, include); - FOR_EACH_VEC_ELT (pph_stream_ptr, include->includes, i, include_child) - VEC_safe_push (pph_stream_ptr, heap, stream->includes, include_child); -} - - -/* Trace a record MARKER and TAG. */ - -static const char *marker_strings[] = -{ - "PPH_RECORD_START", - "PPH_RECORD_START_NO_CACHE", - "PPH_RECORD_START_MUTATED", - "PPH_RECORD_START_MERGE_KEY", - "PPH_RECORD_START_MERGE_BODY", - "PPH_RECORD_END", - "PPH_RECORD_IREF", - "PPH_RECORD_XREF", - "PPH_RECORD_PREF" -}; - -static const char *tag_strings[] = -{ - "PPH_any_tree", - "PPH_binding_entry", - "PPH_binding_table", - "PPH_cgraph_node", - "PPH_cp_binding_level", - "PPH_cp_class_binding", - "PPH_cp_label_binding", - "PPH_cxx_binding", - "PPH_function", - "PPH_lang_decl", - "PPH_lang_type", - "PPH_language_function", - "PPH_sorted_fields_type" -}; - -void -pph_trace_marker (enum pph_record_marker marker, enum pph_tag tag) -{ - fprintf (pph_logfile, "marker "); - if (PPH_RECORD_START <= marker && marker <= PPH_RECORD_PREF) - fprintf (pph_logfile, "%s", marker_strings[marker - PPH_RECORD_START]); - else - fprintf (pph_logfile, "unknown"); - fprintf (pph_logfile, " tag "); - if (tag == PPH_null) - fprintf (pph_logfile, "PPH_null\n"); - else if (tag < PPH_any_tree) - fprintf (pph_logfile, "%s\n", tree_code_name[tag]); - else if (tag < PPH_NUM_TAGS) - fprintf (pph_logfile, "%s\n", tag_strings[tag - PPH_any_tree]); - else - fprintf (pph_logfile, "unknown\n"); -} - - -/* Print tracing information for a possibly MERGEABLE tree T. */ - -void -pph_trace_tree (tree t, enum pph_trace_end end, enum pph_trace_kind kind) -{ - char end_char, kind_char, decl_char; - bool is_merge, is_decl; - bool emit = false; - - switch (kind) - { - case pph_trace_key_out: - kind_char = 'K'; - is_merge = true; - break; - case pph_trace_unmerged_key: - kind_char = 'U'; - is_merge = true; - break; - case pph_trace_merged_key: - kind_char = 'M'; - is_merge = true; - break; - case pph_trace_merge_body: - kind_char = 'B'; - is_merge = true; - break; - case pph_trace_mutate: - kind_char = '='; - is_merge = false; - break; - case pph_trace_normal: - kind_char = '.'; - is_merge = false; - break; - default: - kind_char = '?'; - is_merge = false; - } - - end_char = end == pph_trace_front ? '{' : '}'; - - is_decl = DECL_P (t); - if (is_decl) - decl_char = 'D'; - else if (TYPE_P (t)) - decl_char = 'T'; - else - decl_char = '.'; - - if (is_merge && is_decl && flag_pph_tracer >= 2) - emit = true; - else if ((is_merge || is_decl) && flag_pph_tracer >= 3) - emit = true; - else if (!EXPR_P (t) && flag_pph_tracer >= 4) - emit = true; - - if (emit) - { - fprintf (pph_logfile, "PPH: %c%c%c ", end_char, kind_char, decl_char); - if (kind == pph_trace_unmerged_key || end == pph_trace_front) - fprintf (pph_logfile, "%s -------\n", - pph_tree_code_text (TREE_CODE (t))); - else - pph_dump_tree_name (pph_logfile, t, 0); - } -} - - -/* Insert DATA in CACHE at slot IX. TAG represents the data structure - pointed-to by DATA. As a restriction to prevent stomping on cache - entries, this will not allow inserting into the same slot more than - once. Return the newly added entry. */ - -pph_cache_entry * -pph_cache_insert_at (pph_cache *cache, void *data, unsigned ix, - enum pph_tag tag) -{ - void **map_slot; - pph_cache_entry e = { data, tag, false, 0, 0 }; - - map_slot = pointer_map_insert (cache->m, data); - - /* We should not be trying to insert the same data more than once. - This indicates that the same DATA pointer has been given two - different cache locations. This almost always points to a - problem with merging data structures read from different files. */ - gcc_assert (*map_slot == NULL); - - *map_slot = (void *) (intptr_t) ix; - if (ix + 1 > VEC_length (pph_cache_entry, cache->v)) - VEC_safe_grow_cleared (pph_cache_entry, heap, cache->v, ix + 1); - VEC_replace (pph_cache_entry, cache->v, ix, &e); - - return pph_cache_get_entry (cache, ix); -} - - -/* If DATA exists in CACHE, return the cache entry holding it. If - IX_P is not NULL, store the cache slot where DATA resides in *IX_P - (or (unsigned)-1 if DATA is not found). If CACHE is NULL use - pph_preloaded_cache. - - If a cache hit is found, the data type tag for the entry must match - TAG. */ - -pph_cache_entry * -pph_cache_lookup (pph_cache *cache, void *data, unsigned *ix_p, - enum pph_tag tag) -{ - void **map_slot; - unsigned ix; - pph_cache_entry *e; - - if (cache == NULL) - cache = pph_preloaded_cache; - - map_slot = pointer_map_contains (cache->m, data); - if (map_slot == NULL) - { - e = NULL; - ix = (unsigned) -1; - } - else - { - intptr_t slot_ix = (intptr_t) *map_slot; - gcc_assert (slot_ix == (intptr_t)(unsigned) slot_ix); - ix = (unsigned) slot_ix; - e = pph_cache_get_entry (cache, ix); - - /* If the caller is looking for a specific TAG, make sure - it matches the tag we pulled from the cache. */ - if (tag != PPH_null) - gcc_assert (tag == e->tag); - } - - if (ix_p) - *ix_p = ix; - - return e; -} - - -/* Return true if DATA is in the pickle cache of one of STREAM's - included images. TAG is the expected data type TAG for data. - - If DATA is found: - - the index for INCLUDE_P into IMAGE->INCLUDES is returned in - *INCLUDE_IX_P (if INCLUDE_IX_P is not NULL), - - the cache slot index for DATA into *INCLUDE_P's pickle cache - is returned in *IX_P (if IX_P is not NULL), and, - - the function returns true. - - If DATA is not found: - - *INCLUDE_IX_P is set to -1 (if INCLUDE_IX_P is not NULL), - - *IX_P is set to -1 (if IX_P is not NULL), and, - - the function returns false. */ - -pph_cache_entry * -pph_cache_lookup_in_includes (pph_stream *stream, void *data, - unsigned *include_ix_p, unsigned *ix_p, - enum pph_tag tag) -{ - unsigned include_ix, ix; - pph_stream *include; - pph_cache_entry *e; - - /* When searching the external caches, do not try to find a match - for TAG. Since this is an external cache, the parser may have - re-allocated the object pointed by DATA (e.g., when merging - decls). In this case, TAG will be different from the tag we find - in the cache, so instead of ICEing, we ignore the match to force - the caller to pickle DATA. */ - e = NULL; - FOR_EACH_VEC_ELT (pph_stream_ptr, stream->includes, include_ix, include) - { - e = pph_cache_lookup (&include->cache, data, &ix, PPH_null); - if (e) - { - /* Only consider DATA found if its data type matches TAG. If - not, it means that the object pointed by DATA has changed, - so DATA will need to be re-pickled. */ - if (e->tag != tag) - e = NULL; - break; - } - } - - if (e == NULL) - { - include_ix = ix = (unsigned) -1; - ix = (unsigned) -1; - } - - if (include_ix_p) - *include_ix_p = include_ix; - - if (ix_p) - *ix_p = ix; - - return e; -} - - -/* Add pointer DATA with data type TAG to CACHE. If IX_P is not NULL, - on exit *IX_P will contain the slot number where DATA is stored. - Return the newly added entry. */ - -pph_cache_entry * -pph_cache_add (pph_cache *cache, void *data, unsigned *ix_p, enum pph_tag tag) -{ - unsigned ix; - pph_cache_entry *e; - - e = pph_cache_lookup (cache, data, &ix, tag); - if (e == NULL) - { - ix = VEC_length (pph_cache_entry, cache->v); - e = pph_cache_insert_at (cache, data, ix, tag); - } - - if (ix_p) - *ix_p = ix; - - return e; -} - - -/* Associate signature CRC with the first NBYTES of the area memory - pointed to by slot IX of CACHE. */ - -void -pph_cache_sign (pph_cache *cache, unsigned ix, unsigned crc, size_t nbytes) -{ - pph_cache_entry *e; - - /* Needed because xcrc32 requires an int to specify the length but - tree_size returns size_t values. */ - gcc_assert (nbytes == (size_t) (int) nbytes); - - e = pph_cache_get_entry (cache, ix); - e->crc = crc; - e->crc_nbytes = nbytes; -} - - -/* Return a signature for tree T. Store the length of the signed area - in *NBYTES_P. */ - -unsigned -pph_get_signature (tree t, size_t *nbytes_p) -{ - tree prev_chain = NULL; - rtx prev_rtl = NULL; - int prev_used; - size_t nbytes; - unsigned crc; - - nbytes = tree_size (t); - if (nbytes_p) - *nbytes_p = nbytes; - - /* Preserve the value of the fields not included in the signature. */ - prev_chain = (DECL_P (t)) ? DECL_CHAIN (t) : NULL; - prev_rtl = (HAS_RTL_P (t)) ? DECL_RTL_IF_SET (t) : NULL; - prev_used = TREE_USED (t); - - /* Clear the fields not included in the signature. */ - if (DECL_P (t)) - DECL_CHAIN (t) = NULL; - if (HAS_RTL_P (t)) - SET_DECL_RTL (t, NULL); - TREE_USED (t) = 0; - - crc = xcrc32 ((const unsigned char *) t, nbytes, -1); - - /* Restore fields we did not include in the signature. */ - if (DECL_P (t)) - DECL_CHAIN (t) = prev_chain; - if (HAS_RTL_P (t)) - SET_DECL_RTL (t, prev_rtl); - TREE_USED (t) = prev_used; - - return crc; -} Index: gcc/cp/config-lang.in =================================================================== --- gcc/cp/config-lang.in (revision 181815) +++ gcc/cp/config-lang.in (working copy) @@ -30,4 +30,4 @@ compilers="cc1plus\$(exeext)" target_libs="target-libstdc++-v3" -gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/pph.h \$(srcdir)/cp/pph.c \$(srcdir)/cp/except.c" +gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/pph.h \$(srcdir)/cp/pph-core.c \$(srcdir)/cp/except.c" Index: gcc/cp/pph-streamer-out.c =================================================================== --- gcc/cp/pph-streamer-out.c (revision 181815) +++ gcc/cp/pph-streamer-out.c (working copy) @@ -1,2629 +0,0 @@ -/* Routines for writing PPH data. - Copyright (C) 2011 Free Software Foundation, Inc. - Contributed by Diego Novillo . - - This file is part of GCC. - - GCC is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - GCC is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "pph.h" -#include "tree.h" -#include "langhooks.h" -#include "tree-iterator.h" -#include "tree-pretty-print.h" -#include "lto-streamer.h" -#include "pph-streamer.h" -#include "tree-pass.h" -#include "version.h" -#include "cppbuiltin.h" -#include "cgraph.h" -#include "parser.h" - - -/****************************************************** forward declarations */ - - -/* Forward declarations to avoid circular references. */ -static void pph_out_merge_key_tree (pph_stream *, tree); - - -/***************************************************** stream initialization */ - - -/* PPH stream that we are currently generating. FIXME pph, this - global is needed because we call back from various parts of the - compiler that do not know about PPH (e.g., some LTO callbacks, - cp_rest_of_decl_compilation). */ -static pph_stream *pph_out_stream = NULL; - - -/* Initialize buffers and tables in STREAM for writing. */ - -void -pph_init_write (pph_stream *stream) -{ - stream->encoder.w.out_state = lto_new_out_decl_state (); - lto_push_out_decl_state (stream->encoder.w.out_state); - stream->encoder.w.decl_state_stream = XCNEW (struct lto_output_stream); - stream->encoder.w.ob = create_output_block (LTO_section_decls); - - /* Associate STREAM with stream->encoder.w.ob so we can recover it from the - streamer hooks. */ - stream->encoder.w.ob->sdata = (void *) stream; -} - - -/* Initialize the PPH writer. */ - -void -pph_writer_init (void) -{ - gcc_assert (pph_out_stream == NULL); - pph_out_stream = pph_stream_open (pph_out_file, "wb"); - if (pph_out_stream == NULL) - fatal_error ("Cannot open PPH file %s for writing: %m", pph_out_file); -} - - -/********************************************************** primitive values */ - - -/* Write an unsigned char VALUE to STREAM. */ - -static void -pph_out_uchar (pph_stream *stream, unsigned char value) -{ - streamer_write_char_stream (stream->encoder.w.ob->main_stream, value); -} - - -/* Write a HOST_WIDE_INT VALUE to stream. */ - -static inline void -pph_out_hwi (pph_stream *stream, HOST_WIDE_INT value) -{ - streamer_write_hwi (stream->encoder.w.ob, value); -} - - -/* Write an int VALUE to stream. */ - -static inline void -pph_out_int (pph_stream *stream, int value) -{ - streamer_write_hwi (stream->encoder.w.ob, value); -} - - -/* Write an unsigned HOST_WIDE_INT VALUE to STREAM. */ - -static inline void -pph_out_uhwi (pph_stream *stream, unsigned HOST_WIDE_INT value) -{ - streamer_write_uhwi (stream->encoder.w.ob, value); -} - - -/* Write an unsigned int VALUE to STREAM. */ - -void -pph_out_uint (pph_stream *stream, unsigned int value) -{ - streamer_write_uhwi (stream->encoder.w.ob, value); -} - - -/* Write N bytes from P to STREAM. */ - -static void -pph_out_bytes (pph_stream *stream, const void *p, size_t n) -{ - lto_output_data_stream (stream->encoder.w.ob->main_stream, p, n); -} - - -/* Write string STR to STREAM. */ - -static inline void -pph_out_string (pph_stream *stream, const char *str) -{ - streamer_write_string (stream->encoder.w.ob, - stream->encoder.w.ob->main_stream, str, false); -} - - -/* Write string STR of length LEN to STREAM. */ -static inline void -pph_out_string_with_length (pph_stream *stream, const char *str, - unsigned int len) -{ - streamer_write_string_with_length (stream->encoder.w.ob, - stream->encoder.w.ob->main_stream, - str, len + 1, false); -} - - -/* Write a bitpack BP to STREAM. */ - -static inline void -pph_out_bitpack (pph_stream *stream, struct bitpack_d *bp) -{ - gcc_assert (stream->encoder.w.ob->main_stream == bp->stream); - streamer_write_bitpack (bp); -} - - -/******************************************************** source information */ - - -/* Emit linenum_type LN to STREAM. */ - -static inline void -pph_out_linenum_type (pph_stream *stream, linenum_type ln) -{ - pph_out_uint (stream, ln); -} - - -/* Emit source_location SL to STREAM. */ - -static inline void -pph_out_source_location (pph_stream *stream, source_location sl) -{ - pph_out_uint (stream, sl); -} - - -/* Emit line table MARKER to STREAM. */ - -static inline void -pph_out_linetable_marker (pph_stream *stream, enum pph_linetable_marker marker) -{ - gcc_assert (marker == (enum pph_linetable_marker)(unsigned char) marker); - pph_out_uchar (stream, marker); -} - - -/* Emit all the fields of struct line_map_ordinary LM to STREAM. IX - is the slot number in the line table where LM is stored. */ - -static void -pph_out_line_map_ordinary (pph_stream *stream, struct line_map *lm, int ix) -{ - struct bitpack_d bp; - int rel_includer_ix, includer_ix; - - pph_out_string (stream, ORDINARY_MAP_FILE_NAME (lm)); - pph_out_linenum_type (stream, ORDINARY_MAP_STARTING_LINE_NUMBER (lm)); - - /* To support relocating this table into other translation units, - emit a relative index to LM's includer. All the relative indices - are positive values indicating the distance from LM to the line - map for its includer. */ - includer_ix = ORDINARY_MAP_INCLUDER_FILE_INDEX (lm); - if (includer_ix >= 0) - { - gcc_assert (includer_ix < ix); - rel_includer_ix = ix - includer_ix; - } - else - { - /* If LM is included by index -1, it means that this is a line map - entry for the top level file being compiled (i.e., the PPH that - we are currently generating). The first time we find this index, - the reader will remember the index of the current parent file - and replace all the -1 entries with it. */ - gcc_assert (includer_ix == -1); - rel_includer_ix = includer_ix; - } - - pph_out_int (stream, rel_includer_ix); - - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, ORDINARY_MAP_IN_SYSTEM_HEADER_P (lm), CHAR_BIT); - bp_pack_value (&bp, ORDINARY_MAP_NUMBER_OF_COLUMN_BITS (lm), COLUMN_BITS_BIT); - pph_out_bitpack (stream, &bp); -} - - -/* Emit all information contained in LM to STREAM. IX is the slot number - in the line table where LM is stored. */ - -static void -pph_out_line_map (pph_stream *stream, struct line_map *lm, int ix) -{ - struct output_block *ob = stream->encoder.w.ob; - - pph_out_source_location (stream, lm->start_location); - streamer_write_enum (ob->main_stream, lc_reason, LC_ENTER_MACRO, lm->reason); - - /* FIXME pph. We currently do not support location tracking for - macros in PPH images. */ - gcc_assert (lm->reason != LC_ENTER_MACRO); - pph_out_line_map_ordinary (stream, lm, ix); -} - - -/* Write a reference of INCLUDE to STREAM. Also write the START_LOCATION of - this include in the current line_table. */ - -static void -pph_out_include (pph_stream *stream, pph_stream *include, - source_location start_location) -{ - pph_out_source_location (stream, start_location); - pph_out_string (stream, include->name); -} - - -/* Compare filenames of a header and it's potentially corresponding pph file, - stripping the path passed in and the extension. Returns true if HEADER_PATH - and PPH_PATH end with the same filename. We expect HEADER_PATH to end in .h - and PPH_PATH to end in .pph. - - FIXME pph: We should not need to do this if we handled include paths - correctly, but for now the linemap holds full paths and the stream's includes - list only holds the include name. Also, the stream's includes hold pph - filenames where as the line_table as header filenames. */ - -static bool -pph_filename_eq_ignoring_path (const char *header_path, const char *pph_path) -{ - const char *header_name = lbasename (header_path); - const char *pph_name = lbasename (pph_path); - - const char *header_ext = strchr (header_name, '.'); - const char *pph_ext = strchr (pph_name, '.'); - - unsigned int name_length; - - if (header_ext != NULL) - { - name_length = header_ext - header_name; - gcc_assert (strcmp (header_ext, ".h") == 0); - } - else - /* Some headers do not have a .h suffix, but will still - have a .pph suffix after being pph'ed. */ - name_length = strlen (header_name); - - gcc_assert (strcmp (pph_ext, ".pph") == 0); - - /* Compare the filenames without their extension. */ - return pph_ext - pph_name == name_length - && strncmp (header_name, pph_name, name_length) == 0; -} - - -/* Return the *NEXT_INCLUDE_IX'th pph_stream in STREAM's list of includes. - Returns NULL if we have read all includes. Increments *NEXT_INCLUDE_IX - when sucessful. */ - -static inline pph_stream * -pph_get_next_include (pph_stream *stream, unsigned int *next_incl_ix) -{ - if (*next_incl_ix < VEC_length (pph_stream_ptr, stream->includes)) - return VEC_index (pph_stream_ptr, stream->includes, (*next_incl_ix)++); - else - return NULL; -} - - -/* Emit the required line_map entry (those directly related to this include) - and some properties in the line_table to STREAM, ignoring builtin and - command-line entries. We will write references to our direct includes - children and skip their actual line_map entries (unless they are non-pph - children in which case we have to write out their line_map entries as well). - We assume stream->encoder.w.includes contains the pph headers included in the - same order they are seen in the line_table. */ - -static void -pph_out_line_table_and_includes (pph_stream *stream) -{ - unsigned int next_incl_ix = 0; - int ix; - pph_stream *current_include; - - /* Any #include should have been fully parsed and exited at this point. */ - gcc_assert (line_table->depth == 0); - - current_include = pph_get_next_include (stream, &next_incl_ix); - - for (ix = PPH_NUM_IGNORED_LINE_TABLE_ENTRIES; - ix < (int) LINEMAPS_ORDINARY_USED (line_table); - ix++) - { - struct line_map *lm = LINEMAPS_ORDINARY_MAP_AT (line_table, ix); - - /* FIXME pph. We currently do not support location tracking for - macros in PPH images. */ - gcc_assert (lm->reason != LC_ENTER_MACRO); - - if (ix == PPH_NUM_IGNORED_LINE_TABLE_ENTRIES) - { - /* The first non-ignored entry should be an LC_RENAME back - in the header after inserting the builtin and - command-line entries. When reading the pph we want this - to be a simple LC_ENTER as the builtin and command_line - entries will already exist and we are now entering a - #include. */ - gcc_assert (lm->reason == LC_RENAME); - lm->reason = LC_ENTER; - } - - /* If LM is an entry for an included PPH image, output a line table - reference to it, so the reader can load the included image at - this point. */ - if (current_include != NULL - && pph_filename_eq_ignoring_path (LINEMAP_FILE (lm), - current_include->name)) - { - struct line_map *included_from; - - /* Assert that we are entering a new header file from another. */ - gcc_assert (lm->reason == LC_ENTER); - gcc_assert (ORDINARY_MAP_INCLUDER_FILE_INDEX (lm) != -1); - - pph_out_linetable_marker (stream, PPH_LINETABLE_REFERENCE); - - pph_out_include (stream, current_include, lm->start_location); - - /* Since all the line table entries corresponding to - CURRENT_INCLUDE and its #include children are emitted - inside CURRENT_INCLUDE, we need to skip them so they do - not get emitted in STREAM. - - To do this, we look for the next line map table that - corresponds to an LC_LEAVE event back to the file that - includes CURRENT_INCLUDE (which is represented by the - line map LM). */ - included_from = INCLUDED_FROM (line_table, lm); - for (ix++; ix < (int) LINEMAPS_ORDINARY_USED (line_table); ix++) - { - struct line_map *map = LINEMAPS_ORDINARY_MAP_AT (line_table, ix); - - /* When we find an LC_LEAVE map, we have two ways of - deciding if it is an LC_LEAVE event back to - INCLUDED_FROM. Either MAP goes to the same file name - as INCLUDED_FROM or both MAP and INCLUDED_FROM are - included by the same line map. Since the latter is - faster, we check it instead of doing a string - comparison. */ - if (map->reason == LC_LEAVE - && ORDINARY_MAP_INCLUDER_FILE_INDEX (included_from) - == ORDINARY_MAP_INCLUDER_FILE_INDEX (map)) - break; - } - - /* We should always leave this loop before the end of the - current line_table entries. */ - gcc_assert (ix < (int) LINEMAPS_ORDINARY_USED (line_table)); - - current_include = pph_get_next_include (stream, &next_incl_ix); - } - else - { - pph_out_linetable_marker (stream, PPH_LINETABLE_ENTRY); - pph_out_line_map (stream, lm, ix); - } - - /* Restore changes made to the first entry above, if needed. */ - if (ix == PPH_NUM_IGNORED_LINE_TABLE_ENTRIES) - lm->reason = LC_RENAME; - } - - pph_out_linetable_marker (stream, PPH_LINETABLE_END); - - /* Output the number of entries written to validate on input. */ - pph_out_uint (stream, LINEMAPS_ORDINARY_USED (line_table) - - PPH_NUM_IGNORED_LINE_TABLE_ENTRIES); - - /* Every PPH header included should have been seen and skipped in the - line_table streaming above. */ - gcc_assert (next_incl_ix == VEC_length (pph_stream_ptr, stream->includes)); - - pph_out_source_location (stream, line_table->highest_location); - pph_out_source_location (stream, line_table->highest_line); - - pph_out_uint (stream, line_table->max_column_hint); -} - - -/*********************************************************** record handling */ - - -/* Return a PPH record marker according to whether DATA is NULL or - it can be found in one of the caches associated with STREAM. TAG - is the data type for DATA. - - If DATA is in any of the caches, return the corresponding slot in - *IX_P. If DATA is in the cache of an image included by STREAM, - return the image's index in *INCLUDE_IX_P. - - Caches are consulted in order of preference: preloaded, internal - and external. - - If DATA is not found anywhere, return PPH_RECORD_START and, if - given, set *IX_P and *INCLUDE_IX_P to -1. */ - -static enum pph_record_marker -pph_get_marker_for (pph_stream *stream, void *data, unsigned *include_ix_p, - unsigned *ix_p, enum pph_tag tag) -{ - if (ix_p) - *ix_p = -1u; - - if (include_ix_p) - *include_ix_p = -1u; - - /* We represent NULL pointers with PPH_RECORD_END. */ - if (data == NULL) - return PPH_RECORD_END; - - /* If DATA is a pre-loaded tree node, return a pre-loaded reference - marker. */ - if (pph_cache_lookup (NULL, data, ix_p, tag)) - return PPH_RECORD_PREF; - - /* If DATA is in STREAM's cache, return an internal reference marker. */ - if (pph_cache_lookup (&stream->cache, data, ix_p, tag)) - return PPH_RECORD_IREF; - - /* If DATA is in the cache of an included image, return an external - reference marker. */ - if (pph_cache_lookup_in_includes (stream, data, include_ix_p, ix_p, tag)) - return PPH_RECORD_XREF; - - /* DATA is in none of the caches. It should be pickled out. */ - return PPH_RECORD_START; -} - - -/* Write record MARKER for data type TAG to STREAM. */ -void -pph_out_record_marker (pph_stream *stream, enum pph_record_marker marker, - enum pph_tag tag) -{ - gcc_assert (marker == (enum pph_record_marker)(unsigned char) marker); - pph_out_uchar (stream, marker); - - gcc_assert (tag == (enum pph_tag)(unsigned) tag); - pph_out_uint (stream, tag); - - if (flag_pph_tracer >= 5) - pph_trace_marker (marker, tag); -} - - -/* Write a reference record on STREAM. MARKER is the tag indicating - what kind of reference to write. TAG indicates the data type to be - stored in this record. IX is the cache slot index to write. - INCLUDE_IX is used for PPH_RECORD_XREF records. */ - -static inline void -pph_out_reference_record (pph_stream *stream, enum pph_record_marker marker, - unsigned include_ix, unsigned ix, enum pph_tag tag) -{ - gcc_assert (marker == PPH_RECORD_END || pph_is_reference_marker (marker)); - - pph_out_record_marker (stream, marker, tag); - - if (pph_is_reference_marker (marker)) - { - if (marker == PPH_RECORD_XREF) - { - gcc_assert (include_ix != -1u); - pph_out_uint (stream, include_ix); - } - - gcc_assert (ix != -1u); - pph_out_uint (stream, ix); - } - else - gcc_assert (marker == PPH_RECORD_END); -} - - -/* Start a new record in STREAM for DATA with data type TAG. If DATA - is NULL write an end-of-record marker and return true. - - If DATA is not NULL and did not exist in the pickle cache, add it, - write a start-of-record marker and return true. This means that we - could not write a reference marker to DATA and the caller should - pickle out DATA's physical representation. - - If DATA existed in the cache, write a reference-record marker and - return true. This means that we could write a reference marker to - DATA. */ - -static inline bool -pph_out_start_record (pph_stream *stream, void *data, enum pph_tag tag) -{ - unsigned include_ix, ix; - enum pph_record_marker marker; - - /* Try to write a reference record first. */ - marker = pph_get_marker_for (stream, data, &include_ix, &ix, tag); - if (marker == PPH_RECORD_END || pph_is_reference_marker (marker)) - { - pph_out_reference_record (stream, marker, include_ix, ix, tag); - return true; - } - - /* DATA is in none of the pickle caches. Add DATA to STREAM's - pickle cache and write the slot where we stored it in. */ - pph_cache_add (&stream->cache, data, &ix, tag); - pph_out_record_marker (stream, PPH_RECORD_START, tag); - pph_out_uint (stream, ix); - - /* The caller will have to write a physical representation for DATA. */ - return false; -} - - -/* Return true if tree node T should be added to the pickle cache. */ - -static inline bool -pph_cache_should_handle (tree t) -{ - if (t) - { - if (TREE_CODE (t) == INTEGER_CST) - { - /* With the exception of some special constants that are - pointer-compared everywhere (e.g., integer_zero_node), we - do not want constants in the cache. Their physical - representation is smaller than a cache reference record - and they can also trick the cache in similar ways to - builtins (read below). */ - return false; - } - else if (streamer_handle_as_builtin_p (t)) - { - /* We do not want builtins in the cache for two reasons: - - - They never need pickling. Much like pre-loaded tree - nodes, builtins are pre-built by the compiler and - accessible with their class and code. - - - They can trick the cache. When possible, user-provided - functions are generally replaced by their builtin - counterparts (e.g., strcmp, malloc, etc). When this - happens, the writer cache will store in its cache two - different expressions, one for the user provided - function and another for the builtin itself. However, - when written out to the PPH image, they both get - emitted as a reference to the builtin. Therefore, when - the reader tries to instantiate the second copy, it - tries to store the same tree in two different cache - slots (and proceeds to ICE in pph_cache_insert_at). */ - return false; - } - } - - return true; -} - - -/* Start a record for tree node T in STREAM. This is like - pph_out_start_record, but it filters certain special trees that - should never be added to the cache. Additionally, instead of - returning a boolean value indicating whether pickling should be - done, it returns the actual marker used to start the record. */ - -static inline enum pph_record_marker -pph_out_start_tree_record (pph_stream *stream, tree t) -{ - unsigned include_ix, ix; - enum pph_record_marker marker; - enum pph_tag tag; - - /* Determine what kind of record we will be writing. */ - tag = pph_tree_code_to_tag (t); - marker = pph_get_marker_for (stream, t, &include_ix, &ix, tag); - - /* Signed tree nodes that have been read from an external PPH image - may have mutated while parsing this header. In that case, - we need to write a mutated reference record and re-pickle the - tree. */ - if (marker == PPH_RECORD_XREF && tree_needs_signature (t)) - { - pph_cache *cache = pph_cache_select (stream, marker, include_ix); - pph_cache_entry *e = pph_cache_get_entry (cache, ix); - unsigned crc = pph_get_signature (t, NULL); - if (crc != e->crc) - marker = PPH_RECORD_START_MUTATED; - } - - /* If we are about to write an internal reference for a mergeable - tree, it means that we have already written the merge key for it. - Check whether we still need to write its merge body. If so, - MARKER should be PPH_RECORD_START_MERGE_BODY. */ - if (marker == PPH_RECORD_IREF && pph_tree_is_mergeable (t)) - { - pph_cache_entry *e = pph_cache_get_entry (&stream->cache, ix); - if (e->needs_merge_body) - { - marker = PPH_RECORD_START_MERGE_BODY; - e->needs_merge_body = false; - } - } - - /* Write a record header according to the value of MARKER. */ - if (marker == PPH_RECORD_END || pph_is_reference_marker (marker)) - pph_out_reference_record (stream, marker, include_ix, ix, tag); - else if (marker == PPH_RECORD_START || marker == PPH_RECORD_START_MERGE_BODY) - { - /* We want to prevent some trees from hitting the cache. - For example, we do not want to cache regular constants (as - their representation is actually smaller than a cache - reference), but some constants are special and need to - always be shared (e.g., integer_zero_node). Those special - constants are pre-loaded in STREAM->PRELOADED_CACHE. */ - if (!pph_cache_should_handle (t)) - marker = PPH_RECORD_START_NO_CACHE; - - pph_out_record_marker (stream, marker, tag); - - if (marker == PPH_RECORD_START || marker == PPH_RECORD_START_MERGE_BODY) - { - unsigned ix; - pph_cache_add (&stream->cache, t, &ix, tag); - pph_out_uint (stream, ix); - } - } - else if (marker == PPH_RECORD_START_MUTATED) - { - unsigned int internal_ix; - - /* We found T in an external PPH file, but it has mutated since - we originally read it. We are going to write out T again, - but the reader should not re-allocate T, rather it should - read the contents of T on top of the existing address. - - We also add T to STREAM's internal cache so further - references go to it rather than the external version. - Note that although we add an entry for T in STREAM's internal - cache, the reference we write to the stream is to the - external version of T. This way the reader will get the - location of T from the external reference and overwrite it - with the contents that we are going to write here. */ - pph_cache_add (&stream->cache, t, &internal_ix, tag); - pph_out_record_marker (stream, marker, tag); - - /* Write the location of T in the external cache. */ - gcc_assert (include_ix != -1u); - pph_out_uint (stream, include_ix); - - gcc_assert (ix != -1u); - pph_out_uint (stream, ix); - - /* Now write the location of the new version of T in the - internal cache. */ - pph_out_uint (stream, internal_ix); - } - else - gcc_unreachable (); - - return marker; -} - - -/* Start a merge key record for EXPR on STREAM. */ - -static bool -pph_out_start_merge_key_record (pph_stream *stream, tree expr) -{ - enum pph_tag tag; - enum pph_record_marker marker; - pph_cache_entry *e; - unsigned include_ix, ix; - - tag = pph_tree_code_to_tag (expr); - marker = pph_get_marker_for (stream, expr, &include_ix, &ix, tag); - - if (marker == PPH_RECORD_END || pph_is_reference_marker (marker)) - { - pph_out_reference_record (stream, marker, include_ix, ix, tag); - return true; - } - - /* This should be the first time that we try to write EXPR. */ - gcc_assert (marker == PPH_RECORD_START); - - pph_out_record_marker (stream, PPH_RECORD_START_MERGE_KEY, tag); - e = pph_cache_add (&stream->cache, expr, &ix, tag); - e->needs_merge_body = true; - pph_out_uint (stream, ix); - return false; -} - - - -/********************************************************** lexical elements */ - - -/* Write location LOC of length to STREAM. */ - -void -pph_out_location (pph_stream *stream, location_t loc) -{ - /* FIXME pph: we are streaming builtin locations, which implies that we are - streaming some builtins, we probably want to figure out what those are and - simply add them to the cache in the preload. */ - struct bitpack_d bp; - struct line_map *map; - location_t first_non_builtin_loc; - - map = LINEMAPS_ORDINARY_MAP_AT (line_table, - PPH_NUM_IGNORED_LINE_TABLE_ENTRIES); - first_non_builtin_loc = MAP_START_LOCATION (map); - - bp = bitpack_create (stream->encoder.w.ob->main_stream); - if (loc < first_non_builtin_loc) - { - /* We should never stream out trees with locations between builtins - and user locations (e.g. ). */ - gcc_assert (loc <= BUILTINS_LOCATION); - bp_pack_value (&bp, true, 1); - } - else - bp_pack_value (&bp, false, 1); - - pph_out_bitpack (stream, &bp); - pph_out_uhwi (stream, loc); -} - - -/* Save the tree associated with TOKEN to STREAM. */ - -static void -pph_out_token_value (pph_stream *stream, cp_token *token) -{ - tree val; - - val = token->u.value; - switch (token->type) - { - case CPP_TEMPLATE_ID: - case CPP_NESTED_NAME_SPECIFIER: - /* FIXME pph - Need to handle struct tree_check. */ - break; - - case CPP_KEYWORD: - /* Nothing to do. We will reconstruct the keyword from - ridpointers[token->keyword] at load time. */ - break; - - case CPP_NAME: - case CPP_CHAR: - case CPP_WCHAR: - case CPP_CHAR16: - case CPP_CHAR32: - case CPP_NUMBER: - case CPP_STRING: - case CPP_WSTRING: - case CPP_STRING16: - case CPP_STRING32: - pph_out_tree (stream, val); - break; - - case CPP_PRAGMA: - /* Nothing to do. Field pragma_kind has already been written. */ - break; - - default: - gcc_assert (token->u.value == NULL); - pph_out_bytes (stream, &token->u.value, sizeof (token->u.value)); - } -} - - -/* Save TOKEN on file F. Return the number of bytes written on F. */ - -static void -pph_out_token (pph_stream *f, cp_token *token) -{ - /* Do not write out the final field in TOKEN. It contains - pointers that need to be pickled separately. - - FIXME pph - Need to also emit the location_t table so we can - reconstruct it when reading the PTH state. */ - pph_out_bytes (f, token, sizeof (cp_token) - sizeof (void *)); - pph_out_token_value (f, token); -} - - -/* Save all the tokens in CACHE to PPH stream F. */ - -static void -pph_out_token_cache (pph_stream *f, cp_token_cache *cache) -{ - unsigned i, num; - cp_token *tok; - - if (cache == NULL) - { - pph_out_uint (f, 0); - return; - } - - for (num = 0, tok = cache->first; tok != cache->last; tok++) - num++; - - pph_out_uint (f, num); - for (i = 0, tok = cache->first; i < num; tok++, i++) - pph_out_token (f, tok); -} - - -/******************************************************************* vectors */ - -/* Note that we use the same format used by streamer_write_chain. - This is to support pph_out_chain_filtered, which writes the - filtered chain as a VEC. Since the reader always reads chains - using streamer_read_chain, we have to write VECs in exactly the - same way as tree chains. */ - -/* Return true if T matches FILTER for STREAM. */ - -static inline bool -pph_tree_matches (pph_stream *stream, tree t, unsigned filter) -{ - if ((filter & PPHF_NO_BUILTINS) - && DECL_P (t) - && DECL_IS_BUILTIN (t)) - return false; - - if ((filter & PPHF_NO_PREFS) - && pph_cache_lookup (NULL, t, NULL, pph_tree_code_to_tag (t))) - return false; - - if ((filter & PPHF_NO_XREFS) - && pph_cache_lookup_in_includes (stream, t, NULL, NULL, - pph_tree_code_to_tag (t))) - return false; - - return true; -} - - -/* Return a heap vector with all the trees in V that match FILTER. - The caller is responsible for freeing the returned vector. */ - -static inline VEC(tree,heap) * -vec2vec_filter (pph_stream *stream, VEC(tree,gc) *v, unsigned filter) -{ - unsigned i; - tree t; - VEC(tree, heap) *filtered_v = NULL; - - /* Do not accept the nil filter. The caller is responsible for - freeing the returned vector and they may inadvertently free - a vector they assumed to be allocated by this function. */ - gcc_assert (filter != PPHF_NONE); - - /* Collect all the nodes that match the filter. */ - FOR_EACH_VEC_ELT (tree, v, i, t) - if (pph_tree_matches (stream, t, filter)) - VEC_safe_push (tree, heap, filtered_v, t); - - return filtered_v; -} - - -/* Write all the trees in VEC V to STREAM. */ - -static void -pph_out_tree_vec (pph_stream *stream, VEC(tree,gc) *v) -{ - unsigned i; - tree t; - pph_out_hwi (stream, VEC_length (tree, v)); - FOR_EACH_VEC_ELT (tree, v, i, t) - pph_out_tree (stream, t); -} - - -/* Write all the trees in VEC V to STREAM. - Clear TREE_CHAIN on every element written out (this is to support - writing chains, as they are supposed to be re-chained by the reader). */ - -static void -pph_out_tree_vec_unchain (pph_stream *stream, VEC(tree,gc) *v) -{ - unsigned i; - tree t; - pph_out_hwi (stream, VEC_length (tree, v)); - FOR_EACH_VEC_ELT (tree, v, i, t) - { - tree prev = TREE_CHAIN (t); - TREE_CHAIN (t) = NULL; - pph_out_tree (stream, t); - TREE_CHAIN (t) = prev; - } -} - - -/* Write all the merge keys for trees in VEC V to STREAM. The keys - must go out in declaration order, i.e. reversed. */ - -static void -pph_out_merge_key_vec (pph_stream *stream, VEC(tree,gc) *v) -{ - unsigned i; - tree t; - pph_out_hwi (stream, VEC_length (tree, v)); - FOR_EACH_VEC_ELT_REVERSE (tree, v, i, t) - pph_out_merge_key_tree (stream, t); -} - - -/* Write all the merge bodies for trees in VEC V to STREAM. The bodies - should/must go out in declaration order, i.e. reversed. */ - -static void -pph_out_merge_body_vec (pph_stream *stream, VEC(tree,gc) *v) -{ - unsigned i; - tree t; - pph_out_hwi (stream, VEC_length (tree, v)); - FOR_EACH_VEC_ELT_REVERSE (tree, v, i, t) - pph_out_tree (stream, t); -} - - -/* Write all the trees in VEC V that match FILTER to STREAM. */ - -static void -pph_out_tree_vec_filtered (pph_stream *stream, VEC(tree,gc) *v, unsigned filter) -{ - if (filter == PPHF_NONE) - pph_out_tree_vec (stream, v); - else - { - VEC(tree,heap) *w = vec2vec_filter (stream, v, filter); - pph_out_tree_vec (stream, (VEC(tree,gc) *)w); - VEC_free (tree, heap, w); - } -} - - -/* Write all the qualified_typedef_usage_t in VEC V to STREAM. */ - -static void -pph_out_qual_use_vec (pph_stream *stream, VEC(qualified_typedef_usage_t,gc) *v) -{ - unsigned i; - qualified_typedef_usage_t *q; - - pph_out_uint (stream, VEC_length (qualified_typedef_usage_t, v)); - FOR_EACH_VEC_ELT (qualified_typedef_usage_t, v, i, q) - { - pph_out_tree (stream, q->typedef_decl); - pph_out_tree (stream, q->context); - pph_out_location (stream, q->locus); - } -} - - -/* Write the vector V of tree_pair_s instances to STREAM. */ - -static void -pph_out_tree_pair_vec (pph_stream *stream, VEC(tree_pair_s,gc) *v) -{ - unsigned i; - tree_pair_s *p; - - pph_out_uint (stream, VEC_length (tree_pair_s, v)); - FOR_EACH_VEC_ELT (tree_pair_s, v, i, p) - { - pph_out_tree (stream, p->purpose); - pph_out_tree (stream, p->value); - } -} - - -/******************************************************************** chains */ - -/* Convert a CHAIN to a VEC by copying only the nodes that match FILTER - for STREAM. */ - -static VEC(tree,heap) * -chain2vec_filter (pph_stream *stream, tree chain, unsigned filter) -{ - tree t; - VEC(tree,heap) *v = NULL; - - /* Do not accept the nil filter. The caller is responsible for - freeing the returned vector and they may inadvertently free - a vector they assumed to be allocated by this function. */ - /* FIXME crowl: gcc_assert (filter != PPHF_NONE); */ - - for (t = chain; t; t = TREE_CHAIN (t)) - if (pph_tree_matches (stream, t, filter)) - VEC_safe_push (tree, heap, v, t); - - return v; -} - - -/* Convert a CHAIN to a VEC by copying the nodes. */ - -static VEC(tree,heap) * -chain2vec (tree chain) -{ - tree t; - VEC(tree,heap) *v = NULL; - - for (t = chain; t; t = TREE_CHAIN (t)) - VEC_safe_push (tree, heap, v, t); - - return v; -} - - -/* Write a chain of trees to STREAM starting with FIRST. */ - -static void -pph_out_chain (pph_stream *stream, tree first) -{ - streamer_write_chain (stream->encoder.w.ob, first, false); -} - - -/* Write a chain of trees to stream starting with FIRST. Only write - the trees that match FILTER. */ - -static void -pph_out_chain_filtered (pph_stream *stream, tree first, unsigned filter) -{ - VEC(tree,heap) *w = chain2vec_filter (stream, first, filter); - pph_out_tree_vec_unchain (stream, (VEC(tree,gc) *)w); - VEC_free (tree, heap, w); -} - - -/* Write, in reverse, a chain of merge keys to STREAM starting - with the last element of CHAIN. Only write the trees that match - FILTER. */ - -static void -pph_out_merge_key_chain (pph_stream *stream, tree chain, unsigned filter) -{ - VEC(tree,heap) *w; - if (filter == PPHF_NONE) - w = chain2vec (chain); - else - w = chain2vec_filter (stream, chain, filter); - pph_out_merge_key_vec (stream, (VEC(tree,gc) *)w); - VEC_free (tree, heap, w); -} - - -/* Write, in reverse, a chain of merge bodies to STREAM starting - with the last element of CHAIN. Only write the trees that match - FILTER. */ - -static void -pph_out_merge_body_chain (pph_stream *stream, tree chain, unsigned filter) -{ - VEC(tree,heap) *w; - if (filter == PPHF_NONE) - w = chain2vec (chain); - else - w = chain2vec_filter (stream, chain, filter); - pph_out_merge_body_vec (stream, (VEC(tree,gc) *)w); - VEC_free (tree, heap, w); -} - - -/****************************************************************** bindings */ - - -/* Forward declaration to break cyclic dependencies. */ -static void pph_out_binding_level (pph_stream *, cp_binding_level *, unsigned); - - -/* Helper for pph_out_cxx_binding. STREAM and CB are as in - pph_out_cxx_binding. */ - -static void -pph_out_cxx_binding_1 (pph_stream *stream, cxx_binding *cb) -{ - struct bitpack_d bp; - - if (pph_out_start_record (stream, cb, PPH_cxx_binding)) - return; - - pph_out_tree (stream, cb->value); - pph_out_tree (stream, cb->type); - pph_out_binding_level (stream, cb->scope, PPHF_NONE); - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, cb->value_is_inherited, 1); - bp_pack_value (&bp, cb->is_local, 1); - pph_out_bitpack (stream, &bp); -} - - -/* Write all the fields of cxx_binding instance CB to STREAM. */ - -static void -pph_out_cxx_binding (pph_stream *stream, cxx_binding *cb) -{ - cxx_binding *prev; - - /* Write the current binding first. */ - pph_out_cxx_binding_1 (stream, cb); - - /* Write the list of previous bindings. */ - for (prev = cb ? cb->previous : NULL; prev; prev = prev->previous) - pph_out_cxx_binding_1 (stream, prev); - - /* Mark the end of the list (if there was a list). */ - if (cb) - pph_out_cxx_binding_1 (stream, NULL); -} - - -/* Write all the fields of cp_class_binding instance CB to STREAM. */ - -static void -pph_out_class_binding (pph_stream *stream, cp_class_binding *cb) -{ - if (pph_out_start_record (stream, cb, PPH_cp_class_binding)) - return; - - pph_out_cxx_binding (stream, cb->base); - pph_out_tree (stream, cb->identifier); -} - - -/* Write all the fields of cp_label_binding instance LB to STREAM. */ - -static void -pph_out_label_binding (pph_stream *stream, cp_label_binding *lb) -{ - if (pph_out_start_record (stream, lb, PPH_cp_label_binding)) - return; - - pph_out_tree (stream, lb->label); - pph_out_tree (stream, lb->prev_value); -} - - -/* Helper for pph_out_binding_level. Write the fields of BL to - STREAM. Do not emit any nodes in BL that do not match FILTER. */ - -static void -pph_out_binding_level_1 (pph_stream *stream, cp_binding_level *bl, - unsigned filter) -{ - unsigned i; - cp_class_binding *cs; - cp_label_binding *sl; - struct bitpack_d bp; - - pph_out_tree (stream, bl->this_entity); - - pph_out_uint (stream, VEC_length (cp_class_binding, bl->class_shadowed)); - FOR_EACH_VEC_ELT (cp_class_binding, bl->class_shadowed, i, cs) - pph_out_class_binding (stream, cs); - - pph_out_tree (stream, bl->type_shadowed); - - pph_out_uint (stream, VEC_length (cp_label_binding, bl->shadowed_labels)); - FOR_EACH_VEC_ELT (cp_label_binding, bl->shadowed_labels, i, sl) - pph_out_label_binding (stream, sl); - - pph_out_tree (stream, bl->blocks); - pph_out_binding_level (stream, bl->level_chain, filter); - pph_out_tree_vec (stream, bl->dead_vars_from_for); - pph_out_chain (stream, bl->statement_list); - pph_out_uint (stream, bl->binding_depth); - - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, bl->kind, 4); - bp_pack_value (&bp, bl->keep, 1); - bp_pack_value (&bp, bl->more_cleanups_ok, 1); - bp_pack_value (&bp, bl->have_cleanups, 1); - pph_out_bitpack (stream, &bp); -} - - -/* Write all the fields of cp_binding_level instance BL to STREAM for the - non-merging case. Do not emit any nodes in BL that do not match FILTER. */ - -static void -pph_out_binding_level (pph_stream *stream, cp_binding_level *bl, - unsigned filter) -{ - if (pph_out_start_record (stream, bl, PPH_cp_binding_level)) - return; - - pph_out_chain_filtered (stream, bl->names, filter); - pph_out_chain_filtered (stream, bl->namespaces, filter); - pph_out_chain_filtered (stream, bl->usings, filter); - pph_out_chain_filtered (stream, bl->using_directives, filter); - pph_out_tree_vec_filtered (stream, bl->static_decls, filter); - pph_out_binding_level_1 (stream, bl, filter); -} - - -/* Write an index of mergeable objects from cp_binding_level BL to STREAM. */ - -static void -pph_out_binding_merge_keys (pph_stream *stream, cp_binding_level *bl) -{ - unsigned filter = PPHF_NO_XREFS | PPHF_NO_PREFS | PPHF_NO_BUILTINS; - pph_out_merge_key_chain (stream, bl->names, filter); - pph_out_merge_key_chain (stream, bl->namespaces, filter); - pph_out_merge_key_chain (stream, bl->usings, filter); - pph_out_merge_key_chain (stream, bl->using_directives, filter); -} - - -/* Write bodies of mergeable objects from cp_binding_level BL to STREAM. */ - -static void -pph_out_binding_merge_bodies (pph_stream *stream, cp_binding_level *bl) -{ - unsigned filter = PPHF_NO_XREFS | PPHF_NO_PREFS | PPHF_NO_BUILTINS; - pph_out_merge_body_chain (stream, bl->names, filter); - pph_out_merge_body_chain (stream, bl->namespaces, filter); - pph_out_merge_body_chain (stream, bl->usings, filter); - pph_out_merge_body_chain (stream, bl->using_directives, filter); - pph_out_tree_vec_filtered (stream, bl->static_decls, filter); - pph_out_binding_level_1 (stream, bl, filter); -} - - -/********************************************************** tree aux classes */ - - -/* Write all the fields of language_function instance LF to STREAM. */ - -static void -pph_out_language_function (pph_stream *stream, struct language_function *lf) -{ - struct bitpack_d bp; - - if (pph_out_start_record (stream, lf, PPH_language_function)) - return; - - pph_out_tree_vec (stream, lf->base.x_stmt_tree.x_cur_stmt_list); - pph_out_uint (stream, lf->base.x_stmt_tree.stmts_are_full_exprs_p); - pph_out_tree (stream, lf->x_cdtor_label); - pph_out_tree (stream, lf->x_current_class_ptr); - pph_out_tree (stream, lf->x_current_class_ref); - pph_out_tree (stream, lf->x_eh_spec_block); - pph_out_tree (stream, lf->x_in_charge_parm); - pph_out_tree (stream, lf->x_vtt_parm); - pph_out_tree (stream, lf->x_return_value); - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, lf->returns_value, 1); - bp_pack_value (&bp, lf->returns_null, 1); - bp_pack_value (&bp, lf->returns_abnormally, 1); - bp_pack_value (&bp, lf->x_in_function_try_handler, 1); - bp_pack_value (&bp, lf->x_in_base_initializer, 1); - bp_pack_value (&bp, lf->can_throw, 1); - pph_out_bitpack (stream, &bp); - - /* FIXME pph. We are not writing lf->x_named_labels. */ - - pph_out_binding_level (stream, lf->bindings, PPHF_NONE); - pph_out_tree_vec (stream, lf->x_local_names); - - /* FIXME pph. We are not writing lf->extern_decl_map. */ -} - - -/* 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; -}; - -static int -pph_out_used_types_slot (void **slot, void *aux) -{ - struct pph_tree_info *pti = (struct pph_tree_info *) aux; - pph_out_tree (pti->stream, (tree) *slot); - return 1; -} - - -/* Write applicable fields of struct function instance FN to STREAM. */ - -static void -pph_out_struct_function (pph_stream *stream, struct function *fn) -{ - struct pph_tree_info pti; - - if (pph_out_start_record (stream, fn, PPH_function)) - return; - - pph_out_tree (stream, fn->decl); - output_struct_function_base (stream->encoder.w.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); - - /* 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; - 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 in lang_decl_base instance LDB to OB. */ - -static void -pph_out_ld_base (pph_stream *stream, struct lang_decl_base *ldb) -{ - struct bitpack_d bp; - - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, ldb->selector, 16); - bp_pack_value (&bp, ldb->language, 4); - bp_pack_value (&bp, ldb->use_template, 2); - bp_pack_value (&bp, ldb->not_really_extern, 1); - bp_pack_value (&bp, ldb->initialized_in_class, 1); - bp_pack_value (&bp, ldb->repo_available_p, 1); - bp_pack_value (&bp, ldb->threadprivate_or_deleted_p, 1); - bp_pack_value (&bp, ldb->anticipated_p, 1); - bp_pack_value (&bp, ldb->friend_attr, 1); - bp_pack_value (&bp, ldb->template_conv_p, 1); - bp_pack_value (&bp, ldb->odr_used, 1); - bp_pack_value (&bp, ldb->u2sel, 1); - pph_out_bitpack (stream, &bp); -} - - -/* Write all the fields in lang_decl_min instance LDM to STREAM. */ - -static void -pph_out_ld_min (pph_stream *stream, struct lang_decl_min *ldm) -{ - pph_out_tree (stream, ldm->template_info); - if (ldm->base.u2sel == 0) - pph_out_tree (stream, ldm->u2.access); - else if (ldm->base.u2sel == 1) - pph_out_uint (stream, ldm->u2.discriminator); - else - gcc_unreachable (); -} - - -/* Write all the fields of lang_decl_fn instance LDF to STREAM. */ - -static void -pph_out_ld_fn (pph_stream *stream, struct lang_decl_fn *ldf) -{ - struct bitpack_d bp; - - /* Write all the fields in lang_decl_min. */ - pph_out_ld_min (stream, &ldf->min); - - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, ldf->operator_code, 16); - bp_pack_value (&bp, ldf->global_ctor_p, 1); - bp_pack_value (&bp, ldf->global_dtor_p, 1); - bp_pack_value (&bp, ldf->constructor_attr, 1); - bp_pack_value (&bp, ldf->destructor_attr, 1); - bp_pack_value (&bp, ldf->assignment_operator_p, 1); - bp_pack_value (&bp, ldf->static_function, 1); - bp_pack_value (&bp, ldf->pure_virtual, 1); - bp_pack_value (&bp, ldf->defaulted_p, 1); - bp_pack_value (&bp, ldf->has_in_charge_parm_p, 1); - bp_pack_value (&bp, ldf->has_vtt_parm_p, 1); - bp_pack_value (&bp, ldf->pending_inline_p, 1); - bp_pack_value (&bp, ldf->nonconverting, 1); - bp_pack_value (&bp, ldf->thunk_p, 1); - bp_pack_value (&bp, ldf->this_thunk_p, 1); - bp_pack_value (&bp, ldf->hidden_friend_p, 1); - pph_out_bitpack (stream, &bp); - - pph_out_tree (stream, ldf->befriending_classes); - pph_out_tree (stream, ldf->context); - - if (ldf->thunk_p == 0) - pph_out_tree (stream, ldf->u5.cloned_function); - else if (ldf->thunk_p == 1) - pph_out_uint (stream, ldf->u5.fixed_offset); - else - gcc_unreachable (); - - if (ldf->pending_inline_p == 1) - pph_out_token_cache (stream, ldf->u.pending_inline_info); - else if (ldf->pending_inline_p == 0) - pph_out_language_function (stream, ldf->u.saved_language_function); -} - - -/* Write all the fields of lang_decl_ns instance LDNS to STREAM. */ - -static void -pph_out_ld_ns (pph_stream *stream, struct lang_decl_ns *ldns) -{ - pph_out_binding_level (stream, ldns->level, PPHF_NONE); -} - - -/* Write all the fields of lang_decl_parm instance LDP to STREAM. */ - -static void -pph_out_ld_parm (pph_stream *stream, struct lang_decl_parm *ldp) -{ - pph_out_uint (stream, ldp->level); - pph_out_uint (stream, ldp->index); -} - - -/* Write all the lang-specific data in DECL to STREAM. */ - -static void -pph_out_lang_specific (pph_stream *stream, tree decl) -{ - struct lang_decl *ld; - struct lang_decl_base *ldb; - - ld = DECL_LANG_SPECIFIC (decl); - if (pph_out_start_record (stream, ld, PPH_lang_decl)) - return; - - /* Write all the fields in lang_decl_base. */ - ldb = &ld->u.base; - pph_out_ld_base (stream, ldb); - - if (ldb->selector == 0) - { - /* Write all the fields in lang_decl_min. */ - pph_out_ld_min (stream, &ld->u.min); - } - else if (ldb->selector == 1) - { - /* Write all the fields in lang_decl_fn. */ - pph_out_ld_fn (stream, &ld->u.fn); - } - else if (ldb->selector == 2) - { - /* Write all the fields in lang_decl_ns. */ - pph_out_ld_ns (stream, &ld->u.ns); - } - else if (ldb->selector == 3) - { - /* Write all the fields in lang_decl_parm. */ - pph_out_ld_parm (stream, &ld->u.parm); - } - else - gcc_unreachable (); -} - - -/********************************************************* tree base classes */ - - -/* Write out the tree_common fields from T to STREAM. */ - -static void -pph_out_tree_common (pph_stream *stream, tree t) -{ - /* The chain field in DECLs is handled separately. Make sure this - is never called with a DECL. */ - gcc_assert (!DECL_P (t)); - - /* The 'struct tree_typed typed' base class is handled in LTO. */ - pph_out_tree (stream, TREE_CHAIN (t)); -} - - -/* Write all the fields in lang_type_header instance LTH to STREAM. */ - -static void -pph_out_lang_type_header (pph_stream *stream, struct lang_type_header *lth) -{ - struct bitpack_d bp; - - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, lth->is_lang_type_class, 1); - bp_pack_value (&bp, lth->has_type_conversion, 1); - bp_pack_value (&bp, lth->has_copy_ctor, 1); - bp_pack_value (&bp, lth->has_default_ctor, 1); - bp_pack_value (&bp, lth->const_needs_init, 1); - bp_pack_value (&bp, lth->ref_needs_init, 1); - bp_pack_value (&bp, lth->has_const_copy_assign, 1); - pph_out_bitpack (stream, &bp); -} - - -/* Write a struct sorted_fields_type instance SFT to STREAM. */ - -static void -pph_out_sorted_fields_type (pph_stream *stream, struct sorted_fields_type *sft) -{ - int i; - - if (pph_out_start_record (stream, sft, PPH_sorted_fields_type)) - return; - - pph_out_uint (stream, sft->len); - for (i = 0; i < sft->len; i++) - pph_out_tree (stream, sft->elts[i]); -} - - -/* Write all the fields in lang_type_class instance LTC to STREAM. */ - -static void -pph_out_lang_type_class (pph_stream *stream, struct lang_type_class *ltc) -{ - struct bitpack_d bp; - - pph_out_uchar (stream, ltc->align); - - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, ltc->has_mutable, 1); - bp_pack_value (&bp, ltc->com_interface, 1); - bp_pack_value (&bp, ltc->non_pod_class, 1); - bp_pack_value (&bp, ltc->nearly_empty_p, 1); - bp_pack_value (&bp, ltc->user_align, 1); - bp_pack_value (&bp, ltc->has_copy_assign, 1); - bp_pack_value (&bp, ltc->has_new, 1); - bp_pack_value (&bp, ltc->has_array_new, 1); - bp_pack_value (&bp, ltc->gets_delete, 2); - bp_pack_value (&bp, ltc->interface_only, 1); - bp_pack_value (&bp, ltc->interface_unknown, 1); - bp_pack_value (&bp, ltc->contains_empty_class_p, 1); - bp_pack_value (&bp, ltc->anon_aggr, 1); - bp_pack_value (&bp, ltc->non_zero_init, 1); - bp_pack_value (&bp, ltc->empty_p, 1); - bp_pack_value (&bp, ltc->vec_new_uses_cookie, 1); - bp_pack_value (&bp, ltc->declared_class, 1); - bp_pack_value (&bp, ltc->diamond_shaped, 1); - bp_pack_value (&bp, ltc->repeated_base, 1); - bp_pack_value (&bp, ltc->being_defined, 1); - bp_pack_value (&bp, ltc->java_interface, 1); - bp_pack_value (&bp, ltc->debug_requested, 1); - bp_pack_value (&bp, ltc->fields_readonly, 1); - bp_pack_value (&bp, ltc->use_template, 2); - bp_pack_value (&bp, ltc->ptrmemfunc_flag, 1); - bp_pack_value (&bp, ltc->was_anonymous, 1); - bp_pack_value (&bp, ltc->lazy_default_ctor, 1); - bp_pack_value (&bp, ltc->lazy_copy_ctor, 1); - bp_pack_value (&bp, ltc->lazy_copy_assign, 1); - bp_pack_value (&bp, ltc->lazy_destructor, 1); - bp_pack_value (&bp, ltc->has_const_copy_ctor, 1); - bp_pack_value (&bp, ltc->has_complex_copy_ctor, 1); - bp_pack_value (&bp, ltc->has_complex_copy_assign, 1); - bp_pack_value (&bp, ltc->non_aggregate, 1); - bp_pack_value (&bp, ltc->has_complex_dflt, 1); - bp_pack_value (&bp, ltc->has_list_ctor, 1); - bp_pack_value (&bp, ltc->non_std_layout, 1); - bp_pack_value (&bp, ltc->is_literal, 1); - bp_pack_value (&bp, ltc->lazy_move_ctor, 1); - bp_pack_value (&bp, ltc->lazy_move_assign, 1); - bp_pack_value (&bp, ltc->has_complex_move_ctor, 1); - bp_pack_value (&bp, ltc->has_complex_move_assign, 1); - bp_pack_value (&bp, ltc->has_constexpr_ctor, 1); - pph_out_bitpack (stream, &bp); - - pph_out_tree (stream, ltc->primary_base); - pph_out_tree_pair_vec (stream, ltc->vcall_indices); - pph_out_tree (stream, ltc->vtables); - pph_out_tree (stream, ltc->typeinfo_var); - pph_out_tree_vec (stream, ltc->vbases); - if (!pph_out_start_record (stream, ltc->nested_udts, PPH_binding_table)) - pph_out_binding_table (stream, ltc->nested_udts); - pph_out_tree (stream, ltc->as_base); - pph_out_tree_vec (stream, ltc->pure_virtuals); - pph_out_tree (stream, ltc->friend_classes); - pph_out_tree_vec (stream, ltc->methods); - pph_out_tree (stream, ltc->key_method); - pph_out_tree (stream, ltc->decl_list); - pph_out_tree (stream, ltc->template_info); - pph_out_tree (stream, ltc->befriending_classes); - pph_out_tree (stream, ltc->objc_info); - pph_out_sorted_fields_type (stream, ltc->sorted_fields); - pph_out_tree (stream, ltc->lambda_expr); -} - - -/* Write struct lang_type_ptrmem instance LTP to STREAM. */ - -static void -pph_out_lang_type_ptrmem (pph_stream *stream, struct lang_type_ptrmem *ltp) -{ - pph_out_tree (stream, ltp->record); -} - - -/* Write all the lang-specific fields of TYPE to STREAM. */ - -static void -pph_out_lang_type (pph_stream *stream, tree type) -{ - struct lang_type *lt; - - lt = TYPE_LANG_SPECIFIC (type); - if (pph_out_start_record (stream, lt, PPH_lang_type)) - return; - - pph_out_lang_type_header (stream, <->u.h); - if (lt->u.h.is_lang_type_class) - pph_out_lang_type_class (stream, <->u.c); - else - pph_out_lang_type_ptrmem (stream, <->u.ptrmem); -} - - -/* Write to STREAM the body of tcc_type node TYPE. */ - -static void -pph_out_tcc_type (pph_stream *stream, tree type) -{ - pph_out_lang_type (stream, type); - pph_out_tree (stream, TYPE_POINTER_TO (type)); - pph_out_tree (stream, TYPE_REFERENCE_TO (type)); - pph_out_tree (stream, TYPE_NEXT_VARIANT (type)); - /* FIXME pph - Streaming TYPE_CANONICAL generates many type comparison - failures. Why? */ - pph_out_tree (stream, TREE_CHAIN (type)); - - /* The type values cache is built as constants are instantiated, - so we only stream it on the nodes that use it for - other purposes. */ - switch (TREE_CODE (type)) - { - case BOUND_TEMPLATE_TEMPLATE_PARM: - case DECLTYPE_TYPE: - case TEMPLATE_TEMPLATE_PARM: - case TEMPLATE_TYPE_PARM: - case TYPENAME_TYPE: - case TYPEOF_TYPE: - pph_out_tree (stream, TYPE_VALUES_RAW (type)); - break; - - default: - break; - } -} - - -/* Write to STREAM the body of tcc_declaration tree DECL. */ - -static void -pph_out_tcc_declaration (pph_stream *stream, tree decl) -{ - pph_out_lang_specific (stream, decl); - pph_out_tree (stream, DECL_INITIAL (decl)); - - /* The tree streamer only writes DECL_CHAIN for PARM_DECL nodes. - We need to write DECL_CHAIN for variables and functions because - they are sometimes chained together in places other than regular - tree chains. For example in BINFO_VTABLEs, the decls are chained - together). */ - if (TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL) - pph_out_tree (stream, DECL_CHAIN (decl)); - - /* Handle some individual decl nodes. */ - switch (TREE_CODE (decl)) - { - case FUNCTION_DECL: - /* Note that for FUNCTION_DECLs 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 (stream, DECL_SAVED_TREE (decl)); - break; - - case TYPE_DECL: - pph_out_tree (stream, DECL_ORIGINAL_TYPE (decl)); - break; - - case TEMPLATE_DECL: - pph_out_tree (stream, DECL_TEMPLATE_RESULT (decl)); - pph_out_tree (stream, DECL_TEMPLATE_PARMS (decl)); - break; - - default: - break; - } -} - - -/******************************************************** tree head and body */ - - -/* Write the body of EXPR to STREAM. This writes out all fields not - written by the generic tree streaming routines. */ - -static void -pph_out_tree_body (pph_stream *stream, tree expr) -{ - bool handled_p; - - /* Write the language-independent parts of EXPR's body. */ - streamer_write_tree_body (stream->encoder.w.ob, expr, false); - - /* Handle common tree code classes first. */ - handled_p = true; - switch (TREE_CODE_CLASS (TREE_CODE (expr))) - { - case tcc_declaration: - pph_out_tcc_declaration (stream, expr); - break; - - case tcc_type: - pph_out_tcc_type (stream, expr); - break; - - case tcc_constant: - if (TREE_CODE (expr) == PTRMEM_CST) - { - pph_out_tree_common (stream, expr); - pph_out_tree (stream, PTRMEM_CST_MEMBER (expr)); - } - break; - - case tcc_expression: - case tcc_unary: - case tcc_binary: - case tcc_vl_exp: - case tcc_reference: - case tcc_comparison: - case tcc_statement: - /* These tree classes are completely handled by the tree streamer. */ - break; - - default: - handled_p = false; - break; - } - - /* If we've already handled the tree, we are done. */ - if (handled_p) - return; - - /* Only tcc_exceptional tree codes are left to handle. */ - gcc_assert (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_exceptional); - - switch (TREE_CODE (expr)) - { - case STATEMENT_LIST: - { - tree_stmt_iterator i; - unsigned num_stmts; - - /* Compute and write the number of statements in the list. */ - for (num_stmts = 0, i = tsi_start (expr); !tsi_end_p (i); tsi_next (&i)) - num_stmts++; - - pph_out_uint (stream, num_stmts); - - /* Write the statements. */ - for (i = tsi_start (expr); !tsi_end_p (i); tsi_next (&i)) - pph_out_tree (stream, tsi_stmt (i)); - } - break; - - case OVERLOAD: - pph_out_tree_common (stream, expr); - pph_out_tree (stream, OVL_CURRENT (expr)); - break; - - case IDENTIFIER_NODE: - pph_out_cxx_binding (stream, IDENTIFIER_NAMESPACE_BINDINGS (expr)); - pph_out_cxx_binding (stream, IDENTIFIER_BINDING (expr)); - pph_out_tree (stream, IDENTIFIER_TEMPLATE (expr)); - pph_out_tree (stream, IDENTIFIER_LABEL_VALUE (expr)); - pph_out_tree (stream, REAL_IDENTIFIER_TYPE_VALUE (expr)); - break; - - case BASELINK: - pph_out_tree_common (stream, expr); - pph_out_tree (stream, BASELINK_BINFO (expr)); - pph_out_tree (stream, BASELINK_FUNCTIONS (expr)); - pph_out_tree (stream, BASELINK_ACCESS_BINFO (expr)); - break; - - case TEMPLATE_INFO: - pph_out_tree_common (stream, expr); - pph_out_qual_use_vec (stream, TI_TYPEDEFS_NEEDING_ACCESS_CHECKING (expr)); - break; - - case DEFAULT_ARG: - pph_out_tree_common (stream, expr); - pph_out_token_cache (stream, DEFARG_TOKENS (expr)); - pph_out_tree_vec (stream, DEFARG_INSTANTIATIONS (expr)); - break; - - case STATIC_ASSERT: - pph_out_tree_common (stream, expr); - pph_out_tree (stream, STATIC_ASSERT_CONDITION (expr)); - pph_out_tree (stream, STATIC_ASSERT_MESSAGE (expr)); - pph_out_location (stream, STATIC_ASSERT_SOURCE_LOCATION (expr)); - break; - - case ARGUMENT_PACK_SELECT: - pph_out_tree_common (stream, expr); - pph_out_tree (stream, ARGUMENT_PACK_SELECT_FROM_PACK (expr)); - pph_out_uint (stream, ARGUMENT_PACK_SELECT_INDEX (expr)); - break; - - case TRAIT_EXPR: - pph_out_tree_common (stream, expr); - pph_out_tree (stream, TRAIT_EXPR_TYPE1 (expr)); - pph_out_tree (stream, TRAIT_EXPR_TYPE2 (expr)); - pph_out_uint (stream, TRAIT_EXPR_KIND (expr)); - break; - - case LAMBDA_EXPR: - pph_out_tree_common (stream, expr); - pph_out_location (stream, LAMBDA_EXPR_LOCATION (expr)); - pph_out_tree (stream, LAMBDA_EXPR_CAPTURE_LIST (expr)); - pph_out_tree (stream, LAMBDA_EXPR_THIS_CAPTURE (expr)); - pph_out_tree (stream, LAMBDA_EXPR_RETURN_TYPE (expr)); - pph_out_tree (stream, LAMBDA_EXPR_EXTRA_SCOPE (expr)); - pph_out_uint (stream, LAMBDA_EXPR_DISCRIMINATOR (expr)); - break; - - case TREE_VEC: - /* TREE_VECs hold template argument lists. */ - pph_out_tree (stream, NON_DEFAULT_TEMPLATE_ARGS_COUNT (expr)); - break; - - case PLACEHOLDER_EXPR: - pph_out_tree (stream, TREE_TYPE (expr)); - break; - - case TEMPLATE_PARM_INDEX: - pph_out_tree_common (stream, expr); - pph_out_uint (stream, TEMPLATE_PARM_IDX (expr)); - pph_out_uint (stream, TEMPLATE_PARM_LEVEL (expr)); - pph_out_uint (stream, TEMPLATE_PARM_ORIG_LEVEL (expr)); - pph_out_uint (stream, TEMPLATE_PARM_NUM_SIBLINGS (expr)); - pph_out_tree (stream, TEMPLATE_PARM_DECL (expr)); - break; - - case DEFERRED_NOEXCEPT: - pph_out_tree (stream, DEFERRED_NOEXCEPT_PATTERN (expr)); - pph_out_tree (stream, DEFERRED_NOEXCEPT_ARGS (expr)); - break; - - /* TREES ALREADY HANDLED */ - case ERROR_MARK: - case TREE_LIST: - case BLOCK: - case CONSTRUCTOR: - case SSA_NAME: - case TREE_BINFO: - break; - - /* TREES UNIMPLEMENTED */ - case OMP_CLAUSE: - case OPTIMIZATION_NODE: - case TARGET_OPTION_NODE: - fatal_error ("PPH: unimplemented tree node '%s'", - pph_tree_code_text (TREE_CODE (expr))); - break; - - /* TREES UNRECOGNIZED */ - default: - fatal_error ("PPH: unrecognized tree node '%s'", - pph_tree_code_text (TREE_CODE (expr))); - } -} - - -/* Pack all the bitfields of EXPR into BP. */ - -static void -pph_pack_value_fields (struct bitpack_d *bp, tree expr) -{ - /* First pack all the language-independent bitfields. */ - streamer_pack_tree_bitfields (bp, expr); - - /* Now pack all the bitfields not handled by the generic packer. */ - if (TYPE_P (expr)) - { - bp_pack_value (bp, TYPE_LANG_FLAG_0 (expr), 1); - bp_pack_value (bp, TYPE_LANG_FLAG_1 (expr), 1); - bp_pack_value (bp, TYPE_LANG_FLAG_2 (expr), 1); - bp_pack_value (bp, TYPE_LANG_FLAG_3 (expr), 1); - bp_pack_value (bp, TYPE_LANG_FLAG_4 (expr), 1); - bp_pack_value (bp, TYPE_LANG_FLAG_5 (expr), 1); - bp_pack_value (bp, TYPE_LANG_FLAG_6 (expr), 1); - } - else if (DECL_P (expr)) - { - bp_pack_value (bp, DECL_LANG_FLAG_0 (expr), 1); - bp_pack_value (bp, DECL_LANG_FLAG_1 (expr), 1); - bp_pack_value (bp, DECL_LANG_FLAG_2 (expr), 1); - bp_pack_value (bp, DECL_LANG_FLAG_3 (expr), 1); - bp_pack_value (bp, DECL_LANG_FLAG_4 (expr), 1); - bp_pack_value (bp, DECL_LANG_FLAG_5 (expr), 1); - bp_pack_value (bp, DECL_LANG_FLAG_6 (expr), 1); - bp_pack_value (bp, DECL_LANG_FLAG_7 (expr), 1); - bp_pack_value (bp, DECL_LANG_FLAG_8 (expr), 1); - } - - bp_pack_value (bp, TREE_LANG_FLAG_0 (expr), 1); - bp_pack_value (bp, TREE_LANG_FLAG_1 (expr), 1); - bp_pack_value (bp, TREE_LANG_FLAG_2 (expr), 1); - bp_pack_value (bp, TREE_LANG_FLAG_3 (expr), 1); - bp_pack_value (bp, TREE_LANG_FLAG_4 (expr), 1); - bp_pack_value (bp, TREE_LANG_FLAG_5 (expr), 1); - bp_pack_value (bp, TREE_LANG_FLAG_6 (expr), 1); -} - - -/* Write the header fields for EXPR to STREAM. This header contains - all the data needed to rematerialize EXPR on the reader side and - a bitpack with all the bitfield values in EXPR. */ - -static void -pph_out_tree_header (pph_stream *stream, tree expr) -{ - struct bitpack_d bp; - struct output_block *ob = stream->encoder.w.ob; - - /* Write the header, containing everything needed to materialize EXPR - on the reading side. */ - streamer_write_tree_header (ob, expr); - - /* Process C++ specific codes that need more data in the header - for the reader to allocate them. */ - if (TREE_CODE (expr) == AGGR_INIT_EXPR) - pph_out_uint (stream, aggr_init_expr_nargs (expr)); - - /* Pack all the non-pointer fields in EXPR into a bitpack and write - the resulting bitpack. */ - bp = bitpack_create (ob->main_stream); - pph_pack_value_fields (&bp, expr); - pph_out_bitpack (stream, &bp); -} - - -/* Return the merge name string identifier tree for a decl EXPR. The - caller is responsible of freeing the returned string. */ - -static char * -pph_merge_name (tree expr) -{ - char *retval; - size_t len; - const char *mangled_str, *name_str; - tree name; - - unsigned flags = TFF_PLAIN_IDENTIFIER - | TFF_SCOPE - | TFF_DECL_SPECIFIERS - | TFF_CLASS_KEY_OR_ENUM - | TFF_RETURN_TYPE; - - if (TYPE_P (expr)) - expr = TYPE_NAME (expr); - - name_str = decl_as_string (expr, flags); - - name = DECL_NAME (expr); - if (name) - { - if (TREE_CODE (expr) == FUNCTION_DECL) - flags |= TFF_RETURN_TYPE - | TFF_FUNCTION_DEFAULT_ARGUMENTS - | TFF_EXCEPTION_SPECIFICATION; - else if (TREE_CODE (expr) == TEMPLATE_DECL) - flags |= TFF_TEMPLATE_HEADER - | TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS; - mangled_str = IDENTIFIER_POINTER (get_mangled_id (expr)); - len = strlen (name_str) + sizeof("|") + strlen (mangled_str); - retval = XNEWVEC (char, len + 1); - sprintf (retval, "%s|%s", name_str, mangled_str); - } - else - { - location_t locus = DECL_SOURCE_LOCATION (expr); - expanded_location xloc = expand_location (locus); - /* There are at most 20 digits in size_t. Add :| for 22 characters. */ - len = strlen (name_str) + strlen (xloc.file) + 22; - retval = XNEWVEC (char, len + 1); - sprintf (retval, "%s|%s:%u", name_str, xloc.file, xloc.line); - } - - return retval; -} - - -/* Write the merge name string for a decl EXPR. */ - -static void -pph_out_merge_name (pph_stream *stream, tree expr) -{ - char *name = pph_merge_name (expr); - pph_out_string (stream, name); - free (name); -} - - -/* Write the merge key for tree EXPR to STREAM. */ - -static void -pph_out_merge_key_tree (pph_stream *stream, tree expr) -{ - gcc_assert (pph_tree_is_mergeable (expr)); - - if (pph_out_start_merge_key_record (stream, expr)) - return; - - if (flag_pph_tracer) - pph_trace_tree (expr, pph_trace_front, pph_trace_key_out); - - /* Write merge key information. This includes EXPR's header (needed - to re-allocate EXPR in the reader) and the merge key, used to - lookup EXPR in the reader's context and merge if necessary. */ - pph_out_tree_header (stream, expr); - pph_out_merge_name (stream, expr); - if (DECL_P (expr)) - { - if (TREE_CODE (expr) == NAMESPACE_DECL) - pph_out_binding_merge_keys (stream, NAMESPACE_LEVEL (expr)); -#if 0 -/* FIXME pph: Distable tree merging for the moment. */ - else if (TREE_CODE (expr) == TYPE_DECL) - pph_out_merge_key_tree (stream, TREE_TYPE (expr)); - } - else if (CLASS_TYPE_P (expr)) - { - unsigned filter = PPHF_NO_XREFS | PPHF_NO_PREFS | PPHF_NO_BUILTINS; - pph_out_merge_key_chain (stream, TYPE_FIELDS (expr), filter); - pph_out_merge_key_chain (stream, TYPE_METHODS (expr), filter); - /* FIXME pph: Nested types are broken. - pph_out_binding_table (stream, CLASSTYPE_NESTED_UTDS (expr)); - pph_out_merge_key_chain (stream, CLASSTYPE_DECL_LIST (expr), filter); - */ -#endif - } - - if (flag_pph_tracer) - pph_trace_tree (expr, pph_trace_back, pph_trace_key_out); -} - - -/* Write a tree EXPR to STREAM. */ - -void -pph_out_tree (pph_stream *stream, tree expr) -{ - enum pph_record_marker marker; - - marker = pph_out_start_tree_record (stream, expr); - - /* If EXPR is NULL or it already existed in the pickle cache, - nothing else needs to be done. */ - if (marker == PPH_RECORD_END || pph_is_reference_marker (marker)) - return; - - if (streamer_handle_as_builtin_p (expr)) - { - /* MD and NORMAL builtins do not need to be written out - completely as they are always instantiated by the compiler on - startup. The only builtins that need to be written out are - BUILT_IN_FRONTEND. For all other builtins, we simply write - the class and code. */ - gcc_assert (marker == PPH_RECORD_START_NO_CACHE); - streamer_write_builtin (stream->encoder.w.ob, expr); - return; - } - else if (TREE_CODE (expr) == INTEGER_CST) - { - /* INTEGER_CST nodes are special because they need their - original type to be materialized by the reader (to implement - TYPE_CACHED_VALUES). */ - gcc_assert (marker == PPH_RECORD_START_NO_CACHE); - streamer_write_integer_cst (stream->encoder.w.ob, expr, false); - return; - } - - if (flag_pph_tracer) - pph_trace_tree (expr, pph_trace_front, - marker == PPH_RECORD_START_MERGE_BODY ? pph_trace_merge_body - : marker == PPH_RECORD_START_MUTATED ? pph_trace_mutate - : pph_trace_normal); - - if (marker == PPH_RECORD_START || marker == PPH_RECORD_START_MUTATED) - { - - /* This is the first time we see EXPR, write it out. */ - if (marker == PPH_RECORD_START) - { - /* We only need to write EXPR's header if it needs to be - re-allocated when reading. If we are writing the mutated - state of an existing tree, then we only need to write its - body. */ - pph_out_tree_header (stream, expr); - } - - pph_out_tree_body (stream, expr); - } - else if (marker == PPH_RECORD_START_MERGE_BODY) - { - gcc_assert (pph_tree_is_mergeable (expr)); - - /* When writing a merge body, we do not need to write EXPR's - header, since that was written out when we wrote the merge - key record for it. */ - pph_out_tree_body (stream, expr); - } - else - gcc_unreachable (); - - if (flag_pph_tracer) - pph_trace_tree (expr, pph_trace_back, - marker == PPH_RECORD_START_MERGE_BODY ? pph_trace_merge_body - : marker == PPH_RECORD_START_MUTATED ? pph_trace_mutate - : pph_trace_normal); -} - - -/************************************************************* file contents */ - - -/* Emit symbol table ACTION to STREAM. */ - -static inline void -pph_out_symtab_action (pph_stream *stream, enum pph_symtab_action action) -{ - gcc_assert (action == (enum pph_symtab_action)(unsigned char) action); - pph_out_uchar (stream, action); -} - - -/* Emit callgraph NODE to STREAM. */ - -static void -pph_out_cgraph_node (pph_stream *stream, struct cgraph_node *node) -{ - struct bitpack_d bp; - - if (pph_out_start_record (stream, node, PPH_cgraph_node)) - return; - - pph_out_tree (stream, node->decl); - pph_out_cgraph_node (stream, node->origin); - pph_out_cgraph_node (stream, node->nested); - pph_out_cgraph_node (stream, node->next_nested); - pph_out_cgraph_node (stream, node->next_needed); - pph_out_cgraph_node (stream, node->next_sibling_clone); - pph_out_cgraph_node (stream, node->prev_sibling_clone); - pph_out_cgraph_node (stream, node->clones); - pph_out_cgraph_node (stream, node->clone_of); - pph_out_cgraph_node (stream, node->same_comdat_group); - gcc_assert (node->call_site_hash == NULL); - pph_out_tree (stream, node->former_clone_of); - gcc_assert (node->aux == NULL); - gcc_assert (VEC_empty (ipa_opt_pass, node->ipa_transforms_to_apply)); - - gcc_assert (VEC_empty (ipa_ref_t, node->ref_list.references)); - gcc_assert (VEC_empty (ipa_ref_ptr, node->ref_list.refering)); - - gcc_assert (node->local.lto_file_data == NULL); - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, node->local.local, 1); - bp_pack_value (&bp, node->local.externally_visible, 1); - bp_pack_value (&bp, node->local.finalized, 1); - bp_pack_value (&bp, node->local.can_change_signature, 1); - bp_pack_value (&bp, node->local.redefined_extern_inline, 1); - pph_out_bitpack (stream, &bp); - - pph_out_cgraph_node (stream, node->global.inlined_to); - - pph_out_uint (stream, node->rtl.preferred_incoming_stack_boundary); - - gcc_assert (VEC_empty (ipa_replace_map_p, node->clone.tree_map)); - pph_out_uhwi (stream, node->thunk.fixed_offset); - pph_out_uhwi (stream, node->thunk.virtual_value); - pph_out_tree (stream, node->thunk.alias); - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, node->thunk.this_adjusting, 1); - bp_pack_value (&bp, node->thunk.virtual_offset_p, 1); - bp_pack_value (&bp, node->thunk.thunk_p, 1); - pph_out_bitpack (stream, &bp); - - pph_out_uhwi (stream, node->count); - pph_out_uint (stream, node->count_materialization_scale); - - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, node->needed, 1); - bp_pack_value (&bp, node->address_taken, 1); - bp_pack_value (&bp, node->abstract_and_needed, 1); - bp_pack_value (&bp, node->reachable, 1); - bp_pack_value (&bp, node->reachable_from_other_partition, 1); - bp_pack_value (&bp, node->lowered, 1); - bp_pack_value (&bp, node->analyzed, 1); - bp_pack_value (&bp, node->in_other_partition, 1); - bp_pack_value (&bp, node->process, 1); - bp_pack_value (&bp, node->alias, 1); - bp_pack_value (&bp, node->same_body_alias, 1); - bp_pack_value (&bp, node->frequency, 2); - bp_pack_value (&bp, node->only_called_at_startup, 1); - bp_pack_value (&bp, node->only_called_at_exit, 1); - pph_out_bitpack (stream, &bp); -} - - -/* Add DECL to the symbol table for pph_out_stream. ACTION determines - how DECL should be presented to the middle-end when reading this - image. TOP_LEVEL and AT_END are as in rest_of_decl_compilation. */ - -void -pph_add_decl_to_symtab (tree decl, enum pph_symtab_action action, - bool top_level, bool at_end) -{ - pph_symtab_entry entry; - - if (decl == NULL || pph_out_stream == NULL) - return; - - gcc_assert (DECL_P (decl)); - - entry.action = action; - entry.decl = decl; - entry.top_level = top_level; - entry.at_end = at_end; - VEC_safe_push (pph_symtab_entry, heap, pph_out_stream->symtab.v, &entry); -} - - -/* 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. */ - -static void -pph_out_symtab (pph_stream *stream) -{ - pph_symtab_entry *entry; - unsigned i; - - pph_out_uint (stream, VEC_length (pph_symtab_entry, stream->symtab.v)); - FOR_EACH_VEC_ELT (pph_symtab_entry, stream->symtab.v, i, entry) - { - pph_out_symtab_action (stream, entry->action); - pph_out_tree (stream, entry->decl); - if (entry->action == PPH_SYMTAB_DECLARE) - { - struct bitpack_d bp; - bp = bitpack_create (stream->encoder.w.ob->main_stream); - bp_pack_value (&bp, entry->top_level, 1); - bp_pack_value (&bp, entry->at_end, 1); - pph_out_bitpack (stream, &bp); - } - else if (entry->action == PPH_SYMTAB_EXPAND) - { - pph_out_struct_function (stream, DECL_STRUCT_FUNCTION (entry->decl)); - pph_out_cgraph_node (stream, cgraph_get_node (entry->decl)); - } - else - gcc_unreachable (); - } -} - - -/* Save the IDENTIFIERS to the STREAM. */ - -static void -pph_out_identifiers (pph_stream *stream, cpp_idents_used *identifiers) -{ - unsigned int num_entries, active_entries, id; - - num_entries = identifiers->num_entries; - pph_out_uint (stream, identifiers->max_ident_len); - pph_out_uint (stream, identifiers->max_value_len); - - active_entries = 0; - for ( id = 0; id < num_entries; ++id ) - { - cpp_ident_use *entry = identifiers->entries + id; - if (!(entry->used_by_directive || entry->expanded_to_text)) - continue; - ++active_entries; - } - - pph_out_uint (stream, active_entries); - - for ( id = 0; id < num_entries; ++id ) - { - cpp_ident_use *entry = identifiers->entries + id; - - if (!(entry->used_by_directive || entry->expanded_to_text)) - continue; - - /* FIXME pph: We are wasting space; ident_len, used_by_directive - and expanded_to_text together could fit into a single uint. */ - - pph_out_uint (stream, entry->used_by_directive); - pph_out_uint (stream, entry->expanded_to_text); - - gcc_assert (entry->ident_len <= identifiers->max_ident_len); - pph_out_string_with_length (stream, entry->ident_str, - entry->ident_len); - - gcc_assert (entry->before_len <= identifiers->max_value_len); - pph_out_string_with_length (stream, entry->before_str, - entry->before_len); - - gcc_assert (entry->after_len <= identifiers->max_value_len); - pph_out_string_with_length (stream, entry->after_str, - entry->after_len); - } -} - - -/* Write the global bindings in scope_chain to STREAM. */ - -static void -pph_out_global_binding (pph_stream *stream) -{ - cp_binding_level *bl; - - /* We only need to write out the scope_chain->bindings, everything - else should be NULL or be some temporary disposable state. - old_namespace should be global_namespace and all entries listed - below should be NULL or 0; otherwise the header parsed was - incomplete. */ - gcc_assert (scope_chain->old_namespace == global_namespace - && !(scope_chain->class_name - || scope_chain->class_type - || scope_chain->access_specifier - || scope_chain->function_decl - || scope_chain->template_parms - || scope_chain->x_saved_tree - || scope_chain->class_bindings - || scope_chain->prev - || scope_chain->unevaluated_operand - || scope_chain->inhibit_evaluation_warnings - || scope_chain->x_processing_template_decl - || scope_chain->x_processing_specialization - || scope_chain->x_processing_explicit_instantiation - || scope_chain->need_pop_function_context - || scope_chain->x_stmt_tree.x_cur_stmt_list - || scope_chain->x_stmt_tree.stmts_are_full_exprs_p)); - - /* We need to write a record for BL before emitting the merge keys - so that the reader can associate the merge keys to it. */ - bl = scope_chain->bindings; - pph_out_start_record (stream, bl, PPH_cp_binding_level); - - /* Emit all the merge keys for objects that need to be merged when reading - multiple PPH images. */ - pph_out_binding_merge_keys (stream, bl); - pph_out_binding_merge_bodies (stream, bl); -} - - -/* Write all the contents of STREAM. */ - -static void -pph_write_file (pph_stream *stream) -{ - cpp_idents_used idents_used; - - if (flag_pph_tracer >= 1) - fprintf (pph_logfile, "PPH: Writing %s\n", pph_out_file); - - /* Emit the line table entries and references to our direct includes. */ - pph_out_line_table_and_includes (stream); - - /* Emit all the identifiers and pre-processor symbols in the global - namespace. */ - idents_used = cpp_lt_capture (parse_in); - pph_out_identifiers (stream, &idents_used); - - /* Emit the bindings for the global namespace. */ - pph_out_global_binding (stream); - - /* 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); - pph_out_tree_vec (stream, unemitted_tinfo_decls); - - pph_out_pending_templates_list (stream); - pph_out_spec_entry_tables (stream); - - pph_out_tree (stream, static_aggregates); - - /* Emit the symbol table. */ - pph_out_symtab (stream); - - if (flag_pph_dump_tree) - pph_dump_namespace (pph_logfile, global_namespace); -} - - -/******************************************************* stream finalization */ - - -/* Callback for lang_hooks.lto.begin_section. Open file NAME. */ - -static void -pph_begin_section (const char *name ATTRIBUTE_UNUSED) -{ -} - - -/* Callback for lang_hooks.lto.append_data. Write LEN bytes from DATA - into pph_out_stream. BLOCK is currently unused. */ - -static void -pph_out_data (const void *data, size_t len, void *block ATTRIBUTE_UNUSED) -{ - if (data) - { - size_t written = fwrite (data, 1, len, pph_out_stream->file); - gcc_assert (written == len); - } -} - - -/* Callback for lang_hooks.lto.end_section. */ - -static void -pph_end_section (void) -{ -} - -/* Write the header for the PPH file represented by STREAM. */ - -static void -pph_out_header (pph_stream *stream) -{ - pph_file_header header; - struct lto_output_stream header_stream; - int major, minor, patchlevel; - - /* Collect version information. */ - parse_basever (&major, &minor, &patchlevel); - gcc_assert (major == (char) major); - gcc_assert (minor == (char) minor); - gcc_assert (patchlevel == (char) patchlevel); - - /* Write the header for the PPH file. */ - memset (&header, 0, sizeof (header)); - strcpy (header.id_str, pph_id_str); - header.major_version = (char) major; - header.minor_version = (char) minor; - header.patchlevel = (char) patchlevel; - header.strtab_size = stream->encoder.w.ob->string_stream->total_size; - - memset (&header_stream, 0, sizeof (header_stream)); - lto_output_data_stream (&header_stream, &header, sizeof (header)); - lto_write_stream (&header_stream); -} - - -/* Write the body of the PPH file represented by STREAM. */ - -static void -pph_out_body (pph_stream *stream) -{ - /* Write the string table. */ - lto_write_stream (stream->encoder.w.ob->string_stream); - - /* Write the main stream where we have been pickling the parse trees. */ - lto_write_stream (stream->encoder.w.ob->main_stream); -} - - -/* Flush all the in-memory buffers for STREAM to disk. */ - -void -pph_flush_buffers (pph_stream *stream) -{ - /* Redirect the LTO basic I/O langhooks. */ - lang_hooks.lto.begin_section = pph_begin_section; - lang_hooks.lto.append_data = pph_out_data; - lang_hooks.lto.end_section = pph_end_section; - - /* Write the state buffers built by pph_out_*() calls. */ - lto_begin_section (stream->name, false); - pph_out_header (stream); - pph_out_body (stream); - lto_end_section (); -} - - -/* Finalize the PPH writer. */ - -void -pph_writer_finish (void) -{ - const char *offending_file; - - if (pph_out_stream == NULL) - return; - - offending_file = cpp_main_missing_guard (parse_in); - if (offending_file == NULL) - pph_write_file (pph_out_stream); - else - error ("header lacks guard for PPH: %s", offending_file); - - pph_stream_close (pph_out_stream); - pph_out_stream = NULL; -} - - -/* Add INCLUDE to the list of images included by pph_out_stream. */ - -void -pph_writer_add_include (pph_stream *include) -{ - pph_add_include (pph_out_stream, include); -} Index: gcc/cp/pph-streamer.h =================================================================== --- gcc/cp/pph-streamer.h (revision 181815) +++ gcc/cp/pph-streamer.h (working copy) @@ -226,13 +226,6 @@ struct pph_stream { #define PPHF_NO_XREFS (1 << 1) #define PPHF_NO_PREFS (1 << 2) -/* In pph.c */ -extern const char *pph_tree_code_text (enum tree_code code); -extern void pph_dump_min_decl (FILE *file, tree decl); -extern void pph_dump_chain (FILE *, tree chain); -extern void pph_dump_binding (FILE *, cp_binding_level *level); -extern void pph_dump_namespace (FILE *, tree ns); - enum pph_trace_kind { pph_trace_key_out, pph_trace_unmerged_key, pph_trace_merged_key, @@ -244,9 +237,9 @@ enum pph_trace_end pph_trace_front, pph_trace_back }; -/* In pph-streamer.c. */ -void pph_streamer_init (void); -void pph_streamer_finish (void); +/* In pph-core.c. */ +const char *pph_tree_code_text (enum tree_code code); +void pph_dump_namespace (FILE *, tree ns); pph_stream *pph_stream_open (const char *, const char *); void pph_mark_stream_read (pph_stream *); void pph_stream_close (pph_stream *); @@ -265,7 +258,7 @@ void pph_cache_sign (pph_cache *, unsign unsigned pph_get_signature (tree, size_t *); void pph_writer_add_include (pph_stream *); -/* In pph-streamer-out.c. */ +/* In pph-out.c. */ void pph_flush_buffers (pph_stream *); void pph_init_write (pph_stream *); void pph_write_mergeable_chain (pph_stream *, tree); @@ -274,7 +267,7 @@ void pph_writer_finish (void); void pph_out_location (pph_stream *, location_t); void pph_out_tree (pph_stream *, tree); -/* In pph-streamer-in.c. */ +/* In pph-in.c. */ void pph_init_read (pph_stream *); location_t pph_in_location (pph_stream *); pph_stream *pph_read_file (const char *);