From patchwork Mon Apr 4 10:10:29 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Diego Novillo X-Patchwork-Id: 89605 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 A60D0B6FAE for ; Mon, 4 Apr 2011 20:11:32 +1000 (EST) Received: (qmail 3863 invoked by alias); 4 Apr 2011 10:11:30 -0000 Received: (qmail 3834 invoked by uid 22791); 4 Apr 2011 10:11:23 -0000 X-SWARE-Spam-Status: No, hits=-2.2 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, SPF_HELO_PASS, TW_CL, TW_CP, TW_CX, TW_TM, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (74.125.121.67) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 04 Apr 2011 10:10:34 +0000 Received: from kpbe20.cbf.corp.google.com (kpbe20.cbf.corp.google.com [172.25.105.84]) by smtp-out.google.com with ESMTP id p34AAVgS024586; Mon, 4 Apr 2011 03:10:31 -0700 Received: from topo.tor.corp.google.com (topo.tor.corp.google.com [172.29.41.2]) by kpbe20.cbf.corp.google.com with ESMTP id p34AATg7020744; Mon, 4 Apr 2011 03:10:29 -0700 Received: by topo.tor.corp.google.com (Postfix, from userid 54752) id 25E4F1DA1BC; Mon, 4 Apr 2011 06:10:29 -0400 (EDT) To: reply@codereview.appspotmail.com, crowl@google.com, gcc-patches@gcc.gnu.org Subject: [pph] Add reading code for DECL_LANG_SPECIFIC (issue4345046) Message-Id: <20110404101029.25E4F1DA1BC@topo.tor.corp.google.com> Date: Mon, 4 Apr 2011 06:10:29 -0400 (EDT) From: dnovillo@google.com (Diego Novillo) 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 This patch adds the reading code for DECL_LANG_SPECIFIC. With this we can write and read global_namespace from a pph image. There are still missing bits, since instantiating global_namespace out of the streamed data produces an ICE in name mangling. For now, we are only writing and reading global_namespace, but not really instantiating it on the way back. For this to work, we still need to: - Skip the text of the header file that is being instantiated from an image. - Add the missing data to fix the name mangling issues. The bulk of the patch deals with the routines to unpickle the DECL_LANG_SPECIFIC structures that we are writing out (all the new routines in pph-streamer-in.c). Nothing too exciting there, just the mirror of the same routines in pph-streamer-out.c. I had to add a few more streamer hooks: - Allocate memory. Not every node can be built with make_node. In the case of CALL_EXPR, we need to explicitly allocate the number of arguments to the call. - Write tree header. The complement to the above, when writing some streamer-specific nodes, we may need to add more data in the header so the node can be re-built during reading. - Registering decls in LTO symtabs. This is not used by the FE streamer. There is a new boolean field that the common streamer code checks to see if it needs to register decls instantiated from a stream. Added new routines to read/write bitpacks from PPH and also to read/write token caches (for deferred inline functions). Tested on x86_64. Committed to branch. gcc/cp/ChangeLog.pph 2011-04-03 Diego Novillo * cp-tree.h (cxx_binding_make): Declare. * name-lookup.c (cxx_binding_make): Make extern. * parser.c (cp_token_cache): Make extern. * parser.h (cp_token_cache): Declare. * pph-streamer-in.c (pph_stream_unpack_value_fields): Move earlier in the file. (pph_stream_init_read): Call lto_reader_init. Associate STREAM with STREAM->DATA_IN. (pph_start_record): New. (pph_stream_read_ld_base): New. (pph_stream_read_ld_min): New. (pph_stream_read_tree_vec): New. (pph_stream_read_cxx_binding_1): New. (pph_stream_read_cxx_binding): New. (pph_stream_read_class_binding): New. (pph_stream_read_label_binding): New. (pph_stream_read_binding_level): New. (pph_stream_read_c_language_function): New. (pph_stream_read_language_function): New. (pph_stream_read_ld_fn): New. (pph_stream_read_ld_ns): New. (pph_stream_read_ld_parm): New. (pph_stream_read_lang_specific_data): New. (pph_stream_read_tree): Retrieve pph_stream instance from DATA_IN->SDATA. Mark IB argument as unused. Call pph_stream_read_lang_specific_data for DECLs that have lang_specific data. Replace calls to lto_input_sleb128 with pph_input_uint. (pph_stream_alloc_tree): New. * pph-streamer-out.c (pph_stream_init_write): Call lto_writer_init. Associate STREAM with OB. (pph_start_record): New. (pph_stream_write_ld_base): Change first argument to be a pph_stream. Change all users. Call pph_start_record. Call pph_output_bitpack. (pph_stream_write_ld_min): Likewise. (pph_stream_write_tree_vec): Likewise. (pph_stream_write_cxx_binding_1): Likewise. (pph_stream_write_cxx_binding): Likewise. (pph_stream_write_class_binding): Likewise. (pph_stream_write_label_binding): Likewise. (pph_stream_write_binding_level): Likewise. (pph_stream_write_c_language_function): Likewise. (pph_stream_write_language_function): Likewise. (pph_stream_write_ld_fn): Likewise. (pph_stream_write_ld_ns): Likewise. (pph_stream_write_ld_parm): Likewise. (pph_stream_write_lang_specific_data): Likewise. (pph_stream_write_tree): Only call pph_stream_write_lang_specific_data for tree nodes that have DECL_LANG_SPECIFIC set. * pph-streamer.c (enum pph_trace_type): Add PPH_TRACE_CHAIN and PPH_TRACE_BITPACK. (pph_stream_trace): Add "chain" and "bitpack" to TYPE_S. Handle PPH_TRACE_CHAIN And PPH_TRACE_BITPACK. (pph_stream_trace_tree): Do not compute tree code size on NULL_TREE. (pph_stream_trace_chain): New. (pph_stream_trace_bitpack): New. (pph_stream_output_tree_header): New. (pph_stream_hooks_init): Add hooks for alloc_tree and output_tree_header. * pph-streamer.h (PPH_RECORD_START): Declare. (PPH_RECORD_END): Declare. (pph_stream_trace_chain): Declare. (pph_stream_trace_bitpack): Declare. (pth_load_token_cache): Declare. (pph_output_tree_or_ref): New. (pph_output_uchar): New. (pph_output_string_with_length): Do not trace the string twice. (pph_output_chain): New. (pph_output_bitpack): New. (pph_input_uchar): New. (pph_input_chain): New. (pph_input_bitpack): New. (pph_get_pph_stream): Remove. Update all users. (pph_set_pph_stream): Remove. Update all users. (pph_stream_output_tree_header): Declare. (pph_stream_alloc_tree): Declare. * pph.c (pth_load_token): Factor out of pth_load_hunk. (pth_load_token_cache): New. (pph_read_file_contents): Read global_namespace. gcc/ChangeLog.pph * lto-streamer-in.c (lto_input_tree_pointers): Remove checks for TS_SSA_NAME, TS_STATEMENT_LIST, TS_OMP_CLAUSE and TS_OPTIMIZATION. (lto_read_tree): Check for streamer_hooks.register_decls_in_symtab_p before registering symbols in LTO symtabs. (gimple_streamer_reader_init): Move file_name_hash_table initialization to lto_reader_init. (lto_materialize_tree): Call streamer_hooks.alloc_tree if it exists. * lto-streamer-out.c (lto_output_tree_header): Remove empty line. (lto_output_tree_header): Assert that the tag to be written is valid. Call streamer_hooks.output_tree_header if it exists. * lto-streamer.c (gimple_streamer_hooks_init): Set register_decls_in_symtab_p to true. * lto-streamer.h (struct lto_streamer_hooks): Add field register_decls_in_symtab_p. (struct lto_file_decl_data): Add field sdata. (struct output_block): Add field sdata. (struct lto_streamer_hooks): Add fields alloc_tree and output_tree_header. (enum LTO_tags): Add an LTO_LAST_TAG marker, force LTO_NUM_TAGS have a value bigger than MAX_TREE_CODES and LAST_AND_UNUSED_GIMPLE_CODE. (lto_tag_is_tree_code_p): Return true for anything less than MAX_TREE_CODES. --- This patch is available for review at http://codereview.appspot.com/4345046 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index aedcab2..9ce164b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4757,6 +4757,7 @@ extern tree check_for_out_of_scope_variable (tree); extern void print_other_binding_stack (struct cp_binding_level *); extern tree maybe_push_decl (tree); extern tree current_decl_namespace (void); +extern cxx_binding *cxx_binding_make (tree, tree); /* decl.c */ extern tree poplevel (int, int, int); diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index defb9d9..dc9cef2 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -285,7 +285,7 @@ cxx_binding_init (cxx_binding *binding, tree value, tree type) /* (GC)-allocate a binding object with VALUE and TYPE member initialized. */ -static cxx_binding * +cxx_binding * cxx_binding_make (tree value, tree type) { cxx_binding *binding; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ef29f3d..e146048 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -230,9 +230,6 @@ static void cp_lexer_print_token (FILE *, cp_token *); #endif /* ENABLE_CHECKING */ -static cp_token_cache *cp_token_cache_new - (cp_token *, cp_token *); - static void cp_parser_initial_pragma (cp_token *); @@ -1003,7 +1000,7 @@ cp_lexer_stop_debugging (cp_lexer* lexer) /* Create a new cp_token_cache, representing a range of tokens. */ -static cp_token_cache * +cp_token_cache * cp_token_cache_new (cp_token *first, cp_token *last) { cp_token_cache *cache = ggc_alloc_cp_token_cache (); diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 50efabc..ac08918 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -374,5 +374,6 @@ extern void cp_lexer_dump_tokens (FILE *, VEC(cp_token,gc) *, unsigned); extern void cp_lexer_get_tokens (cp_lexer *); extern cp_token_position cp_lexer_token_position (cp_lexer *, bool); extern void cp_lexer_debug_tokens (VEC(cp_token,gc) *); +extern cp_token_cache *cp_token_cache_new (cp_token *, cp_token *); #endif /* GCC_CP_PARSER_H */ diff --git a/gcc/cp/pph-streamer-in.c b/gcc/cp/pph-streamer-in.c index aaa0a6c..af7cd57 100644 --- a/gcc/cp/pph-streamer-in.c +++ b/gcc/cp/pph-streamer-in.c @@ -32,6 +32,16 @@ along with GCC; see the file COPYING3. If not see #include "version.h" #include "cppbuiltin.h" +/* Callback for unpacking value fields in ASTs. BP is the bitpack + we are unpacking from. EXPR is the tree to unpack. */ + +void +pph_stream_unpack_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, + tree expr ATTRIBUTE_UNUSED) +{ + /* Do nothing for now. */ +} + /* Get the section with name NAME and type SECTION_TYPE from FILE_DATA. Return a pointer to the start of the section contents and store @@ -82,6 +92,8 @@ pph_stream_init_read (pph_stream *stream) pph_file_header *header; const char *strtab, *body; + lto_reader_init (); + /* Read STREAM->NAME into the memory buffer STREAM->FILE_DATA. FIXME pph, we are reading the whole file at once. This seems wasteful. */ @@ -118,6 +130,436 @@ pph_stream_init_read (pph_stream *stream) LTO_INIT_INPUT_BLOCK_PTR (stream->ib, body, 0, body_size); stream->data_in = lto_data_in_create (stream->pph_sections[0], strtab, strtab_size, NULL); + + /* Associate STREAM with STREAM->DATA_IN so we can recover it from + the streamer hooks. */ + stream->data_in->sdata = (void *) stream; +} + + +/* Read and return a record marker from STREAM. The marker + must be one of PPH_RECORD_START or PPH_RECORD_END. If PPH_RECORD_END + is read, return false. Otherwise, return true. */ + +static inline bool +pph_start_record (pph_stream *stream) +{ + unsigned char marker = pph_input_uchar (stream); + gcc_assert (marker == PPH_RECORD_START || marker == PPH_RECORD_END); + return (marker == PPH_RECORD_START); +} + + +/* Read all fields in lang_decl_base instance LDB from STREAM. */ + +static void +pph_stream_read_ld_base (pph_stream *stream, struct lang_decl_base *ldb) +{ + struct bitpack_d bp; + + if (!pph_start_record (stream)) + return; + + bp = pph_input_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_stream_read_ld_min (pph_stream *stream, struct lang_decl_min *ldm) +{ + if (!pph_start_record (stream)) + return; + + gcc_assert (ldm->base.selector == 0); + + ldm->template_info = pph_input_tree (stream); + if (ldm->base.u2sel == 0) + ldm->u2.access = pph_input_tree (stream); + else if (ldm->base.u2sel == 1) + ldm->u2.discriminator = pph_input_uint (stream); + else + gcc_unreachable (); +} + + +/* Read and return a VEC of trees from STREAM. */ + +static VEC(tree,gc) * +pph_stream_read_tree_vec (pph_stream *stream) +{ + unsigned i, num; + VEC(tree,gc) *v; + + num = pph_input_uint (stream); + v = NULL; + for (i = 0; i < num; i++) + { + tree t = pph_input_tree (stream); + VEC_safe_push (tree, gc, v, t); + } + + return v; +} + +/* Forward declaration to break cyclic dependencies. */ +static struct cp_binding_level *pph_stream_read_binding_level (pph_stream *); + +/* Helper for pph_stream_read_cxx_binding. Read and return a cxx_binding + instance from STREAM. */ + +static cxx_binding * +pph_stream_read_cxx_binding_1 (pph_stream *stream) +{ + struct bitpack_d bp; + cxx_binding *cb; + tree value, type; + + if (!pph_start_record (stream)) + return NULL; + + value = pph_input_tree (stream); + type = pph_input_tree (stream); + cb = cxx_binding_make (value, type); + cb->scope = pph_stream_read_binding_level (stream); + bp = pph_input_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_stream_read_cxx_binding (pph_stream *stream) +{ + unsigned i, num_bindings; + cxx_binding *curr, *cb; + + if (!pph_start_record (stream)) + return NULL; + + /* Read the list of previous bindings. */ + num_bindings = pph_input_uint (stream); + for (curr = NULL, i = 0; i < num_bindings; i++) + { + cxx_binding *prev = pph_stream_read_cxx_binding_1 (stream); + if (curr) + curr->previous = prev; + curr = prev; + } + + /* Read the current binding at the end. */ + cb = pph_stream_read_cxx_binding_1 (stream); + cb->previous = curr; + + return cb; +} + + +/* Read all the fields of cp_class_binding instance CB to OB. REF_P + is true if the tree fields should be written as references. */ + +static cp_class_binding * +pph_stream_read_class_binding (pph_stream *stream) +{ + cp_class_binding *cb; + + if (!pph_start_record (stream)) + return NULL; + + cb = ggc_alloc_cleared_cp_class_binding (); + memcpy (&cb->base, pph_stream_read_cxx_binding (stream), + sizeof (cxx_binding)); + cb->identifier = pph_input_tree (stream); + + return cb; +} + + +/* Read and return an instance of cp_label_binding from STREAM. */ + +static cp_label_binding * +pph_stream_read_label_binding (pph_stream *stream) +{ + cp_label_binding *lb; + + if (!pph_start_record (stream)) + return NULL; + + lb = ggc_alloc_cleared_cp_label_binding (); + lb->label = pph_input_tree (stream); + lb->prev_value = pph_input_tree (stream); + + return lb; +} + + +/* Read and return an instance of cp_binding_level from STREAM. */ + +static struct cp_binding_level * +pph_stream_read_binding_level (pph_stream *stream) +{ + unsigned i, num; + cp_label_binding *sl; + struct cp_binding_level *bl; + struct bitpack_d bp; + + if (!pph_start_record (stream)) + return NULL; + + bl = ggc_alloc_cleared_cp_binding_level (); + bl->names = pph_input_chain (stream); + bl->names_size = pph_input_uint (stream); + bl->namespaces = pph_input_chain (stream); + + bl->static_decls = pph_stream_read_tree_vec (stream); + + bl->usings = pph_input_chain (stream); + bl->using_directives = pph_input_chain (stream); + + num = pph_input_uint (stream); + bl->class_shadowed = NULL; + for (i = 0; i < num; i++) + { + cp_class_binding *cb = pph_stream_read_class_binding (stream); + VEC_safe_push (cp_class_binding, gc, bl->class_shadowed, cb); + } + + bl->type_shadowed = pph_input_tree (stream); + + num = pph_input_uint (stream); + bl->shadowed_labels = NULL; + for (i = 0; VEC_iterate (cp_label_binding, bl->shadowed_labels, i, sl); i++) + { + cp_label_binding *sl = pph_stream_read_label_binding (stream); + VEC_safe_push (cp_label_binding, gc, bl->shadowed_labels, sl); + } + + bl->blocks = pph_input_chain (stream); + bl->this_entity = pph_input_tree (stream); + bl->level_chain = pph_stream_read_binding_level (stream); + bl->dead_vars_from_for = pph_stream_read_tree_vec (stream); + bl->statement_list = pph_input_chain (stream); + bl->binding_depth = pph_input_uint (stream); + + bp = pph_input_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); + + return bl; +} + + +/* Read and return an instance of struct c_language_function from STREAM. */ + +static struct c_language_function * +pph_stream_read_c_language_function (pph_stream *stream) +{ + struct c_language_function *clf; + + if (!pph_start_record (stream)) + return NULL; + + clf = ggc_alloc_cleared_c_language_function (); + clf->x_stmt_tree.x_cur_stmt_list = pph_input_tree (stream); + clf->x_stmt_tree.stmts_are_full_exprs_p = pph_input_uint (stream); + + return clf; +} + + +/* Read and return an instance of struct language_function from STREAM. */ + +static struct language_function * +pph_stream_read_language_function (pph_stream *stream) +{ + struct bitpack_d bp; + struct language_function *lf; + + if (!pph_start_record (stream)) + return NULL; + + lf = ggc_alloc_cleared_language_function (); + memcpy (&lf->base, pph_stream_read_c_language_function (stream), + sizeof (struct c_language_function)); + lf->x_cdtor_label = pph_input_tree (stream); + lf->x_current_class_ptr = pph_input_tree (stream); + lf->x_current_class_ref = pph_input_tree (stream); + lf->x_eh_spec_block = pph_input_tree (stream); + lf->x_in_charge_parm = pph_input_tree (stream); + lf->x_vtt_parm = pph_input_tree (stream); + lf->x_return_value = pph_input_tree (stream); + bp = pph_input_bitpack (stream); + lf->x_returns_value = bp_unpack_value (&bp, 1); + lf->x_returns_null = bp_unpack_value (&bp, 1); + lf->x_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_stream_read_binding_level (stream); + lf->x_local_names = pph_stream_read_tree_vec (stream); + + /* FIXME pph. We are not reading lf->extern_decl_map. */ + + return lf; +} + + +/* Read all the fields of lang_decl_fn instance LDF from STREAM. */ + +static void +pph_stream_read_ld_fn (pph_stream *stream, struct lang_decl_fn *ldf) +{ + struct bitpack_d bp; + + if (!pph_start_record (stream)) + return; + + bp = pph_input_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_input_tree (stream); + ldf->context = pph_input_tree (stream); + + if (ldf->thunk_p == 0) + ldf->u5.cloned_function = pph_input_tree (stream); + else if (ldf->thunk_p == 1) + ldf->u5.fixed_offset = pph_input_uint (stream); + else + gcc_unreachable (); + + if (ldf->pending_inline_p == 1) + ldf->u.pending_inline_info = pth_load_token_cache (stream); + else if (ldf->pending_inline_p == 0) + ldf->u.saved_language_function = pph_stream_read_language_function (stream); +} + + +/* Read all the fields of lang_decl_ns instance LDNS from STREAM. */ + +static void +pph_stream_read_ld_ns (pph_stream *stream, struct lang_decl_ns *ldns) +{ + if (!pph_start_record (stream)) + return; + + ldns->level = pph_stream_read_binding_level (stream); +} + + +/* Read all the fields of lang_decl_parm instance LDP from STREAM. */ + +static void +pph_stream_read_ld_parm (pph_stream *stream, struct lang_decl_parm *ldp) +{ + if (!pph_start_record (stream)) + return; + + ldp->level = pph_input_uint (stream); + ldp->index = pph_input_uint (stream); +} + + +/* Read language specific data in DECL from STREAM. */ + +static void +pph_stream_read_lang_specific_data (pph_stream *stream, tree decl) +{ + struct lang_decl *ld; + struct lang_decl_base *ldb; + + if (!pph_start_record (stream)) + return; + + /* Allocate a lang_decl structure for DECL. */ + retrofit_lang_decl (decl); + + ld = DECL_LANG_SPECIFIC (decl); + ldb = &ld->u.base; + + /* Read all the fields in lang_decl_base. */ + pph_stream_read_ld_base (stream, ldb); + + if (ldb->selector == 0) + { + /* Read all the fields in lang_decl_min. */ + pph_stream_read_ld_min (stream, &ld->u.min); + } + else if (ldb->selector == 1) + { + /* Read all the fields in lang_decl_fn. */ + pph_stream_read_ld_fn (stream, &ld->u.fn); + } + else if (ldb->selector == 2) + { + /* Read all the fields in lang_decl_ns. */ + pph_stream_read_ld_ns (stream, &ld->u.ns); + } + else if (ldb->selector == 3) + { + /* Read all the fields in lang_decl_parm. */ + pph_stream_read_ld_parm (stream, &ld->u.parm); + } + else + gcc_unreachable (); +} + + +/* Allocate a tree node with code CODE. IB and DATA_IN are used to + read more data from the stream, if needed to build this node. + Return NULL if we did not want to handle this node. In that case, + the caller will call make_node to allocate this tree. */ + +tree +pph_stream_alloc_tree (enum tree_code code, + struct lto_input_block *ib ATTRIBUTE_UNUSED, + struct data_in *data_in) +{ + pph_stream *stream = (pph_stream *) data_in->sdata; + + if (code == CALL_EXPR) + { + unsigned nargs = pph_input_uint (stream); + return build_vl_exp (CALL_EXPR, nargs + 3); + } + + return NULL_TREE; } @@ -127,29 +569,30 @@ pph_stream_init_read (pph_stream *stream) tree. */ void -pph_stream_read_tree (struct lto_input_block *ib, struct data_in *data_in, - tree expr) +pph_stream_read_tree (struct lto_input_block *ib ATTRIBUTE_UNUSED, + struct data_in *data_in, tree expr) { - if (TREE_CODE (expr) == FUNCTION_DECL) - DECL_SAVED_TREE (expr) = lto_input_tree (ib, data_in); + pph_stream *stream = (pph_stream *) data_in->sdata; + + if (DECL_P (expr)) + { + if (TREE_CODE (expr) == FUNCTION_DECL + || TREE_CODE (expr) == NAMESPACE_DECL + || TREE_CODE (expr) == PARM_DECL + || LANG_DECL_HAS_MIN (expr)) + { + pph_stream_read_lang_specific_data (stream, expr); + if (TREE_CODE (expr) == FUNCTION_DECL) + DECL_SAVED_TREE (expr) = pph_input_tree (stream); + } + } else if (TREE_CODE (expr) == STATEMENT_LIST) { - HOST_WIDE_INT i, num_trees = lto_input_sleb128 (ib); + HOST_WIDE_INT i, num_trees = pph_input_uint (stream); for (i = 0; i < num_trees; i++) { - tree stmt = lto_input_tree (ib, data_in); + tree stmt = pph_input_tree (stream); append_to_statement_list (stmt, &expr); } } } - - -/* Callback for unpacking value fields in ASTs. BP is the bitpack - we are unpacking from. EXPR is the tree to unpack. */ - -void -pph_stream_unpack_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, - tree expr ATTRIBUTE_UNUSED) -{ - /* Do nothing for now. */ -} diff --git a/gcc/cp/pph-streamer-out.c b/gcc/cp/pph-streamer-out.c index a67d60b..d1b4cec 100644 --- a/gcc/cp/pph-streamer-out.c +++ b/gcc/cp/pph-streamer-out.c @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see not allow passing a FILE handle to them. */ static FILE *current_pph_file = NULL; + /* Callback for packing value fields in ASTs. BP is the bitpack we are packing into. EXPR is the tree to pack. */ @@ -53,11 +54,15 @@ pph_stream_pack_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, void pph_stream_init_write (pph_stream *stream) { + lto_writer_init (); stream->out_state = lto_new_out_decl_state (); lto_push_out_decl_state (stream->out_state); stream->decl_state_stream = XCNEW (struct lto_output_stream); stream->ob = create_output_block (LTO_section_decls); - pph_set_pph_stream (stream->ob, stream); + + /* Associate STREAM with STREAM->OB so we can recover it from the + streamer hooks. */ + stream->ob->sdata = (void *) stream; } @@ -160,20 +165,37 @@ pph_stream_flush_buffers (pph_stream *stream) } +/* Start a new record in STREAM for data in DATA. If DATA is NULL, + write an end-of-record marker and return false. Otherwise, write a + start-of-record marker and return true. */ + +static inline bool +pph_start_record (pph_stream *stream, void *data) +{ + if (data) + { + pph_output_uchar (stream, PPH_RECORD_START); + return true; + } + else + { + pph_output_uchar (stream, PPH_RECORD_END); + return false; + } +} + + /* Write all the fields in lang_decl_base instance LDB to OB. */ static void -pph_stream_write_ld_base (struct output_block *ob, struct lang_decl_base *ldb) +pph_stream_write_ld_base (pph_stream *stream, struct lang_decl_base *ldb) { struct bitpack_d bp; - if (ldb == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, ldb)) + return; - bp = bitpack_create (ob->main_stream); + bp = bitpack_create (stream->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); @@ -186,277 +208,245 @@ pph_stream_write_ld_base (struct output_block *ob, struct lang_decl_base *ldb) bp_pack_value (&bp, ldb->template_conv_p, 1); bp_pack_value (&bp, ldb->odr_used, 1); bp_pack_value (&bp, ldb->u2sel, 1); - lto_output_bitpack (&bp); + pph_output_bitpack (stream, &bp); } -/* Write all the fields in lang_decl_min instance LDM to OB. If REF_P +/* Write all the fields in lang_decl_min instance LDM to STREAM. If REF_P is true, all tree fields should be written as references. */ static void -pph_stream_write_ld_min (struct output_block *ob, struct lang_decl_min *ldm, +pph_stream_write_ld_min (pph_stream *stream, struct lang_decl_min *ldm, bool ref_p) { - if (ldm == 0) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, ldm)) + return; gcc_assert (ldm->base.selector == 0); - lto_output_tree_or_ref (ob, ldm->template_info, ref_p); + pph_output_tree_or_ref (stream, ldm->template_info, ref_p); if (ldm->base.u2sel == 0) - lto_output_tree_or_ref (ob, ldm->u2.access, ref_p); + pph_output_tree_or_ref (stream, ldm->u2.access, ref_p); else if (ldm->base.u2sel == 1) - lto_output_sleb128_stream (ob->main_stream, ldm->u2.discriminator); + pph_output_uint (stream, ldm->u2.discriminator); else gcc_unreachable (); } -/* Write all the trees in VEC V to OB. REF_P is true if the trees should +/* Write all the trees in VEC V to STREAM. REF_P is true if the trees should be written as references. */ static void -pph_stream_write_tree_vec (struct output_block *ob, VEC(tree,gc) *v, bool ref_p) +pph_stream_write_tree_vec (pph_stream *stream, VEC(tree,gc) *v, bool ref_p) { unsigned i; tree t; - lto_output_uleb128_stream (ob->main_stream, VEC_length (tree, v)); + pph_output_uint (stream, VEC_length (tree, v)); for (i = 0; VEC_iterate (tree, v, i, t); i++) - lto_output_tree_or_ref (ob, t, ref_p); + pph_output_tree_or_ref (stream, t, ref_p); } /* Forward declaration to break cyclic dependencies. */ -static void pph_stream_write_binding_level (struct output_block *, +static void pph_stream_write_binding_level (pph_stream *, struct cp_binding_level *, bool); -/* Helper for pph_stream_write_cxx_binding. OB, CB and REF_P are as in +/* Helper for pph_stream_write_cxx_binding. STREAM, CB and REF_P are as in pph_stream_write_cxx_binding. */ static void -pph_stream_write_cxx_binding_1 (struct output_block *ob, cxx_binding *cb, - bool ref_p) +pph_stream_write_cxx_binding_1 (pph_stream *stream, cxx_binding *cb, bool ref_p) { struct bitpack_d bp; - if (cb == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, cb)) + return; - lto_output_tree_or_ref (ob, cb->value, ref_p); - lto_output_tree_or_ref (ob, cb->type, ref_p); - pph_stream_write_binding_level (ob, cb->scope, ref_p); - bp = bitpack_create (ob->main_stream); + pph_output_tree_or_ref (stream, cb->value, ref_p); + pph_output_tree_or_ref (stream, cb->type, ref_p); + pph_stream_write_binding_level (stream, cb->scope, ref_p); + bp = bitpack_create (stream->ob->main_stream); bp_pack_value (&bp, cb->value_is_inherited, 1); bp_pack_value (&bp, cb->is_local, 1); - lto_output_bitpack (&bp); + pph_output_bitpack (stream, &bp); } -/* Write all the fields of cxx_binding instance CB to OB. REF_P is +/* Write all the fields of cxx_binding instance CB to STREAM. REF_P is true if the tree fields should be written as references. */ static void -pph_stream_write_cxx_binding (struct output_block *ob, cxx_binding *cb, - bool ref_p) +pph_stream_write_cxx_binding (pph_stream *stream, cxx_binding *cb, bool ref_p) { unsigned num_bindings; cxx_binding *prev; - if (cb == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, cb)) + return; for (num_bindings = 0, prev = cb->previous; prev; prev = prev->previous) num_bindings++; /* Write the list of previous bindings. */ - lto_output_sleb128_stream (ob->main_stream, num_bindings); + pph_output_uint (stream, num_bindings); for (prev = cb->previous; prev; prev = prev->previous) - pph_stream_write_cxx_binding_1 (ob, prev, ref_p); + pph_stream_write_cxx_binding_1 (stream, prev, ref_p); /* Write the current binding at the end. */ - pph_stream_write_cxx_binding_1 (ob, cb, ref_p); + pph_stream_write_cxx_binding_1 (stream, cb, ref_p); } -/* Write all the fields of cp_class_binding instance CB to OB. REF_P +/* Write all the fields of cp_class_binding instance CB to STREAM. REF_P is true if the tree fields should be written as references. */ static void -pph_stream_write_class_binding (struct output_block *ob, - cp_class_binding *cb, bool ref_p) +pph_stream_write_class_binding (pph_stream *stream, cp_class_binding *cb, + bool ref_p) { - if (cb == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, cb)) + return; - pph_stream_write_cxx_binding (ob, &cb->base, ref_p); - lto_output_tree_or_ref (ob, cb->identifier, ref_p); + pph_stream_write_cxx_binding (stream, &cb->base, ref_p); + pph_output_tree_or_ref (stream, cb->identifier, ref_p); } -/* Write all the fields of cp_label_binding instance LB to OB. If +/* Write all the fields of cp_label_binding instance LB to STREAM. If REF_P is true, tree fields will be written as references. */ static void -pph_stream_write_label_binding (struct output_block *ob, - cp_label_binding *lb, bool ref_p) +pph_stream_write_label_binding (pph_stream *stream, cp_label_binding *lb, + bool ref_p) { - if (lb == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, lb)) + return; - lto_output_tree_or_ref (ob, lb->label, ref_p); - lto_output_tree_or_ref (ob, lb->prev_value, ref_p); + pph_output_tree_or_ref (stream, lb->label, ref_p); + pph_output_tree_or_ref (stream, lb->prev_value, ref_p); } -/* Write all the fields of cp_binding_level instance BL to OB. If +/* Write all the fields of cp_binding_level instance BL to STREAM. If REF_P is true, tree fields will be written as references. */ static void -pph_stream_write_binding_level (struct output_block *ob, - struct cp_binding_level *bl, bool ref_p) +pph_stream_write_binding_level (pph_stream *stream, struct cp_binding_level *bl, + bool ref_p) { unsigned i; cp_class_binding *cs; cp_label_binding *sl; struct bitpack_d bp; - if (bl == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, bl)) + return; - lto_output_chain (ob, bl->names, ref_p); - lto_output_uleb128_stream (ob->main_stream, bl->names_size); - lto_output_chain (ob, bl->namespaces, ref_p); + pph_output_chain (stream, bl->names, ref_p); + pph_output_uint (stream, bl->names_size); + pph_output_chain (stream, bl->namespaces, ref_p); - pph_stream_write_tree_vec (ob, bl->static_decls, ref_p); + pph_stream_write_tree_vec (stream, bl->static_decls, ref_p); - lto_output_chain (ob, bl->usings, ref_p); - lto_output_chain (ob, bl->using_directives, ref_p); + pph_output_chain (stream, bl->usings, ref_p); + pph_output_chain (stream, bl->using_directives, ref_p); - lto_output_uleb128_stream (ob->main_stream, VEC_length (cp_class_binding, - bl->class_shadowed)); + pph_output_uint (stream, VEC_length (cp_class_binding, bl->class_shadowed)); for (i = 0; VEC_iterate (cp_class_binding, bl->class_shadowed, i, cs); i++) - pph_stream_write_class_binding (ob, cs, ref_p); + pph_stream_write_class_binding (stream, cs, ref_p); - lto_output_tree_or_ref (ob, bl->type_shadowed, ref_p); + pph_output_tree_or_ref (stream, bl->type_shadowed, ref_p); - lto_output_uleb128_stream (ob->main_stream, VEC_length (cp_label_binding, - bl->shadowed_labels)); + pph_output_uint (stream, VEC_length (cp_label_binding, bl->shadowed_labels)); for (i = 0; VEC_iterate (cp_label_binding, bl->shadowed_labels, i, sl); i++) - pph_stream_write_label_binding (ob, sl, ref_p); + pph_stream_write_label_binding (stream, sl, ref_p); - lto_output_chain (ob, bl->blocks, ref_p); - lto_output_tree_or_ref (ob, bl->this_entity, ref_p); - pph_stream_write_binding_level (ob, bl->level_chain, ref_p); - pph_stream_write_tree_vec (ob, bl->dead_vars_from_for, ref_p); - lto_output_chain (ob, bl->statement_list, ref_p); - lto_output_sleb128_stream (ob->main_stream, bl->binding_depth); + pph_output_chain (stream, bl->blocks, ref_p); + pph_output_tree_or_ref (stream, bl->this_entity, ref_p); + pph_stream_write_binding_level (stream, bl->level_chain, ref_p); + pph_stream_write_tree_vec (stream, bl->dead_vars_from_for, ref_p); + pph_output_chain (stream, bl->statement_list, ref_p); + pph_output_uint (stream, bl->binding_depth); - bp = bitpack_create (ob->main_stream); + bp = bitpack_create (stream->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); - lto_output_bitpack (&bp); + pph_output_bitpack (stream, &bp); } -/* Write all the fields of c_language_function instance CLF to OB. If +/* Write all the fields of c_language_function instance CLF to STREAM. If REF_P is true, all tree fields should be written as references. */ static void -pph_stream_write_c_language_function (struct output_block *ob, +pph_stream_write_c_language_function (pph_stream *stream, struct c_language_function *clf, bool ref_p) { - if (clf == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, clf)) + return; - lto_output_tree_or_ref (ob, clf->x_stmt_tree.x_cur_stmt_list, ref_p); - lto_output_sleb128_stream (ob->main_stream, - clf->x_stmt_tree.stmts_are_full_exprs_p); + pph_output_tree_or_ref (stream, clf->x_stmt_tree.x_cur_stmt_list, ref_p); + pph_output_uint (stream, clf->x_stmt_tree.stmts_are_full_exprs_p); } -/* Write all the fields of language_function instance LF to OB. If +/* Write all the fields of language_function instance LF to STREAM. If REF_P is true, all tree fields should be written as references. */ static void -pph_stream_write_language_function (struct output_block *ob, +pph_stream_write_language_function (pph_stream *stream, struct language_function *lf, bool ref_p) { struct bitpack_d bp; - if (lf == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } - - pph_stream_write_c_language_function (ob, &lf->base, ref_p); - lto_output_tree_or_ref (ob, lf->x_cdtor_label, ref_p); - lto_output_tree_or_ref (ob, lf->x_current_class_ptr, ref_p); - lto_output_tree_or_ref (ob, lf->x_current_class_ref, ref_p); - lto_output_tree_or_ref (ob, lf->x_eh_spec_block, ref_p); - lto_output_tree_or_ref (ob, lf->x_in_charge_parm, ref_p); - lto_output_tree_or_ref (ob, lf->x_vtt_parm, ref_p); - lto_output_tree_or_ref (ob, lf->x_return_value, ref_p); - bp = bitpack_create (ob->main_stream); + if (!pph_start_record (stream, lf)) + return; + + pph_stream_write_c_language_function (stream, &lf->base, ref_p); + pph_output_tree_or_ref (stream, lf->x_cdtor_label, ref_p); + pph_output_tree_or_ref (stream, lf->x_current_class_ptr, ref_p); + pph_output_tree_or_ref (stream, lf->x_current_class_ref, ref_p); + pph_output_tree_or_ref (stream, lf->x_eh_spec_block, ref_p); + pph_output_tree_or_ref (stream, lf->x_in_charge_parm, ref_p); + pph_output_tree_or_ref (stream, lf->x_vtt_parm, ref_p); + pph_output_tree_or_ref (stream, lf->x_return_value, ref_p); + bp = bitpack_create (stream->ob->main_stream); bp_pack_value (&bp, lf->x_returns_value, 1); bp_pack_value (&bp, lf->x_returns_null, 1); bp_pack_value (&bp, lf->x_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); - lto_output_bitpack (&bp); + pph_output_bitpack (stream, &bp); /* FIXME pph. We are not writing lf->x_named_labels. */ - pph_stream_write_binding_level (ob, lf->bindings, ref_p); - pph_stream_write_tree_vec (ob, lf->x_local_names, ref_p); + pph_stream_write_binding_level (stream, lf->bindings, ref_p); + pph_stream_write_tree_vec (stream, lf->x_local_names, ref_p); /* FIXME pph. We are not writing lf->extern_decl_map. */ } -/* Write all the fields of lang_decl_fn instance LDF to OB. If REF_P +/* Write all the fields of lang_decl_fn instance LDF to STREAM. If REF_P is true, all tree fields should be written as references. */ static void -pph_stream_write_ld_fn (struct output_block *ob, struct lang_decl_fn *ldf, +pph_stream_write_ld_fn (pph_stream *stream, struct lang_decl_fn *ldf, bool ref_p) { struct bitpack_d bp; - if (ldf == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, ldf)) + return; - bp = bitpack_create (ob->main_stream); + bp = bitpack_create (stream->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); @@ -473,107 +463,116 @@ pph_stream_write_ld_fn (struct output_block *ob, struct lang_decl_fn *ldf, 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); - lto_output_bitpack (&bp); + pph_output_bitpack (stream, &bp); - lto_output_tree_or_ref (ob, ldf->befriending_classes, ref_p); - lto_output_tree_or_ref (ob, ldf->context, ref_p); + pph_output_tree_or_ref (stream, ldf->befriending_classes, ref_p); + pph_output_tree_or_ref (stream, ldf->context, ref_p); if (ldf->thunk_p == 0) - lto_output_tree_or_ref (ob, ldf->u5.cloned_function, ref_p); + pph_output_tree_or_ref (stream, ldf->u5.cloned_function, ref_p); else if (ldf->thunk_p == 1) - lto_output_sleb128_stream (ob->main_stream, ldf->u5.fixed_offset); + pph_output_uint (stream, ldf->u5.fixed_offset); else gcc_unreachable (); if (ldf->pending_inline_p == 1) - pth_save_token_cache (ldf->u.pending_inline_info, pph_get_pph_stream (ob)); + pth_save_token_cache (ldf->u.pending_inline_info, stream); else if (ldf->pending_inline_p == 0) - pph_stream_write_language_function (ob, ldf->u.saved_language_function, + pph_stream_write_language_function (stream, ldf->u.saved_language_function, ref_p); } -/* Write all the fields of lang_decl_ns instance LDNS to OB. If REF_P +/* Write all the fields of lang_decl_ns instance LDNS to STREAM. If REF_P is true, all tree fields should be written as references. */ static void -pph_stream_write_ld_ns (struct output_block *ob, struct lang_decl_ns *ldns, +pph_stream_write_ld_ns (pph_stream *stream, struct lang_decl_ns *ldns, bool ref_p) { struct cp_binding_level *level; - if (ldns == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, ldns)) + return; level = ldns->level; - pph_stream_write_binding_level (ob, level, ref_p); + pph_stream_write_binding_level (stream, level, ref_p); } -/* Write all the fields of lang_decl_parm instance LDP to OB. If REF_P +/* Write all the fields of lang_decl_parm instance LDP to STREAM. If REF_P is true, all tree fields should be written as references. */ static void -pph_stream_write_ld_parm (struct output_block *ob, struct lang_decl_parm *ldp) +pph_stream_write_ld_parm (pph_stream *stream, struct lang_decl_parm *ldp) { - if (ldp == NULL) - { - pph_output_uint (pph_get_pph_stream (ob), 0); - return; - } + if (!pph_start_record (stream, ldp)) + return; - lto_output_sleb128_stream (ob->main_stream, ldp->level); - lto_output_sleb128_stream (ob->main_stream, ldp->index); + pph_output_uint (stream, ldp->level); + pph_output_uint (stream, ldp->index); } -/* Write all the lang-specific data in DECL to OB. REF_P is true if +/* Write all the lang-specific data in DECL to STREAM. REF_P is true if the trees referenced in lang-specific fields should be written as references. */ static void -pph_stream_write_lang_specific_data (struct output_block *ob, - tree decl, bool ref_p) +pph_stream_write_lang_specific_data (pph_stream *stream, tree decl, bool ref_p) { struct lang_decl *ld; struct lang_decl_base *ldb; - gcc_assert (DECL_P (decl) && DECL_LANG_SPECIFIC (decl)); + gcc_assert (DECL_P (decl)); ld = DECL_LANG_SPECIFIC (decl); - ldb = &ld->u.base; - + if (!pph_start_record (stream, ld)) + return; + /* Write all the fields in lang_decl_base. */ - pph_stream_write_ld_base (ob, ldb); + ldb = &ld->u.base; + pph_stream_write_ld_base (stream, ldb); if (ldb->selector == 0) { /* Write all the fields in lang_decl_min. */ - pph_stream_write_ld_min (ob, &ld->u.min, ref_p); + pph_stream_write_ld_min (stream, &ld->u.min, ref_p); } else if (ldb->selector == 1) { /* Write all the fields in lang_decl_fn. */ - pph_stream_write_ld_fn (ob, &ld->u.fn, ref_p); + pph_stream_write_ld_fn (stream, &ld->u.fn, ref_p); } else if (ldb->selector == 2) { /* Write all the fields in lang_decl_ns. */ - pph_stream_write_ld_ns (ob, &ld->u.ns, ref_p); + pph_stream_write_ld_ns (stream, &ld->u.ns, ref_p); } else if (ldb->selector == 3) { /* Write all the fields in lang_decl_parm. */ - pph_stream_write_ld_parm (ob, &ld->u.parm); + pph_stream_write_ld_parm (stream, &ld->u.parm); } else gcc_unreachable (); } +/* Write header information for some AST nodes not handled by the + common streamer code. EXPR is the tree to write to output block + OB. If EXPR does not need to be handled specially, do nothing. */ + +void +pph_stream_output_tree_header (struct output_block *ob, tree expr) +{ + pph_stream *stream = (pph_stream *) ob->sdata; + + if (TREE_CODE (expr) == CALL_EXPR) + pph_output_uint (stream, call_expr_nargs (expr)); +} + + /* Callback for writing ASTs to a stream. This writes all the fields that are not processed by default by the common tree pickler. OB and REF_P are as in lto_write_tree. EXPR is the tree to write. */ @@ -581,13 +580,20 @@ pph_stream_write_lang_specific_data (struct output_block *ob, void pph_stream_write_tree (struct output_block *ob, tree expr, bool ref_p) { + pph_stream *stream = (pph_stream *) ob->sdata; + if (DECL_P (expr)) { - if (DECL_LANG_SPECIFIC (expr)) - pph_stream_write_lang_specific_data (ob, expr, ref_p); - - if (TREE_CODE (expr) == FUNCTION_DECL) - lto_output_tree_or_ref (ob, DECL_SAVED_TREE (expr), ref_p); + if (TREE_CODE (expr) == FUNCTION_DECL + || TREE_CODE (expr) == NAMESPACE_DECL + || TREE_CODE (expr) == PARM_DECL + || LANG_DECL_HAS_MIN (expr)) + { + pph_stream_write_lang_specific_data (stream, expr, ref_p); + + if (TREE_CODE (expr) == FUNCTION_DECL) + pph_output_tree (stream, DECL_SAVED_TREE (expr), ref_p); + } } else if (TREE_CODE (expr) == STATEMENT_LIST) { @@ -598,10 +604,10 @@ pph_stream_write_tree (struct output_block *ob, tree expr, bool ref_p) for (num_stmts = 0, i = tsi_start (expr); !tsi_end_p (i); tsi_next (&i)) num_stmts++; - lto_output_sleb128_stream (ob->main_stream, num_stmts); + pph_output_uint (stream, num_stmts); /* Write the statements. */ for (i = tsi_start (expr); !tsi_end_p (i); tsi_next (&i)) - lto_output_tree_or_ref (ob, tsi_stmt (i), ref_p); + pph_output_tree (stream, tsi_stmt (i), ref_p); } } diff --git a/gcc/cp/pph-streamer.c b/gcc/cp/pph-streamer.c index 989bbbe..e65a792 100644 --- a/gcc/cp/pph-streamer.c +++ b/gcc/cp/pph-streamer.c @@ -68,6 +68,8 @@ pph_stream_hooks_init (void) h->pack_value_fields = pph_stream_pack_value_fields; h->indexable_with_decls_p = pph_indexable_with_decls_p; h->unpack_value_fields = pph_stream_unpack_value_fields; + h->alloc_tree = pph_stream_alloc_tree; + h->output_tree_header = pph_stream_output_tree_header; } @@ -118,7 +120,9 @@ enum pph_trace_type PPH_TRACE_TREE, PPH_TRACE_UINT, PPH_TRACE_BYTES, - PPH_TRACE_STRING + PPH_TRACE_STRING, + PPH_TRACE_CHAIN, + PPH_TRACE_BITPACK }; @@ -131,7 +135,8 @@ pph_stream_trace (pph_stream *stream, const void *data, unsigned int nbytes, enum pph_trace_type type) { const char *op = (stream->write_p) ? "write" : "read"; - const char *type_s[] = { "tree", "uint", "bytes", "string" }; + const char *type_s[] = { "tree", "uint", "bytes", "string", "chain", + "bitpack" }; fprintf (pph_logfile, "*** %s: op=%s, type=%s, size=%u, value=", stream->name, op, type_s[type], (unsigned) nbytes); @@ -174,6 +179,22 @@ pph_stream_trace (pph_stream *stream, const void *data, unsigned int nbytes, fprintf (pph_logfile, ""); break; + case PPH_TRACE_CHAIN: + { + const_tree t = (const_tree) data; + print_generic_expr (pph_logfile, CONST_CAST (union tree_node *, t), + TDF_SLIM); + fprintf (pph_logfile, " (%d nodes in chain)", list_length (t)); + } + break; + + case PPH_TRACE_BITPACK: + { + const struct bitpack_d *bp = (const struct bitpack_d *) data; + fprintf (pph_logfile, "0x%lx", bp->word); + } + break; + default: gcc_unreachable (); } @@ -187,7 +208,8 @@ pph_stream_trace (pph_stream *stream, const void *data, unsigned int nbytes, void pph_stream_trace_tree (pph_stream *stream, tree t) { - pph_stream_trace (stream, t, tree_code_size (TREE_CODE (t)), PPH_TRACE_TREE); + pph_stream_trace (stream, t, t ? tree_code_size (TREE_CODE (t)) : 0, + PPH_TRACE_TREE); } @@ -227,3 +249,22 @@ pph_stream_trace_string_with_length (pph_stream *stream, const char *s, { pph_stream_trace (stream, s, len, PPH_TRACE_STRING); } + + +/* Show tracing information for a tree chain starting with T on STREAM. */ + +void +pph_stream_trace_chain (pph_stream *stream, tree t) +{ + pph_stream_trace (stream, t, t ? tree_code_size (TREE_CODE (t)) : 0, + PPH_TRACE_CHAIN); +} + + +/* Show tracing information for a bitpack BP on STREAM. */ + +void +pph_stream_trace_bitpack (pph_stream *stream, struct bitpack_d *bp) +{ + pph_stream_trace (stream, bp, sizeof (*bp), PPH_TRACE_BITPACK); +} diff --git a/gcc/cp/pph-streamer.h b/gcc/cp/pph-streamer.h index 2c6f405..0f4869d 100644 --- a/gcc/cp/pph-streamer.h +++ b/gcc/cp/pph-streamer.h @@ -24,6 +24,10 @@ along with GCC; see the file COPYING3. If not see #include "lto-streamer.h" #include "tree.h" +/* Record markers. */ +static const unsigned char PPH_RECORD_START = 0xff; +static const unsigned char PPH_RECORD_END = 0xfe; + /* Number of sections in a PPH file. FIXME, currently only one section is supported. To add more, it will also be necessary to handle section names in pph_get_section_data and pph_free_section_data. */ @@ -91,34 +95,49 @@ void pph_stream_trace_uint (pph_stream *, unsigned int); void pph_stream_trace_bytes (pph_stream *, const void *, size_t); void pph_stream_trace_string (pph_stream *, const char *); void pph_stream_trace_string_with_length (pph_stream *, const char *, unsigned); +void pph_stream_trace_chain (pph_stream *, tree); +void pph_stream_trace_bitpack (pph_stream *, struct bitpack_d *); /* In pph-streamer-out.c. */ void pph_stream_flush_buffers (pph_stream *); void pph_stream_init_write (pph_stream *); void pph_stream_write_tree (struct output_block *, tree, bool ref_p); void pph_stream_pack_value_fields (struct bitpack_d *, tree); +void pph_stream_output_tree_header (struct output_block *, tree); /* In pph-streamer-in.c. */ void pph_stream_init_read (pph_stream *); void pph_stream_read_tree (struct lto_input_block *, struct data_in *, tree); void pph_stream_unpack_value_fields (struct bitpack_d *, tree); - -/* In pph.c. FIXME move these to pph-streamer.c. */ +tree pph_stream_alloc_tree (enum tree_code, struct lto_input_block *, + struct data_in *); +/* In pph.c. FIXME pph move these to pph-streamer.c. */ struct cp_token_cache; void pth_save_token_cache (struct cp_token_cache *, pph_stream *); +struct cp_token_cache *pth_load_token_cache (pph_stream *); /* Inline functions. */ -/* Output AST T to STREAM. */ +/* Output AST T to STREAM. If REF_P is true, output all the leaves of T + as references. */ +static inline void +pph_output_tree (pph_stream *stream, tree t, bool ref_p) +{ + if (flag_pph_tracer) + pph_stream_trace_tree (stream, t); + lto_output_tree (stream->ob, t, ref_p); +} + +/* Output AST T to STREAM. If REF_P is true, output a reference to T. */ static inline void -pph_output_tree (pph_stream *stream, tree t) +pph_output_tree_or_ref (pph_stream *stream, tree t, bool ref_p) { if (flag_pph_tracer) pph_stream_trace_tree (stream, t); - lto_output_tree (stream->ob, t, true); + lto_output_tree_or_ref (stream->ob, t, ref_p); } -/* Write a uint VALUE to STREAM. */ +/* Write an unsigned int VALUE to STREAM. */ static inline void pph_output_uint (pph_stream *stream, unsigned int value) { @@ -127,6 +146,15 @@ pph_output_uint (pph_stream *stream, unsigned int value) lto_output_sleb128_stream (stream->ob->main_stream, value); } +/* Write an unsigned char VALUE to STREAM. */ +static inline void +pph_output_uchar (pph_stream *stream, unsigned char value) +{ + if (flag_pph_tracer) + pph_stream_trace_uint (stream, value); + lto_output_1_stream (stream->ob->main_stream, value); +} + /* Write N bytes from P to STREAM. */ static inline void pph_output_bytes (pph_stream *stream, const void *p, size_t n) @@ -151,17 +179,38 @@ pph_output_string_with_length (pph_stream *stream, const char *str, unsigned int len) { if (str) - lto_output_string_with_length (stream->ob, stream->ob->main_stream, - str, len + 1); + { + lto_output_string_with_length (stream->ob, stream->ob->main_stream, + str, len + 1); + if (flag_pph_tracer) + pph_stream_trace_string_with_length (stream, str, len); + } else { /* lto_output_string_with_length does not handle NULL strings, but lto_output_string does. */ pph_output_string (stream, NULL); } +} +/* Write a chain of ASTs to STREAM starting with FIRST. REF_P is true + if the nodes should be emitted as references. */ +static inline void +pph_output_chain (pph_stream *stream, tree first, bool ref_p) +{ + lto_output_chain (stream->ob, first, ref_p); if (flag_pph_tracer) - pph_stream_trace_string_with_length (stream, str, len); + pph_stream_trace_chain (stream, first); +} + +/* Write a bitpack BP to STREAM. */ +static inline void +pph_output_bitpack (pph_stream *stream, struct bitpack_d *bp) +{ + gcc_assert (stream->ob->main_stream == bp->stream); + if (flag_pph_tracer) + pph_stream_trace_bitpack (stream, bp); + lto_output_bitpack (bp); } /* Read an unsigned HOST_WIDE_INT integer from STREAM. */ @@ -175,6 +224,16 @@ pph_input_uint (pph_stream *stream) return (unsigned) n; } +/* Read an unsigned char VALUE to STREAM. */ +static inline unsigned char +pph_input_uchar (pph_stream *stream) +{ + unsigned char n = lto_input_1_unsigned (stream->ib); + if (flag_pph_tracer) + pph_stream_trace_uint (stream, n); + return n; +} + /* Read N bytes from STREAM into P. The caller is responsible for allocating a sufficiently large buffer. */ static inline void @@ -199,7 +258,6 @@ pph_input_string (pph_stream *stream) } /* Load an AST from STREAM. Return the corresponding tree. */ - static inline tree pph_input_tree (pph_stream *stream) { @@ -209,22 +267,24 @@ pph_input_tree (pph_stream *stream) return t; } -/* Return the PPH stream object associated with output block OB. */ - -static inline pph_stream * -pph_get_pph_stream (struct output_block *ob) +/* Read a chain of ASTs from STREAM. */ +static inline tree +pph_input_chain (pph_stream *stream) { - /* FIXME pph - Do not overload OB fields this way. */ - return ((pph_stream *) ob->cfg_stream); + tree t = lto_input_chain (stream->ib, stream->data_in); + if (flag_pph_tracer) + pph_stream_trace_chain (stream, t); + return t; } -/* Set the PPH stream object F associated with output block OB. */ - -static inline void -pph_set_pph_stream (struct output_block *ob, pph_stream *f) +/* Read a bitpack from STREAM. */ +static inline struct bitpack_d +pph_input_bitpack (pph_stream *stream) { - /* FIXME pph - Do not overload OB fields this way. */ - ob->cfg_stream = (struct lto_output_stream *) f; + struct bitpack_d bp = lto_input_bitpack (stream->ib); + if (flag_pph_tracer) + pph_stream_trace_bitpack (stream, &bp); + return bp; } #endif /* GCC_CP_PPH_STREAMER_H */ diff --git a/gcc/cp/pph.c b/gcc/cp/pph.c index c397751..82d1e1d 100644 --- a/gcc/cp/pph.c +++ b/gcc/cp/pph.c @@ -427,6 +427,7 @@ pth_save_token (cp_token *token, pph_stream *f) pth_save_token_value (f, token); } + /* Save all the tokens in CACHE to PPH stream F. */ void @@ -990,6 +991,50 @@ pth_load_token_value (cp_token *token, pph_stream *f) } +/* Read and return a token from STREAM. */ + +static cp_token * +pth_load_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_input_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 pth_load_token_value works with no tokens. */ + pth_load_token_value (token, stream); + + return token; +} + + +/* Read and return a cp_token_cache instance from STREAM. */ + +cp_token_cache * +pth_load_token_cache (pph_stream *stream) +{ + unsigned i, num; + cp_token *first, *last; + + num = pph_input_uint (stream); + for (last = first = NULL, i = 0; i < num; i++) + { + last = pth_load_token (stream); + if (first == NULL) + first = last; + } + + return cp_token_cache_new (first, last); +} + + /* Load the IDENTIFERS for a hunk from a STREAM. */ static void @@ -1078,20 +1123,8 @@ pth_load_hunk (pth_image *image, pph_stream *stream) hunk->buffer = VEC_alloc (cp_token, gc, num_tokens); for (j = 0; j < num_tokens; j++) { - cp_token *token = VEC_quick_push (cp_token, hunk->buffer, NULL); - - /* 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_input_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 pth_load_token_value works with no tokens. */ - pth_load_token_value (token, stream); + cp_token *token = pth_load_token (stream); + VEC_quick_push (cp_token, hunk->buffer, token); } gcc_assert (num_tokens == VEC_length (cp_token, hunk->buffer)); @@ -1807,7 +1840,7 @@ static void pph_write_file_contents (pph_stream *stream, cpp_idents_used *idents_used) { pth_save_identifiers (idents_used, stream); - pph_output_tree (stream, global_namespace); + pph_output_tree (stream, global_namespace, false); } @@ -1898,7 +1931,7 @@ pph_read_file_contents (pph_stream *stream) cpp_lt_replay (parse_in, &idents_used); */ - /* FIXME pph: Also read decls. */ + pph_input_tree (stream); } diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c index f982329..1b0bc16 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -1852,9 +1852,15 @@ lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in, } else { - /* All other nodes can be materialized with a raw make_node - call. */ - result = make_node (code); + /* For all other nodes, see if the streamer knows how to allocate + it. */ + if (streamer_hooks ()->alloc_tree) + result = streamer_hooks ()->alloc_tree (code, ib, data_in); + + /* If the hook did not handle it, materialize the tree with a raw + make_node call. */ + if (result == NULL_TREE) + result = make_node (code); } #ifdef LTO_STREAMER_DEBUG @@ -2360,38 +2366,15 @@ lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in, if (CODE_CONTAINS_STRUCT (code, TS_EXP)) lto_input_ts_exp_tree_pointers (ib, data_in, expr); - if (CODE_CONTAINS_STRUCT (code, TS_SSA_NAME)) - { - /* We only stream the version number of SSA names. */ - gcc_unreachable (); - } - if (CODE_CONTAINS_STRUCT (code, TS_BLOCK)) lto_input_ts_block_tree_pointers (ib, data_in, expr); if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) lto_input_ts_binfo_tree_pointers (ib, data_in, expr); - if (CODE_CONTAINS_STRUCT (code, TS_STATEMENT_LIST)) - { - /* This should only appear in GENERIC. */ - gcc_unreachable (); - } - if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR)) lto_input_ts_constructor_tree_pointers (ib, data_in, expr); - if (CODE_CONTAINS_STRUCT (code, TS_OMP_CLAUSE)) - { - /* This should only appear in High GIMPLE. */ - gcc_unreachable (); - } - - if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION)) - { - sorry ("optimization options not supported yet"); - } - if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION)) lto_input_ts_target_option (ib, expr); @@ -2622,10 +2605,13 @@ lto_read_tree (struct lto_input_block *ib, struct data_in *data_in, if (TREE_CODE (result) == FUNCTION_DECL) gcc_assert (!lto_stream_as_builtin_p (result)); - if (TREE_CODE (result) == VAR_DECL) - lto_register_var_decl_in_symtab (data_in, result); - else if (TREE_CODE (result) == FUNCTION_DECL && !DECL_BUILT_IN (result)) - lto_register_function_decl_in_symtab (data_in, result); + if (streamer_hooks ()->register_decls_in_symtab_p) + { + if (TREE_CODE (result) == VAR_DECL) + lto_register_var_decl_in_symtab (data_in, result); + else if (TREE_CODE (result) == FUNCTION_DECL && !DECL_BUILT_IN (result)) + lto_register_function_decl_in_symtab (data_in, result); + } /* end_marker = */ lto_input_1_unsigned (ib); @@ -2739,6 +2725,8 @@ void lto_reader_init (void) { lto_streamer_init (); + file_name_hash_table = htab_create (37, hash_string_slot_node, + eq_string_slot_node, free); if (streamer_hooks ()->reader_init) streamer_hooks ()->reader_init (); } @@ -2751,8 +2739,6 @@ gimple_streamer_reader_init (void) { memset (<o_stats, 0, sizeof (lto_stats)); bitmap_obstack_initialize (NULL); - file_name_hash_table = htab_create (37, hash_string_slot_node, - eq_string_slot_node, free); gimple_register_cfg_hooks (); } diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index 24543b2..974f3a9 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -1206,7 +1206,6 @@ lto_output_tree_header (struct output_block *ob, tree expr, int ix) enum tree_code code; lto_streamer_hooks *h = streamer_hooks (); - /* We should not see any non-GIMPLE tree nodes here. */ code = TREE_CODE (expr); if (h->is_streamable && !h->is_streamable (expr)) @@ -1218,6 +1217,7 @@ lto_output_tree_header (struct output_block *ob, tree expr, int ix) EXPR on the reading side (such as the number of slots in variable sized nodes). */ tag = lto_tree_code_to_tag (code); + gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS); output_record_start (ob, tag); output_sleb128 (ob, ix); @@ -1241,6 +1241,11 @@ lto_output_tree_header (struct output_block *ob, tree expr, int ix) output_sleb128 (ob, TREE_VEC_LENGTH (expr)); else if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) output_uleb128 (ob, BINFO_N_BASE_BINFOS (expr)); + + /* Allow the streamer to write any streamer-specific information + needed to instantiate the node when reading. */ + if (streamer_hooks ()->output_tree_header) + streamer_hooks ()->output_tree_header (ob, expr); } diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c index be8d36d..1b611e6 100644 --- a/gcc/lto-streamer.c +++ b/gcc/lto-streamer.c @@ -843,6 +843,7 @@ gimple_streamer_hooks_init (void) h->is_streamable = lto_is_streamable; h->write_tree = gimple_streamer_write_tree; h->read_tree = gimple_streamer_read_tree; + h->register_decls_in_symtab_p = true; } diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h index 8e49a55..5f56fc6 100644 --- a/gcc/lto-streamer.h +++ b/gcc/lto-streamer.h @@ -98,6 +98,28 @@ typedef struct lto_streamer_hooks { /* Called by unpack_value_fields to retrieve any non-pointer fields in the tree structure. The arguments are as in unpack_value_fields. */ void (*unpack_value_fields) (struct bitpack_d *, tree); + + /* Non-zero if the streamer should register decls in the LTO + global symbol tables. */ + unsigned register_decls_in_symtab_p : 1; + + /* Called by lto_materialize_tree for tree nodes that it does not + know how to allocate memory for. If defined, this hook should + return a new tree node of the given code. The data_in and + input_block arguments are passed in case the hook needs to + read more data from the stream to allocate the node. + If this hook returns NULL, then lto_materialize_tree will attempt + to allocate the tree by calling make_node directly. */ + tree (*alloc_tree) (enum tree_code, struct lto_input_block *, + struct data_in *); + + /* Called by lto_output_tree_header to write any streamer-specific + information needed to allocate the tree. This hook may assume + that the basic header data (tree code, etc) has already been + written. It should only write any extra data needed to allocate + the node (e.g., in the case of CALL_EXPR, this hook would write + the number of arguments to the CALL_EXPR). */ + void (*output_tree_header) (struct output_block *, tree); } lto_streamer_hooks; @@ -298,9 +320,10 @@ enum LTO_tags LTO_imported_decl_ref, LTO_translation_unit_decl_ref, LTO_global_decl_ref, /* Do not change. */ + LTO_LAST_TAG, /* This tag must always be last. */ - LTO_NUM_TAGS + LTO_NUM_TAGS = LTO_LAST_TAG + MAX_TREE_CODES + LAST_AND_UNUSED_GIMPLE_CODE }; @@ -673,6 +696,9 @@ struct GTY(()) lto_file_decl_data VEC(ld_plugin_symbol_resolution_t,heap) * GTY((skip)) resolutions; struct gcov_ctr_summary GTY((skip)) profile_info; + + /* Any other streamer-specific data needed by the streamer. */ + void * GTY((skip)) sdata; }; typedef struct lto_file_decl_data *lto_file_decl_data_ptr; @@ -768,6 +794,9 @@ struct output_block /* Cache of nodes written in this section. */ struct lto_streamer_cache_d *writer_cache; + + /* Any other streamer-specific data needed by the streamer. */ + void *sdata; }; @@ -802,6 +831,9 @@ struct data_in /* Cache of pickled nodes. */ struct lto_streamer_cache_d *reader_cache; + + /* Any other streamer-specific data needed by the streamer. */ + void *sdata; }; @@ -1029,7 +1061,7 @@ extern VEC(lto_out_decl_state_ptr, heap) *lto_function_decl_states; static inline bool lto_tag_is_tree_code_p (enum LTO_tags tag) { - return tag > LTO_null && (unsigned) tag <= NUM_TREE_CODES; + return tag > LTO_null && (unsigned) tag <= MAX_TREE_CODES; }