Commit f0efc7aa by Diego Novillo Committed by Diego Novillo

rebase

From-SVN: r177571
parent b7926cf9
2011-08-08 Diego Novillo <dnovillo@google.com>
* Makefile.in (LTO_STREAMER_H): Add DIAGNOSTIC_H.
(DATA_STREAMER_H): New.
(GIMPLE_STREAMER_H): New.
(TREE_STREAMER_H): New.
(STREAMER_HOOKS_H): New.
(OBJS): Add data-streamer.o, data-streamer-in.o, data-streamer-out.o,
gimple-streamer-in.o, gimple-streamer-out.o, streamer-hooks.o,
tree-streamer.o, tree-streamer-in.o and tree-streamer-out.o.
(data-streamer.o): New.
(data-streamer-in.o): New.
(data-streamer-out.o): New.
(gimple-streamer-in.o): New.
(gimple-streamer-out.o): New.
(streamer-hooks.o): New.
(tree-streamer.o): New.
(tree-streamer-in.o): New.
(tree-streamer-out.o): New.
(lto-cgraph.o): Add dependency on DATA_STREAMER_H and
TREE_STREAMER_H.
(lto-streamer-in.o): Add dependency on DATA_STREAMER_H,
GIMPLE_STREAMER_H and TREE_STREAMER_H.
(lto-streamer-out.o): Add dependency on DATA_STREAMER_H,
GIMPLE_STREAMER_H and TREE_STREAMER_H.
(lto-streamer.o): Add dependency on STREAMER_HOOKS_H.
(ipa-prop.o): Add dependency on DATA_STREAMER_H and
TREE_STREAMER_H.
(ipa-inline-analysis.o): Likewise.
(ipa-pure-const.o): Likewise.
* data-streamer-in.c: New.
* data-streamer-out.c: New.
* data-streamer.c: New.
* data-streamer.h: New.
* gimple-streamer-in.c: New.
* gimple-streamer-out.c: New.
* gimple-streamer.h: New.
* ipa-inline-analysis.c: Include data-streamer.h.
* ipa-prop.c: Include data-streamer.h.
* ipa-pure-const.c: Include data-streamer.h.
* lto-cgraph.c: Include data-streamer.h.
* lto-section-in.c (lto_input_uleb128): Move to data-streamer-in.c.
(lto_input_widest_uint_uleb128): Likewise.
(lto_input_sleb128): Likewise.
(bp_unpack_var_len_unsigned): Likewise.
(bp_unpack_var_len_int): Likewise.
* lto-section-out.c (lto_output_uleb128_stream): Move to
data-streamer-out.c.
(lto_output_widest_uint_uleb128_stream): Likewise.
(lto_output_sleb128_stream): Likewise.
(bp_pack_var_len_unsigned): Likewise.
(bp_pack_var_len_int): Likewise.
* lto-streamer-in.c: Include data-streamer.h and
gimple-streamer.h.
(struct string_slot): Remove. Update all users.
(lto_tag_check_set): Make extern.
(lto_tag_check_range): Move to lto-streamer.h.
(lto_tag_check): Likewise.
(hash_string_slot_node): Remove. Update all users.
(eq_string_slot_node): Remove. Update all users.
(string_for_index): Move to data-streamer-in.c
(input_string_internal): Likewise.
(input_string_cst): Move to tree-streamer-in.c.
(input_identifier): Likewise.
(lto_input_string): Move to data-streamer-in.c
(input_record_start): Move to data-streamer.h
(canon_file_name): Use new definition of struct string_slot
from data-streamer.h.
Set S_SLOT.LEN.
(lto_input_location): Make extern.
(lto_input_chain): Move to tree-streamer-in.c.
(lto_init_eh): Make extern.
(input_phi): Move to gimple-streamer-in.c.
(input_gimple_stmt): Likewise.
(input_bb): Likewise.
(unpack_ts_base_value_fields): Move to tree-streamer-in.c.
(unpack_ts_real_cst_value_fields): Likewise.
(unpack_ts_fixed_cst_value_fields): Likewise.
(unpack_ts_decl_common_value_fields): Likewise.
(unpack_ts_decl_wrtl_value_fields): Likewise.
(unpack_ts_decl_with_vis_value_fields): Likewise.
(unpack_ts_function_decl_value_fields): Likewise.
(unpack_ts_type_common_value_fields): Likewise.
(unpack_ts_block_value_fields): Likewise.
(unpack_ts_translation_unit_decl_value_fields): Likewise.
(unpack_value_fields): Likewise.
(lto_materialize_tree): Likewise.
(lto_input_ts_common_tree_pointers): Likewise.
(lto_input_ts_vector_tree_pointers): Likewise.
(lto_input_ts_complex_tree_pointers): Likewise.
(lto_input_ts_decl_minimal_tree_pointers): Likewise.
(lto_input_ts_decl_common_tree_pointers): Likewise.
(lto_input_ts_decl_non_common_tree_pointers): Likewise.
(lto_input_ts_decl_with_vis_tree_pointers): Likewise.
(lto_input_ts_field_decl_tree_pointers): Likewise.
(lto_input_ts_function_decl_tree_pointers): Likewise.
(lto_input_ts_type_common_tree_pointers): Likewise.
(lto_input_ts_type_non_common_tree_pointers): Likewise.
(lto_input_ts_list_tree_pointers): Likewise.
(lto_input_ts_vec_tree_pointers): Likewise.
(lto_input_ts_exp_tree_pointers): Likewise.
(lto_input_ts_block_tree_pointers): Likewise.
(lto_input_ts_binfo_tree_pointers): Likewise.
(lto_input_ts_constructor_tree_pointers): Likewise.
(lto_input_ts_target_option): Likewise.
(lto_input_ts_translation_unit_decl_tree_pointers): Likewise.
(lto_input_tree_pointers): Likewise.
(lto_get_pickled_tree): Likewise.
(lto_get_builtin_tree): Likewise.
(lto_read_tree): Likewise.
(lto_input_integer_cst): Likewise.
(lto_input_tree): Likewise.
* lto-streamer-out.c: Include data-streamer.h,
gimple-streamer.h and streamer-hooks.h.
(struct string_slot): Move to data-streamer.h.
(hash_string_slot_node): Likewise.
(eq_string_slot_node): Likewise.
(lto_string_index): Move to data-streamer-out.c.
(lto_output_string_with_length): Likewise.
(lto_output_string): Likewise.
(output_string_cst): Move to tree-streamer-out.c.
(output_identifier): Likewise.
(output_zero): Move to data-streamer-out.c
(output_uleb128): Likewise.
(output_sleb128): Likewise.
(output_record_start): Move to data-streamer.h
(pack_ts_base_value_fields): Move to tree-streamer-out.c.
(pack_ts_real_cst_value_fields): Likewise.
(pack_ts_fixed_cst_value_fields): Likewise.
(pack_ts_decl_common_value_fields): Likewise.
(pack_ts_decl_wrtl_value_fields): Likewise.
(pack_ts_decl_with_vis_value_fields): Likewise.
(pack_ts_function_decl_value_fields): Likewise.
(pack_ts_type_common_value_fields): Likewise.
(pack_ts_block_value_fields): Likewise.
(pack_ts_translation_unit_decl_value_fields): Likewise.
(pack_value_fields): Likewise.
(lto_output_chain): Likewise.
(lto_output_ts_common_tree_pointers): Likewise.
(lto_output_ts_vector_tree_pointers): Likewise.
(lto_output_ts_complex_tree_pointers): Likewise.
(lto_output_ts_decl_minimal_tree_pointers): Likewise.
(lto_output_ts_decl_common_tree_pointers): Likewise.
(lto_output_ts_decl_non_common_tree_pointers): Likewise.
(lto_output_ts_decl_with_vis_tree_pointers): Likewise.
(lto_output_ts_field_decl_tree_pointers): Likewise.
(lto_output_ts_function_decl_tree_pointers): Likewise.
(lto_output_ts_type_common_tree_pointers): Likewise.
(lto_output_ts_type_non_common_tree_pointers): Likewise.
(lto_output_ts_list_tree_pointers): Likewise.
(lto_output_ts_vec_tree_pointers): Likewise.
(lto_output_ts_exp_tree_pointers): Likewise.
(lto_output_ts_block_tree_pointers): Likewise.
(lto_output_ts_binfo_tree_pointers): Likewise.
(lto_output_ts_constructor_tree_pointers): Likewise.
(lto_output_ts_target_option): Likewise.
(lto_output_ts_translation_unit_decl_tree_pointers): Likewise.
(lto_output_tree_pointers): Likewise.
(lto_output_tree_header): Likewise.
(lto_output_builtin_tree): Likewise.
(lto_write_tree): Likewise.
(lto_output_integer_cst): Likewise.
(lto_output_tree): Likewise.
(output_phi): Move to gimple-streamer-out.c.
(output_gimple_stmt): Likewise.
(output_bb): Likewise.
* lto-streamer.c: Include tree-streamer.h and streamer-hooks.h.
(streamer_hooks): Move to streamer-hooks.c.
(check_handled_ts_structures): Move to tree-streamer.c
(lto_streamer_cache_add_to_node_array): Likewise.
(lto_streamer_cache_insert_1): Likewise.
(lto_streamer_cache_insert): Likewise.
(lto_streamer_cache_insert_at): Likewise.
(lto_streamer_cache_append): Likewise.
(lto_streamer_cache_lookup): Likewise.
(lto_streamer_cache_get): Likewise.
(lto_record_common_node): Likewise.
(lto_preload_common_nodes): Likewise.
(lto_streamer_cache_create): Likewise.
(lto_streamer_cache_delete): Likewise.
(streamer_hooks_init): Move to streamer-hooks.c.
* lto-streamer.h: Include diagnostic.h
(struct output_block, struct lto_input_block,
struct data_in, struct bitpack_d): Remove forward
declarations.
(struct bitpack_d): Move to data-streamer.h.
(struct lto_streamer_cache_d): Move to tree-streamer.h.
(struct streamer_hooks): Move to streamer-hooks.h.
(bp_pack_var_len_unsigned): Move to data-streamer.h.
(bp_pack_var_len_int): Likewise.
(bp_unpack_var_len_unsigned): Likewise.
(bp_unpack_var_len_int): Likewise.
(lto_input_location): Declare.
(lto_tag_check_set): Declare.
(lto_init_eh): Declare.
(lto_output_tree_ref): Declare.
(lto_output_location): Declare.
(bitpack_create): Move to data-streamer.h.
(bp_pack_value): Likewise.
(lto_output_bitpack): Likewise.
(lto_input_bitpack): Likewise.
(bp_unpack_value): Likewise.
(lto_output_1_stream): Likewise.
(lto_input_1_unsigned): Likewise.
(lto_output_int_in_range): Likewise.
(lto_input_int_in_range): Likewise.
(bp_pack_int_in_range): Likewise.
(bp_unpack_int_in_range): Likewise.
(lto_output_enum): Likewise.
(lto_input_enum): Likewise.
(bp_pack_enum): Likewise.
(bp_unpack_enum): Likewise.
* streamer-hooks.c: New.
* streamer-hooks.h: New.
* tree-streamer-in.c: New.
* tree-streamer-out.c: New.
* tree-streamer.c: New.
* tree-streamer.h: New.
2011-08-08 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* gthr-posix95.h: Remove.
......
......@@ -995,7 +995,12 @@ DBGCNT_H = dbgcnt.h dbgcnt.def
EBITMAP_H = ebitmap.h sbitmap.h
LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \
$(CGRAPH_H) $(VEC_H) vecprim.h $(TREE_H) $(GIMPLE_H) \
$(GCOV_IO_H)
$(GCOV_IO_H) $(DIAGNOSTIC_H)
DATA_STREAMER_H = data-streamer.h $(VEC_H) $(LTO_STREAMER_H)
GIMPLE_STREAMER_H = gimple-streamer.h $(LTO_STREAMER_H) $(BASIC_BLOCK_H) \
$(FUNCTION_H)
TREE_STREAMER_H = tree-streamer.h $(TREE_H) $(LTO_STREAMER_H)
STREAMER_HOOKS_H = streamer-hooks.h $(TREE_H)
TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H)
IPA_PROP_H = ipa-prop.h $(TREE_H) $(VEC_H) $(CGRAPH_H) $(GIMPLE_H) alloc-pool.h
GSTAB_H = gstab.h stab.def
......@@ -1239,6 +1244,9 @@ OBJS = \
cprop.o \
cse.o \
cselib.o \
data-streamer.o \
data-streamer-in.o \
data-streamer-out.o \
dbxout.o \
dbgcnt.o \
dce.o \
......@@ -1275,6 +1283,8 @@ OBJS = \
gimple-fold.o \
gimple-low.o \
gimple-pretty-print.o \
gimple-streamer-in.o \
gimple-streamer-out.o \
gimplify.o \
godump.o \
graph.o \
......@@ -1330,13 +1340,13 @@ OBJS = \
loop-unswitch.o \
lower-subreg.o \
lto-cgraph.o \
lto-streamer.o \
lto-streamer-in.o \
lto-streamer-out.o \
lto-section-in.o \
lto-section-out.o \
lto-symtab.o \
lto-opts.o \
lto-streamer.o \
lto-compress.o \
matrix-reorg.o \
mcf.o \
......@@ -1391,6 +1401,7 @@ OBJS = \
stmt.o \
stor-layout.o \
store-motion.o \
streamer-hooks.o \
stringpool.o \
target-globals.o \
targhooks.o \
......@@ -1467,6 +1478,9 @@ OBJS = \
tree-ssa.o \
tree-ssanames.o \
tree-stdarg.o \
tree-streamer.o \
tree-streamer-in.o \
tree-streamer-out.o \
tree-tailcall.o \
tree-vect-generic.o \
tree-vect-patterns.o \
......@@ -2281,22 +2295,47 @@ lto-compress.o: lto-compress.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TREE_H) langhooks.h $(LTO_STREAMER_H) $(LTO_SECTION_H) \
lto-compress.h $(DIAGNOSTIC_CORE_H) $(DIAGNOSTIC_CORE_H)
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(ZLIBINC) $< $(OUTPUT_OPTION)
data-streamer-in.o: data-streamer-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(DATA_STREAMER_H) $(DIAGNOSTIC_H)
data-streamer-out.o: data-streamer-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(DATA_STREAMER_H)
data-streamer.o: data-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(DATA_STREAMER_H)
gimple-streamer-in.o: gimple-streamer-in.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(GIMPLE_STREAMER_H) $(TREE_FLOW_H) $(DATA_STREAMER_H) \
$(TREE_STREAMER_H) $(DIAGNOSTIC_H)
gimple-streamer-out.o: gimple-streamer-out.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(GIMPLE_STREAMER_H) $(DATA_STREAMER_H) $(TREE_FLOW_H) \
$(LTO_STREAMER_H)
tree-streamer.o: tree-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TREE_STREAMER_H) $(STREAMER_HOOKS_H)
tree-streamer-in.o: tree-streamer-in.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(DIAGNOSTIC_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_STREAMER_H) \
$(DATA_STREAMER_H) $(STREAMER_HOOKS_H) $(LTO_STREAMER_H)
tree-streamer-out.o: tree-streamer-out.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(DIAGNOSTIC_H) $(TREE_STREAMER_H) $(DATA_STREAMER_H) \
$(STREAMER_HOOKS_H)
streamer-hooks.o: streamer-hooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(STREAMER_HOOKS_H)
lto-cgraph.o: lto-cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
$(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) \
$(TREE_FLOW_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_CORE_H) \
$(EXCEPT_H) $(TIMEVAR_H) output.h pointer-set.h $(LTO_STREAMER_H) $(GCOV_IO_H)
$(EXCEPT_H) $(TIMEVAR_H) output.h pointer-set.h $(LTO_STREAMER_H) \
$(GCOV_IO_H) $(DATA_STREAMER_H) $(TREE_STREAMER_H)
lto-streamer-in.o: lto-streamer-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) toplev.h $(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
$(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) \
$(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) $(LIBFUNCS_H) $(EXCEPT_H) debug.h \
$(TIMEVAR_H) output.h $(IPA_UTILS_H) $(LTO_STREAMER_H) toplev.h
$(TIMEVAR_H) output.h $(IPA_UTILS_H) $(LTO_STREAMER_H) toplev.h \
$(DATA_STREAMER_H) $(GIMPLE_STREAMER_H) $(TREE_STREAMER_H)
lto-streamer-out.o : lto-streamer-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(DIAGNOSTIC_CORE_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
$(HASHTAB_H) $(BASIC_BLOCK_H) tree-iterator.h \
$(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) \
$(DIAGNOSTIC_CORE_H) $(EXCEPT_H) $(LTO_STREAMER_H) $(DIAGNOSTIC_CORE_H)
$(DIAGNOSTIC_CORE_H) $(EXCEPT_H) $(LTO_STREAMER_H) $(DIAGNOSTIC_CORE_H) \
$(DATA_STREAMER_H) $(STREAMER_HOOKS_H) $(GIMPLE_STREAMER_H) \
$(TREE_STREAMER_H)
lto-section-in.o: lto-section-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
$(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(CGRAPH_H) $(FUNCTION_H) \
......@@ -2315,7 +2354,8 @@ lto-opts.o: lto-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
$(COMMON_TARGET_H) $(DIAGNOSTIC_H) $(LTO_STREAMER_H)
lto-streamer.o: lto-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TREE_H) $(GIMPLE_H) $(BITMAP_H) $(LTO_STREAMER_H) $(FLAGS_H) \
$(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(LTO_SYMTAB_H) toplev.h $(DIAGNOSTIC_CORE_H)
$(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(LTO_SYMTAB_H) toplev.h \
$(DIAGNOSTIC_CORE_H) $(STREAMER_HOOKS_H)
langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) toplev.h $(DIAGNOSTIC_CORE_H) $(TREE_INLINE_H) $(RTL_H) insn-config.h $(INTEGRATE_H) \
langhooks.h $(TARGET_H) $(LANGHOOKS_DEF_H) $(FLAGS_H) $(GGC_H) $(DIAGNOSTIC_H) \
......@@ -2995,7 +3035,8 @@ ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(DIAGNOSTIC_H) \
$(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) \
$(TREE_INLINE_H) $(GIMPLE_H) $(TIMEVAR_H) \
tree-pretty-print.h gimple-pretty-print.h $(LTO_STREAMER_H)
tree-pretty-print.h gimple-pretty-print.h $(LTO_STREAMER_H) \
$(DATA_STREAMER_H) $(TREE_STREAMER_H)
ipa-ref.o : ipa-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(TREE_H) $(TARGET_H) \
$(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) $(GGC_H)
......@@ -3023,7 +3064,8 @@ ipa-inline-analysis.o : ipa-inline-analysis.c $(CONFIG_H) $(SYSTEM_H) coretypes.
$(TREE_H) langhooks.h $(TREE_INLINE_H) $(FLAGS_H) $(CGRAPH_H) intl.h \
$(DIAGNOSTIC_H) $(PARAMS_H) $(TIMEVAR_H) $(TREE_PASS_H) \
$(HASHTAB_H) $(COVERAGE_H) $(GGC_H) $(TREE_FLOW_H) $(IPA_PROP_H) \
gimple-pretty-print.h ipa-inline.h $(LTO_STREAMER_H)
gimple-pretty-print.h ipa-inline.h $(LTO_STREAMER_H) $(DATA_STREAMER_H) \
$(TREE_STREAMER_H)
ipa-inline-transform.o : ipa-inline-transform.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) langhooks.h $(TREE_INLINE_H) $(FLAGS_H) $(CGRAPH_H) intl.h \
$(DIAGNOSTIC_H) $(PARAMS_H) $(TIMEVAR_H) $(TREE_PASS_H) \
......@@ -3043,7 +3085,7 @@ ipa-pure-const.o : ipa-pure-const.c $(CONFIG_H) $(SYSTEM_H) \
pointer-set.h $(GGC_H) $(IPA_UTILS_H) $(TARGET_H) \
$(GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) $(TREE_PASS_H) $(TIMEVAR_H) \
$(DIAGNOSTIC_H) $(CFGLOOP_H) $(SCEV_H) $(LTO_STREAMER_H) \
gimple-pretty-print.h
gimple-pretty-print.h $(DATA_STREAMER_H) $(TREE_STREAMER_H)
coverage.o : coverage.c $(GCOV_IO_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) \
$(FUNCTION_H) $(BASIC_BLOCK_H) toplev.h $(DIAGNOSTIC_CORE_H) $(GGC_H) langhooks.h $(COVERAGE_H) \
......
/* Routines for restoring various data types from a file stream. This deals
with various data types like strings, integers, enums, etc.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
#include "data-streamer.h"
/* Read a string from the string table in DATA_IN using input block
IB. Write the length to RLEN. */
const char *
string_for_index (struct data_in *data_in, unsigned int loc, unsigned int *rlen)
{
struct lto_input_block str_tab;
unsigned int len;
const char *result;
if (!loc)
{
*rlen = 0;
return NULL;
}
/* Get the string stored at location LOC in DATA_IN->STRINGS. */
LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings, loc - 1,
data_in->strings_len);
len = lto_input_uleb128 (&str_tab);
*rlen = len;
if (str_tab.p + len > data_in->strings_len)
internal_error ("bytecode stream: string too long for the string table");
result = (const char *)(data_in->strings + str_tab.p);
return result;
}
/* Read a string from the string table in DATA_IN using input block
IB. Write the length to RLEN. */
const char *
input_string_internal (struct data_in *data_in, struct lto_input_block *ib,
unsigned int *rlen)
{
return string_for_index (data_in, lto_input_uleb128 (ib), rlen);
}
/* Read a NULL terminated string from the string table in DATA_IN. */
const char *
lto_input_string (struct data_in *data_in, struct lto_input_block *ib)
{
unsigned int len;
const char *ptr;
ptr = input_string_internal (data_in, ib, &len);
if (!ptr)
return NULL;
if (ptr[len - 1] != '\0')
internal_error ("bytecode stream: found non-null terminated string");
return ptr;
}
/* Read an ULEB128 Number of IB. */
unsigned HOST_WIDE_INT
lto_input_uleb128 (struct lto_input_block *ib)
{
unsigned HOST_WIDE_INT result = 0;
int shift = 0;
unsigned HOST_WIDE_INT byte;
while (true)
{
byte = lto_input_1_unsigned (ib);
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
return result;
}
}
/* HOST_WIDEST_INT version of lto_input_uleb128. IB is as in
lto_input_uleb128. */
unsigned HOST_WIDEST_INT
lto_input_widest_uint_uleb128 (struct lto_input_block *ib)
{
unsigned HOST_WIDEST_INT result = 0;
int shift = 0;
unsigned HOST_WIDEST_INT byte;
while (true)
{
byte = lto_input_1_unsigned (ib);
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
return result;
}
}
/* Read an SLEB128 Number of IB. */
HOST_WIDE_INT
lto_input_sleb128 (struct lto_input_block *ib)
{
HOST_WIDE_INT result = 0;
int shift = 0;
unsigned HOST_WIDE_INT byte;
while (true)
{
byte = lto_input_1_unsigned (ib);
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
{
if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
result |= - ((HOST_WIDE_INT)1 << shift);
return result;
}
}
}
/* Routines for saving various data types to a file stream. This deals
with various data types like strings, integers, enums, etc.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "data-streamer.h"
/* Return index used to reference STRING of LEN characters in the string table
in OB. The string might or might not include a trailing '\0'.
Then put the index onto the INDEX_STREAM.
When PERSISTENT is set, the string S is supposed to not change during
duration of the OB and thus OB can keep pointer into it. */
unsigned
lto_string_index (struct output_block *ob, const char *s, unsigned int len,
bool persistent)
{
struct string_slot **slot;
struct string_slot s_slot;
s_slot.s = s;
s_slot.len = len;
s_slot.slot_num = 0;
slot = (struct string_slot **) htab_find_slot (ob->string_hash_table,
&s_slot, INSERT);
if (*slot == NULL)
{
struct lto_output_stream *string_stream = ob->string_stream;
unsigned int start = string_stream->total_size;
struct string_slot *new_slot = XOBNEW (&ob->obstack, struct string_slot);
const char *string;
if (!persistent)
{
char *tmp;
string = tmp = XOBNEWVEC (&ob->obstack, char, len);
memcpy (tmp, s, len);
}
else
string = s;
new_slot->s = string;
new_slot->len = len;
new_slot->slot_num = start;
*slot = new_slot;
lto_output_uleb128_stream (string_stream, len);
lto_output_data_stream (string_stream, string, len);
return start + 1;
}
else
{
struct string_slot *old_slot = *slot;
return old_slot->slot_num + 1;
}
}
/* Output STRING of LEN characters to the string table in OB. The
string might or might not include a trailing '\0'. Then put the
index onto the INDEX_STREAM.
When PERSISTENT is set, the string S is supposed to not change during
duration of the OB and thus OB can keep pointer into it. */
void
lto_output_string_with_length (struct output_block *ob,
struct lto_output_stream *index_stream,
const char *s, unsigned int len, bool persistent)
{
if (s)
lto_output_uleb128_stream (index_stream,
lto_string_index (ob, s, len, persistent));
else
lto_output_1_stream (index_stream, 0);
}
/* Output the '\0' terminated STRING to the string
table in OB. Then put the index onto the INDEX_STREAM.
When PERSISTENT is set, the string S is supposed to not change during
duration of the OB and thus OB can keep pointer into it. */
void
lto_output_string (struct output_block *ob,
struct lto_output_stream *index_stream,
const char *string, bool persistent)
{
if (string)
lto_output_string_with_length (ob, index_stream, string,
strlen (string) + 1,
persistent);
else
lto_output_1_stream (index_stream, 0);
}
/* Write a zero to the output stream. */
void
output_zero (struct output_block *ob)
{
lto_output_1_stream (ob->main_stream, 0);
}
/* Output an unsigned LEB128 quantity to OB->main_stream. */
void
output_uleb128 (struct output_block *ob, unsigned HOST_WIDE_INT work)
{
lto_output_uleb128_stream (ob->main_stream, work);
}
/* Output a signed LEB128 quantity to OB->main_stream. */
void
output_sleb128 (struct output_block *ob, HOST_WIDE_INT work)
{
lto_output_sleb128_stream (ob->main_stream, work);
}
/* Output an unsigned LEB128 quantity to OBS. */
void
lto_output_uleb128_stream (struct lto_output_stream *obs,
unsigned HOST_WIDE_INT work)
{
do
{
unsigned int byte = (work & 0x7f);
work >>= 7;
if (work != 0)
/* More bytes to follow. */
byte |= 0x80;
lto_output_1_stream (obs, byte);
}
while (work != 0);
}
/* Identical to output_uleb128_stream above except using unsigned
HOST_WIDEST_INT type. For efficiency on host where unsigned HOST_WIDEST_INT
is not native, we only use this if we know that HOST_WIDE_INT is not wide
enough. */
void
lto_output_widest_uint_uleb128_stream (struct lto_output_stream *obs,
unsigned HOST_WIDEST_INT work)
{
do
{
unsigned int byte = (work & 0x7f);
work >>= 7;
if (work != 0)
/* More bytes to follow. */
byte |= 0x80;
lto_output_1_stream (obs, byte);
}
while (work != 0);
}
/* Output a signed LEB128 quantity. */
void
lto_output_sleb128_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
{
int more, byte;
do
{
byte = (work & 0x7f);
/* arithmetic shift */
work >>= 7;
more = !((work == 0 && (byte & 0x40) == 0)
|| (work == -1 && (byte & 0x40) != 0));
if (more)
byte |= 0x80;
lto_output_1_stream (obs, byte);
}
while (more);
}
/* Generic streaming support for basic data types.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "data-streamer.h"
/* Pack WORK into BP in a variant of uleb format. */
void
bp_pack_var_len_unsigned (struct bitpack_d *bp, unsigned HOST_WIDE_INT work)
{
do
{
unsigned int half_byte = (work & 0x7);
work >>= 3;
if (work != 0)
/* More half_bytes to follow. */
half_byte |= 0x8;
bp_pack_value (bp, half_byte, 4);
}
while (work != 0);
}
/* Pack WORK into BP in a variant of sleb format. */
void
bp_pack_var_len_int (struct bitpack_d *bp, HOST_WIDE_INT work)
{
int more, half_byte;
do
{
half_byte = (work & 0x7);
/* arithmetic shift */
work >>= 3;
more = !((work == 0 && (half_byte & 0x4) == 0)
|| (work == -1 && (half_byte & 0x4) != 0));
if (more)
half_byte |= 0x8;
bp_pack_value (bp, half_byte, 4);
}
while (more);
}
/* Unpack VAL from BP in a variant of uleb format. */
unsigned HOST_WIDE_INT
bp_unpack_var_len_unsigned (struct bitpack_d *bp)
{
unsigned HOST_WIDE_INT result = 0;
int shift = 0;
unsigned HOST_WIDE_INT half_byte;
while (true)
{
half_byte = bp_unpack_value (bp, 4);
result |= (half_byte & 0x7) << shift;
shift += 3;
if ((half_byte & 0x8) == 0)
return result;
}
}
/* Unpack VAL from BP in a variant of sleb format. */
HOST_WIDE_INT
bp_unpack_var_len_int (struct bitpack_d *bp)
{
HOST_WIDE_INT result = 0;
int shift = 0;
unsigned HOST_WIDE_INT half_byte;
while (true)
{
half_byte = bp_unpack_value (bp, 4);
result |= (half_byte & 0x7) << shift;
shift += 3;
if ((half_byte & 0x8) == 0)
{
if ((shift < HOST_BITS_PER_WIDE_INT) && (half_byte & 0x4))
result |= - ((HOST_WIDE_INT)1 << shift);
return result;
}
}
}
/* Generic streaming support for various data types.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#ifndef GCC_DATA_STREAMER_H
#define GCC_DATA_STREAMER_H
#include "vec.h"
#include "lto-streamer.h"
/* Data structures used to pack values and bitflags into a vector of
words. Used to stream values of a fixed number of bits in a space
efficient way. */
static unsigned const BITS_PER_BITPACK_WORD = HOST_BITS_PER_WIDE_INT;
typedef unsigned HOST_WIDE_INT bitpack_word_t;
DEF_VEC_I(bitpack_word_t);
DEF_VEC_ALLOC_I(bitpack_word_t, heap);
struct bitpack_d
{
/* The position of the first unused or unconsumed bit in the word. */
unsigned pos;
/* The current word we are (un)packing. */
bitpack_word_t word;
/* The lto_output_stream or the lto_input_block we are streaming to/from. */
void *stream;
};
/* String hashing. */
struct string_slot
{
const char *s;
int len;
unsigned int slot_num;
};
/* Returns a hash code for P. Adapted from libiberty's htab_hash_string
to support strings that may not end in '\0'. */
static inline hashval_t
hash_string_slot_node (const void *p)
{
const struct string_slot *ds = (const struct string_slot *) p;
hashval_t r = ds->len;
int i;
for (i = 0; i < ds->len; i++)
r = r * 67 + (unsigned)ds->s[i] - 113;
return r;
}
/* Returns nonzero if P1 and P2 are equal. */
static inline int
eq_string_slot_node (const void *p1, const void *p2)
{
const struct string_slot *ds1 = (const struct string_slot *) p1;
const struct string_slot *ds2 = (const struct string_slot *) p2;
if (ds1->len == ds2->len)
return memcmp (ds1->s, ds2->s, ds1->len) == 0;
return 0;
}
/* Returns a new bit-packing context for bit-packing into S. */
static inline struct bitpack_d
bitpack_create (struct lto_output_stream *s)
{
struct bitpack_d bp;
bp.pos = 0;
bp.word = 0;
bp.stream = (void *)s;
return bp;
}
/* Pack the NBITS bit sized value VAL into the bit-packing context BP. */
static inline void
bp_pack_value (struct bitpack_d *bp, bitpack_word_t val, unsigned nbits)
{
bitpack_word_t word = bp->word;
int pos = bp->pos;
/* Verify that VAL fits in the NBITS. */
gcc_checking_assert (nbits == BITS_PER_BITPACK_WORD
|| !(val & ~(((bitpack_word_t)1<<nbits)-1)));
/* If val does not fit into the current bitpack word switch to the
next one. */
if (pos + nbits > BITS_PER_BITPACK_WORD)
{
lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream, word);
word = val;
pos = nbits;
}
else
{
word |= val << pos;
pos += nbits;
}
bp->word = word;
bp->pos = pos;
}
/* Finishes bit-packing of BP. */
static inline void
lto_output_bitpack (struct bitpack_d *bp)
{
lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream,
bp->word);
bp->word = 0;
bp->pos = 0;
}
/* Returns a new bit-packing context for bit-unpacking from IB. */
static inline struct bitpack_d
lto_input_bitpack (struct lto_input_block *ib)
{
struct bitpack_d bp;
bp.word = lto_input_uleb128 (ib);
bp.pos = 0;
bp.stream = (void *)ib;
return bp;
}
/* Unpacks NBITS bits from the bit-packing context BP and returns them. */
static inline bitpack_word_t
bp_unpack_value (struct bitpack_d *bp, unsigned nbits)
{
bitpack_word_t mask, val;
int pos = bp->pos;
mask = (nbits == BITS_PER_BITPACK_WORD
? (bitpack_word_t) -1
: ((bitpack_word_t) 1 << nbits) - 1);
/* If there are not continuous nbits in the current bitpack word
switch to the next one. */
if (pos + nbits > BITS_PER_BITPACK_WORD)
{
bp->word = val = lto_input_uleb128 ((struct lto_input_block *)bp->stream);
bp->pos = nbits;
return val & mask;
}
val = bp->word;
val >>= pos;
bp->pos = pos + nbits;
return val & mask;
}
/* Write a character to the output block. */
static inline void
lto_output_1_stream (struct lto_output_stream *obs, char c)
{
/* No space left. */
if (obs->left_in_block == 0)
lto_append_block (obs);
/* Write the actual character. */
*obs->current_pointer = c;
obs->current_pointer++;
obs->total_size++;
obs->left_in_block--;
}
/* Read byte from the input block. */
static inline unsigned char
lto_input_1_unsigned (struct lto_input_block *ib)
{
if (ib->p >= ib->len)
lto_section_overrun (ib);
return (ib->data[ib->p++]);
}
/* Output VAL into OBS and verify it is in range MIN...MAX that is supposed
to be compile time constant.
Be host independent, limit range to 31bits. */
static inline void
lto_output_int_in_range (struct lto_output_stream *obs,
HOST_WIDE_INT min,
HOST_WIDE_INT max,
HOST_WIDE_INT val)
{
HOST_WIDE_INT range = max - min;
gcc_checking_assert (val >= min && val <= max && range > 0
&& range < 0x7fffffff);
val -= min;
lto_output_1_stream (obs, val & 255);
if (range >= 0xff)
lto_output_1_stream (obs, (val >> 8) & 255);
if (range >= 0xffff)
lto_output_1_stream (obs, (val >> 16) & 255);
if (range >= 0xffffff)
lto_output_1_stream (obs, (val >> 24) & 255);
}
/* Input VAL into OBS and verify it is in range MIN...MAX that is supposed
to be compile time constant. PURPOSE is used for error reporting. */
static inline HOST_WIDE_INT
lto_input_int_in_range (struct lto_input_block *ib,
const char *purpose,
HOST_WIDE_INT min,
HOST_WIDE_INT max)
{
HOST_WIDE_INT range = max - min;
HOST_WIDE_INT val = lto_input_1_unsigned (ib);
gcc_checking_assert (range > 0 && range < 0x7fffffff);
if (range >= 0xff)
val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 8;
if (range >= 0xffff)
val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 16;
if (range >= 0xffffff)
val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 24;
val += min;
if (val < min || val > max)
lto_value_range_error (purpose, val, min, max);
return val;
}
/* Output VAL into BP and verify it is in range MIN...MAX that is supposed
to be compile time constant.
Be host independent, limit range to 31bits. */
static inline void
bp_pack_int_in_range (struct bitpack_d *bp,
HOST_WIDE_INT min,
HOST_WIDE_INT max,
HOST_WIDE_INT val)
{
HOST_WIDE_INT range = max - min;
int nbits = floor_log2 (range) + 1;
gcc_checking_assert (val >= min && val <= max && range > 0
&& range < 0x7fffffff);
val -= min;
bp_pack_value (bp, val, nbits);
}
/* Input VAL into BP and verify it is in range MIN...MAX that is supposed
to be compile time constant. PURPOSE is used for error reporting. */
static inline HOST_WIDE_INT
bp_unpack_int_in_range (struct bitpack_d *bp,
const char *purpose,
HOST_WIDE_INT min,
HOST_WIDE_INT max)
{
HOST_WIDE_INT range = max - min;
int nbits = floor_log2 (range) + 1;
HOST_WIDE_INT val = bp_unpack_value (bp, nbits);
gcc_checking_assert (range > 0 && range < 0x7fffffff);
if (val < min || val > max)
lto_value_range_error (purpose, val, min, max);
return val;
}
/* Output VAL of type "enum enum_name" into OBS.
Assume range 0...ENUM_LAST - 1. */
#define lto_output_enum(obs,enum_name,enum_last,val) \
lto_output_int_in_range ((obs), 0, (int)(enum_last) - 1, (int)(val))
/* Input enum of type "enum enum_name" from IB.
Assume range 0...ENUM_LAST - 1. */
#define lto_input_enum(ib,enum_name,enum_last) \
(enum enum_name)lto_input_int_in_range ((ib), #enum_name, 0, \
(int)(enum_last) - 1)
/* Output VAL of type "enum enum_name" into BP.
Assume range 0...ENUM_LAST - 1. */
#define bp_pack_enum(bp,enum_name,enum_last,val) \
bp_pack_int_in_range ((bp), 0, (int)(enum_last) - 1, (int)(val))
/* Input enum of type "enum enum_name" from BP.
Assume range 0...ENUM_LAST - 1. */
#define bp_unpack_enum(bp,enum_name,enum_last) \
(enum enum_name)bp_unpack_int_in_range ((bp), #enum_name, 0, \
(int)(enum_last) - 1)
/* Output the start of a record with TAG to output block OB. */
static inline void
output_record_start (struct output_block *ob, enum LTO_tags tag)
{
lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS, tag);
}
/* Return the next tag in the input block IB. */
static inline enum LTO_tags
input_record_start (struct lto_input_block *ib)
{
return lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
}
/* In data-streamer.c */
void bp_pack_var_len_unsigned (struct bitpack_d *, unsigned HOST_WIDE_INT);
void bp_pack_var_len_int (struct bitpack_d *, HOST_WIDE_INT);
unsigned HOST_WIDE_INT bp_unpack_var_len_unsigned (struct bitpack_d *);
HOST_WIDE_INT bp_unpack_var_len_int (struct bitpack_d *);
/* In data-streamer-out.c */
void output_zero (struct output_block *);
void output_uleb128 (struct output_block *, unsigned HOST_WIDE_INT);
void output_sleb128 (struct output_block *, HOST_WIDE_INT);
void lto_output_string (struct output_block *, struct lto_output_stream *,
const char *, bool);
unsigned lto_string_index (struct output_block *, const char *, unsigned int,
bool);
void lto_output_string_with_length (struct output_block *,
struct lto_output_stream *,
const char *, unsigned int, bool);
const char *input_string_internal (struct data_in *, struct lto_input_block *,
unsigned int *);
/* In data-streamer-in.c */
const char *string_for_index (struct data_in *, unsigned int, unsigned int *);
const char *lto_input_string (struct data_in *, struct lto_input_block *);
#endif /* GCC_DATA_STREAMER_H */
/* Routines for reading GIMPLE from a file stream.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
#include "tree.h"
#include "tree-flow.h"
#include "data-streamer.h"
#include "tree-streamer.h"
#include "gimple-streamer.h"
/* Read a PHI function for basic block BB in function FN. DATA_IN is
the file being read. IB is the input block to use for reading. */
static gimple
input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
struct function *fn)
{
unsigned HOST_WIDE_INT ix;
tree phi_result;
int i, len;
gimple result;
ix = lto_input_uleb128 (ib);
phi_result = VEC_index (tree, SSANAMES (fn), ix);
len = EDGE_COUNT (bb->preds);
result = create_phi_node (phi_result, bb);
SSA_NAME_DEF_STMT (phi_result) = result;
/* We have to go through a lookup process here because the preds in the
reconstructed graph are generally in a different order than they
were in the original program. */
for (i = 0; i < len; i++)
{
tree def = lto_input_tree (ib, data_in);
int src_index = lto_input_uleb128 (ib);
location_t arg_loc = lto_input_location (ib, data_in);
basic_block sbb = BASIC_BLOCK_FOR_FUNCTION (fn, src_index);
edge e = NULL;
int j;
for (j = 0; j < len; j++)
if (EDGE_PRED (bb, j)->src == sbb)
{
e = EDGE_PRED (bb, j);
break;
}
add_phi_arg (result, def, e, arg_loc);
}
return result;
}
/* Read a statement with tag TAG in function FN from block IB using
descriptors in DATA_IN. */
static gimple
input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
struct function *fn, enum LTO_tags tag)
{
gimple stmt;
enum gimple_code code;
unsigned HOST_WIDE_INT num_ops;
size_t i;
struct bitpack_d bp;
code = lto_tag_to_gimple_code (tag);
/* Read the tuple header. */
bp = lto_input_bitpack (ib);
num_ops = bp_unpack_var_len_unsigned (&bp);
stmt = gimple_alloc (code, num_ops);
stmt->gsbase.no_warning = bp_unpack_value (&bp, 1);
if (is_gimple_assign (stmt))
stmt->gsbase.nontemporal_move = bp_unpack_value (&bp, 1);
stmt->gsbase.has_volatile_ops = bp_unpack_value (&bp, 1);
stmt->gsbase.subcode = bp_unpack_var_len_unsigned (&bp);
/* Read location information. */
gimple_set_location (stmt, lto_input_location (ib, data_in));
/* Read lexical block reference. */
gimple_set_block (stmt, lto_input_tree (ib, data_in));
/* Read in all the operands. */
switch (code)
{
case GIMPLE_RESX:
gimple_resx_set_region (stmt, lto_input_sleb128 (ib));
break;
case GIMPLE_EH_MUST_NOT_THROW:
gimple_eh_must_not_throw_set_fndecl (stmt, lto_input_tree (ib, data_in));
break;
case GIMPLE_EH_DISPATCH:
gimple_eh_dispatch_set_region (stmt, lto_input_sleb128 (ib));
break;
case GIMPLE_ASM:
{
/* FIXME lto. Move most of this into a new gimple_asm_set_string(). */
tree str;
stmt->gimple_asm.ni = lto_input_uleb128 (ib);
stmt->gimple_asm.no = lto_input_uleb128 (ib);
stmt->gimple_asm.nc = lto_input_uleb128 (ib);
stmt->gimple_asm.nl = lto_input_uleb128 (ib);
str = input_string_cst (data_in, ib);
stmt->gimple_asm.string = TREE_STRING_POINTER (str);
}
/* Fallthru */
case GIMPLE_ASSIGN:
case GIMPLE_CALL:
case GIMPLE_RETURN:
case GIMPLE_SWITCH:
case GIMPLE_LABEL:
case GIMPLE_COND:
case GIMPLE_GOTO:
case GIMPLE_DEBUG:
for (i = 0; i < num_ops; i++)
{
tree op = lto_input_tree (ib, data_in);
gimple_set_op (stmt, i, op);
if (!op)
continue;
/* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled
by decl merging. */
if (TREE_CODE (op) == ADDR_EXPR)
op = TREE_OPERAND (op, 0);
while (handled_component_p (op))
{
if (TREE_CODE (op) == COMPONENT_REF)
{
tree field, type, tem;
tree closest_match = NULL_TREE;
field = TREE_OPERAND (op, 1);
type = DECL_CONTEXT (field);
for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
{
if (tem == field)
break;
if (DECL_NONADDRESSABLE_P (tem)
== DECL_NONADDRESSABLE_P (field)
&& gimple_compare_field_offset (tem, field))
{
if (types_compatible_p (TREE_TYPE (tem),
TREE_TYPE (field)))
break;
else
closest_match = tem;
}
}
/* In case of type mismatches across units we can fail
to unify some types and thus not find a proper
field-decl here. */
if (tem == NULL_TREE)
{
/* Thus, emit a ODR violation warning. */
if (warning_at (gimple_location (stmt), 0,
"use of type %<%E%> with two mismatching "
"declarations at field %<%E%>",
type, TREE_OPERAND (op, 1)))
{
if (TYPE_FIELDS (type))
inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)),
"original type declared here");
inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)),
"field in mismatching type declared here");
if (TYPE_NAME (TREE_TYPE (field))
&& (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
== TYPE_DECL))
inform (DECL_SOURCE_LOCATION
(TYPE_NAME (TREE_TYPE (field))),
"type of field declared here");
if (closest_match
&& TYPE_NAME (TREE_TYPE (closest_match))
&& (TREE_CODE (TYPE_NAME
(TREE_TYPE (closest_match))) == TYPE_DECL))
inform (DECL_SOURCE_LOCATION
(TYPE_NAME (TREE_TYPE (closest_match))),
"type of mismatching field declared here");
}
/* And finally fixup the types. */
TREE_OPERAND (op, 0)
= build1 (VIEW_CONVERT_EXPR, type,
TREE_OPERAND (op, 0));
}
else
TREE_OPERAND (op, 1) = tem;
}
op = TREE_OPERAND (op, 0);
}
}
if (is_gimple_call (stmt))
{
if (gimple_call_internal_p (stmt))
gimple_call_set_internal_fn
(stmt, lto_input_enum (ib, internal_fn, IFN_LAST));
else
gimple_call_set_fntype (stmt, lto_input_tree (ib, data_in));
}
break;
case GIMPLE_NOP:
case GIMPLE_PREDICT:
break;
default:
internal_error ("bytecode stream: unknown GIMPLE statement tag %s",
lto_tag_name (tag));
}
/* Update the properties of symbols, SSA names and labels associated
with STMT. */
if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL)
{
tree lhs = gimple_get_lhs (stmt);
if (lhs && TREE_CODE (lhs) == SSA_NAME)
SSA_NAME_DEF_STMT (lhs) = stmt;
}
else if (code == GIMPLE_LABEL)
gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt))
|| DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl);
else if (code == GIMPLE_ASM)
{
unsigned i;
for (i = 0; i < gimple_asm_noutputs (stmt); i++)
{
tree op = TREE_VALUE (gimple_asm_output_op (stmt, i));
if (TREE_CODE (op) == SSA_NAME)
SSA_NAME_DEF_STMT (op) = stmt;
}
}
/* Reset alias information. */
if (code == GIMPLE_CALL)
gimple_call_reset_alias_info (stmt);
/* Mark the statement modified so its operand vectors can be filled in. */
gimple_set_modified (stmt, true);
return stmt;
}
/* Read a basic block with tag TAG from DATA_IN using input block IB.
FN is the function being processed. */
void
input_bb (struct lto_input_block *ib, enum LTO_tags tag,
struct data_in *data_in, struct function *fn,
int count_materialization_scale)
{
unsigned int index;
basic_block bb;
gimple_stmt_iterator bsi;
/* This routine assumes that CFUN is set to FN, as it needs to call
basic GIMPLE routines that use CFUN. */
gcc_assert (cfun == fn);
index = lto_input_uleb128 (ib);
bb = BASIC_BLOCK_FOR_FUNCTION (fn, index);
bb->count = (lto_input_sleb128 (ib) * count_materialization_scale
+ REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
bb->loop_depth = lto_input_sleb128 (ib);
bb->frequency = lto_input_sleb128 (ib);
bb->flags = lto_input_sleb128 (ib);
/* LTO_bb1 has statements. LTO_bb0 does not. */
if (tag == LTO_bb0)
return;
bsi = gsi_start_bb (bb);
tag = input_record_start (ib);
while (tag)
{
gimple stmt = input_gimple_stmt (ib, data_in, fn, tag);
if (!is_gimple_debug (stmt))
find_referenced_vars_in (stmt);
gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
/* After the statement, expect a 0 delimiter or the EH region
that the previous statement belongs to. */
tag = input_record_start (ib);
lto_tag_check_set (tag, 2, LTO_eh_region, LTO_null);
if (tag == LTO_eh_region)
{
HOST_WIDE_INT region = lto_input_sleb128 (ib);
gcc_assert (region == (int) region);
add_stmt_to_eh_lp (stmt, region);
}
tag = input_record_start (ib);
}
tag = input_record_start (ib);
while (tag)
{
gimple phi = input_phi (ib, bb, data_in, fn);
find_referenced_vars_in (phi);
tag = input_record_start (ib);
}
}
/* Routines for emitting GIMPLE to a file stream.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "tree-flow.h"
#include "data-streamer.h"
#include "gimple-streamer.h"
#include "lto-streamer.h"
/* Output PHI function PHI to the main stream in OB. */
static void
output_phi (struct output_block *ob, gimple phi)
{
unsigned i, len = gimple_phi_num_args (phi);
output_record_start (ob, lto_gimple_code_to_tag (GIMPLE_PHI));
output_uleb128 (ob, SSA_NAME_VERSION (PHI_RESULT (phi)));
for (i = 0; i < len; i++)
{
lto_output_tree_ref (ob, gimple_phi_arg_def (phi, i));
output_uleb128 (ob, gimple_phi_arg_edge (phi, i)->src->index);
lto_output_location (ob, gimple_phi_arg_location (phi, i));
}
}
/* Emit statement STMT on the main stream of output block OB. */
static void
output_gimple_stmt (struct output_block *ob, gimple stmt)
{
unsigned i;
enum gimple_code code;
enum LTO_tags tag;
struct bitpack_d bp;
/* Emit identifying tag. */
code = gimple_code (stmt);
tag = lto_gimple_code_to_tag (code);
output_record_start (ob, tag);
/* Emit the tuple header. */
bp = bitpack_create (ob->main_stream);
bp_pack_var_len_unsigned (&bp, gimple_num_ops (stmt));
bp_pack_value (&bp, gimple_no_warning_p (stmt), 1);
if (is_gimple_assign (stmt))
bp_pack_value (&bp, gimple_assign_nontemporal_move_p (stmt), 1);
bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1);
bp_pack_var_len_unsigned (&bp, stmt->gsbase.subcode);
lto_output_bitpack (&bp);
/* Emit location information for the statement. */
lto_output_location (ob, gimple_location (stmt));
/* Emit the lexical block holding STMT. */
lto_output_tree (ob, gimple_block (stmt), true);
/* Emit the operands. */
switch (gimple_code (stmt))
{
case GIMPLE_RESX:
output_sleb128 (ob, gimple_resx_region (stmt));
break;
case GIMPLE_EH_MUST_NOT_THROW:
lto_output_tree_ref (ob, gimple_eh_must_not_throw_fndecl (stmt));
break;
case GIMPLE_EH_DISPATCH:
output_sleb128 (ob, gimple_eh_dispatch_region (stmt));
break;
case GIMPLE_ASM:
lto_output_uleb128_stream (ob->main_stream, gimple_asm_ninputs (stmt));
lto_output_uleb128_stream (ob->main_stream, gimple_asm_noutputs (stmt));
lto_output_uleb128_stream (ob->main_stream, gimple_asm_nclobbers (stmt));
lto_output_uleb128_stream (ob->main_stream, gimple_asm_nlabels (stmt));
lto_output_string (ob, ob->main_stream, gimple_asm_string (stmt), true);
/* Fallthru */
case GIMPLE_ASSIGN:
case GIMPLE_CALL:
case GIMPLE_RETURN:
case GIMPLE_SWITCH:
case GIMPLE_LABEL:
case GIMPLE_COND:
case GIMPLE_GOTO:
case GIMPLE_DEBUG:
for (i = 0; i < gimple_num_ops (stmt); i++)
{
tree op = gimple_op (stmt, i);
/* Wrap all uses of non-automatic variables inside MEM_REFs
so that we do not have to deal with type mismatches on
merged symbols during IL read in. The first operand
of GIMPLE_DEBUG must be a decl, not MEM_REF, though. */
if (op && (i || !is_gimple_debug (stmt)))
{
tree *basep = &op;
while (handled_component_p (*basep))
basep = &TREE_OPERAND (*basep, 0);
if (TREE_CODE (*basep) == VAR_DECL
&& !auto_var_in_fn_p (*basep, current_function_decl)
&& !DECL_REGISTER (*basep))
{
bool volatilep = TREE_THIS_VOLATILE (*basep);
*basep = build2 (MEM_REF, TREE_TYPE (*basep),
build_fold_addr_expr (*basep),
build_int_cst (build_pointer_type
(TREE_TYPE (*basep)), 0));
TREE_THIS_VOLATILE (*basep) = volatilep;
}
}
lto_output_tree_ref (ob, op);
}
if (is_gimple_call (stmt))
{
if (gimple_call_internal_p (stmt))
lto_output_enum (ob->main_stream, internal_fn,
IFN_LAST, gimple_call_internal_fn (stmt));
else
lto_output_tree_ref (ob, gimple_call_fntype (stmt));
}
break;
case GIMPLE_NOP:
case GIMPLE_PREDICT:
break;
default:
gcc_unreachable ();
}
}
/* Output a basic block BB to the main stream in OB for this FN. */
void
output_bb (struct output_block *ob, basic_block bb, struct function *fn)
{
gimple_stmt_iterator bsi = gsi_start_bb (bb);
output_record_start (ob,
(!gsi_end_p (bsi)) || phi_nodes (bb)
? LTO_bb1
: LTO_bb0);
output_uleb128 (ob, bb->index);
output_sleb128 (ob, bb->count);
output_sleb128 (ob, bb->loop_depth);
output_sleb128 (ob, bb->frequency);
output_sleb128 (ob, bb->flags);
if (!gsi_end_p (bsi) || phi_nodes (bb))
{
/* Output the statements. The list of statements is terminated
with a zero. */
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
int region;
gimple stmt = gsi_stmt (bsi);
output_gimple_stmt (ob, stmt);
/* Emit the EH region holding STMT. */
region = lookup_stmt_eh_lp_fn (fn, stmt);
if (region != 0)
{
output_record_start (ob, LTO_eh_region);
output_sleb128 (ob, region);
}
else
output_record_start (ob, LTO_null);
}
output_record_start (ob, LTO_null);
for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
gimple phi = gsi_stmt (bsi);
/* Only emit PHIs for gimple registers. PHI nodes for .MEM
will be filled in on reading when the SSA form is
updated. */
if (is_gimple_reg (gimple_phi_result (phi)))
output_phi (ob, phi);
}
output_record_start (ob, LTO_null);
}
}
/* Data structures and functions for streaming GIMPLE.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#ifndef GCC_GIMPLE_STREAMER_H
#define GCC_GIMPLE_STREAMER_H
#include "basic-block.h"
#include "function.h"
#include "lto-streamer.h"
/* In gimple-streamer-in.c */
void input_bb (struct lto_input_block *, enum LTO_tags, struct data_in *,
struct function *, int);
/* In gimple-streamer-out.c */
void output_bb (struct output_block *, basic_block, struct function *);
#endif /* GCC_GIMPLE_STREAMER_H */
......@@ -84,6 +84,8 @@ along with GCC; see the file COPYING3. If not see
#include "tree-flow.h"
#include "ipa-prop.h"
#include "lto-streamer.h"
#include "data-streamer.h"
#include "tree-streamer.h"
#include "ipa-inline.h"
#include "alloc-pool.h"
......
......@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "gimple-pretty-print.h"
#include "lto-streamer.h"
#include "data-streamer.h"
#include "tree-streamer.h"
/* Intermediate information about a parameter that is only useful during the
......
......@@ -54,6 +54,8 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "target.h"
#include "lto-streamer.h"
#include "data-streamer.h"
#include "tree-streamer.h"
#include "cfgloop.h"
#include "tree-scalar-evolution.h"
#include "intl.h"
......
......@@ -43,6 +43,8 @@ along with GCC; see the file COPYING3. If not see
#include "output.h"
#include "pointer-set.h"
#include "lto-streamer.h"
#include "data-streamer.h"
#include "tree-streamer.h"
#include "gcov-io.h"
static void output_varpool (cgraph_node_set, varpool_node_set);
......
......@@ -63,115 +63,6 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] =
};
/* Read an ULEB128 Number of IB. */
unsigned HOST_WIDE_INT
lto_input_uleb128 (struct lto_input_block *ib)
{
unsigned HOST_WIDE_INT result = 0;
int shift = 0;
unsigned HOST_WIDE_INT byte;
while (true)
{
byte = lto_input_1_unsigned (ib);
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
return result;
}
}
/* HOST_WIDEST_INT version of lto_input_uleb128. IB is as in
lto_input_uleb128. */
unsigned HOST_WIDEST_INT
lto_input_widest_uint_uleb128 (struct lto_input_block *ib)
{
unsigned HOST_WIDEST_INT result = 0;
int shift = 0;
unsigned HOST_WIDEST_INT byte;
while (true)
{
byte = lto_input_1_unsigned (ib);
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
return result;
}
}
/* Read an SLEB128 Number of IB. */
HOST_WIDE_INT
lto_input_sleb128 (struct lto_input_block *ib)
{
HOST_WIDE_INT result = 0;
int shift = 0;
unsigned HOST_WIDE_INT byte;
while (true)
{
byte = lto_input_1_unsigned (ib);
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
{
if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40))
result |= - ((HOST_WIDE_INT)1 << shift);
return result;
}
}
}
/* Unpack VAL from BP in a variant of uleb format. */
unsigned HOST_WIDE_INT
bp_unpack_var_len_unsigned (struct bitpack_d *bp)
{
unsigned HOST_WIDE_INT result = 0;
int shift = 0;
unsigned HOST_WIDE_INT half_byte;
while (true)
{
half_byte = bp_unpack_value (bp, 4);
result |= (half_byte & 0x7) << shift;
shift += 3;
if ((half_byte & 0x8) == 0)
return result;
}
}
/* Unpack VAL from BP in a variant of sleb format. */
HOST_WIDE_INT
bp_unpack_var_len_int (struct bitpack_d *bp)
{
HOST_WIDE_INT result = 0;
int shift = 0;
unsigned HOST_WIDE_INT half_byte;
while (true)
{
half_byte = bp_unpack_value (bp, 4);
result |= (half_byte & 0x7) << shift;
shift += 3;
if ((half_byte & 0x8) == 0)
{
if ((shift < HOST_BITS_PER_WIDE_INT) && (half_byte & 0x4))
result |= - ((HOST_WIDE_INT)1 << shift);
return result;
}
}
}
/* Hooks so that the ipa passes can call into the lto front end to get
sections. */
......
......@@ -265,113 +265,6 @@ lto_output_data_stream (struct lto_output_stream *obs, const void *data,
}
/* Output an unsigned LEB128 quantity to OBS. */
void
lto_output_uleb128_stream (struct lto_output_stream *obs,
unsigned HOST_WIDE_INT work)
{
do
{
unsigned int byte = (work & 0x7f);
work >>= 7;
if (work != 0)
/* More bytes to follow. */
byte |= 0x80;
lto_output_1_stream (obs, byte);
}
while (work != 0);
}
/* Identical to output_uleb128_stream above except using unsigned
HOST_WIDEST_INT type. For efficiency on host where unsigned HOST_WIDEST_INT
is not native, we only use this if we know that HOST_WIDE_INT is not wide
enough. */
void
lto_output_widest_uint_uleb128_stream (struct lto_output_stream *obs,
unsigned HOST_WIDEST_INT work)
{
do
{
unsigned int byte = (work & 0x7f);
work >>= 7;
if (work != 0)
/* More bytes to follow. */
byte |= 0x80;
lto_output_1_stream (obs, byte);
}
while (work != 0);
}
/* Output a signed LEB128 quantity. */
void
lto_output_sleb128_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
{
int more, byte;
do
{
byte = (work & 0x7f);
/* arithmetic shift */
work >>= 7;
more = !((work == 0 && (byte & 0x40) == 0)
|| (work == -1 && (byte & 0x40) != 0));
if (more)
byte |= 0x80;
lto_output_1_stream (obs, byte);
}
while (more);
}
/* Pack WORK into BP in a variant of uleb format. */
void
bp_pack_var_len_unsigned (struct bitpack_d *bp, unsigned HOST_WIDE_INT work)
{
do
{
unsigned int half_byte = (work & 0x7);
work >>= 3;
if (work != 0)
/* More half_bytes to follow. */
half_byte |= 0x8;
bp_pack_value (bp, half_byte, 4);
}
while (work != 0);
}
/* Pack WORK into BP in a variant of sleb format. */
void
bp_pack_var_len_int (struct bitpack_d *bp, HOST_WIDE_INT work)
{
int more, half_byte;
do
{
half_byte = (work & 0x7);
/* arithmetic shift */
work >>= 3;
more = !((work == 0 && (half_byte & 0x4) == 0)
|| (work == -1 && (half_byte & 0x4) != 0));
if (more)
half_byte |= 0x8;
bp_pack_value (bp, half_byte, 4);
}
while (more);
}
/* Lookup NAME in ENCODER. If NAME is not found, create a new entry in
ENCODER for NAME with the next available index of ENCODER, then
print the index to OBS. True is returned if NAME was added to
......
......@@ -45,16 +45,12 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "output.h"
#include "ipa-utils.h"
#include "data-streamer.h"
#include "gimple-streamer.h"
#include "lto-streamer.h"
#include "tree-streamer.h"
#include "tree-pass.h"
/* Data structure used to hash file names in the source_location field. */
struct string_slot
{
const char *s;
unsigned int slot_num;
};
/* The table to hold the file names. */
static htab_t file_name_hash_table;
......@@ -62,7 +58,7 @@ static htab_t file_name_hash_table;
/* Check that tag ACTUAL has one of the given values. NUM_TAGS is the
number of valid tag values to check. */
static void
void
lto_tag_check_set (enum LTO_tags actual, int ntags, ...)
{
va_list ap;
......@@ -81,128 +77,6 @@ lto_tag_check_set (enum LTO_tags actual, int ntags, ...)
}
/* Check that tag ACTUAL is in the range [TAG1, TAG2]. */
static void
lto_tag_check_range (enum LTO_tags actual, enum LTO_tags tag1,
enum LTO_tags tag2)
{
if (actual < tag1 || actual > tag2)
internal_error ("bytecode stream: tag %s is not in the expected range "
"[%s, %s]",
lto_tag_name (actual),
lto_tag_name (tag1),
lto_tag_name (tag2));
}
/* Check that tag ACTUAL == EXPECTED. */
static void
lto_tag_check (enum LTO_tags actual, enum LTO_tags expected)
{
if (actual != expected)
internal_error ("bytecode stream: expected tag %s instead of %s",
lto_tag_name (expected), lto_tag_name (actual));
}
/* Return a hash code for P. */
static hashval_t
hash_string_slot_node (const void *p)
{
const struct string_slot *ds = (const struct string_slot *) p;
return (hashval_t) htab_hash_string (ds->s);
}
/* Returns nonzero if P1 and P2 are equal. */
static int
eq_string_slot_node (const void *p1, const void *p2)
{
const struct string_slot *ds1 = (const struct string_slot *) p1;
const struct string_slot *ds2 = (const struct string_slot *) p2;
return strcmp (ds1->s, ds2->s) == 0;
}
/* Read a string from the string table in DATA_IN using input block
IB. Write the length to RLEN. */
static const char *
string_for_index (struct data_in *data_in,
unsigned int loc,
unsigned int *rlen)
{
struct lto_input_block str_tab;
unsigned int len;
const char *result;
if (!loc)
{
*rlen = 0;
return NULL;
}
/* Get the string stored at location LOC in DATA_IN->STRINGS. */
LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings, loc - 1, data_in->strings_len);
len = lto_input_uleb128 (&str_tab);
*rlen = len;
if (str_tab.p + len > data_in->strings_len)
internal_error ("bytecode stream: string too long for the string table");
result = (const char *)(data_in->strings + str_tab.p);
return result;
}
/* Read a string from the string table in DATA_IN using input block
IB. Write the length to RLEN. */
static const char *
input_string_internal (struct data_in *data_in, struct lto_input_block *ib,
unsigned int *rlen)
{
return string_for_index (data_in, lto_input_uleb128 (ib), rlen);
}
/* Read a STRING_CST from the string table in DATA_IN using input
block IB. */
static tree
input_string_cst (struct data_in *data_in, struct lto_input_block *ib)
{
unsigned int len;
const char * ptr;
ptr = input_string_internal (data_in, ib, &len);
if (!ptr)
return NULL;
return build_string (len, ptr);
}
/* Read an IDENTIFIER from the string table in DATA_IN using input
block IB. */
static tree
input_identifier (struct data_in *data_in, struct lto_input_block *ib)
{
unsigned int len;
const char *ptr;
ptr = input_string_internal (data_in, ib, &len);
if (!ptr)
return NULL;
return get_identifier_with_length (ptr, len);
}
/* Read LENGTH bytes from STREAM to ADDR. */
void
......@@ -216,33 +90,6 @@ lto_input_data_block (struct lto_input_block *ib, void *addr, size_t length)
}
/* Read a NULL terminated string from the string table in DATA_IN. */
const char *
lto_input_string (struct data_in *data_in, struct lto_input_block *ib)
{
unsigned int len;
const char *ptr;
ptr = input_string_internal (data_in, ib, &len);
if (!ptr)
return NULL;
if (ptr[len - 1] != '\0')
internal_error ("bytecode stream: found non-null terminated string");
return ptr;
}
/* Return the next tag in the input block IB. */
static inline enum LTO_tags
input_record_start (struct lto_input_block *ib)
{
return lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
}
/* Lookup STRING in file_name_hash_table. If found, return the existing
string, otherwise insert STRING as the canonical version. */
......@@ -252,6 +99,7 @@ canon_file_name (const char *string)
void **slot;
struct string_slot s_slot;
s_slot.s = string;
s_slot.len = strlen (string);
slot = htab_find_slot (file_name_hash_table, &s_slot, INSERT);
if (*slot == NULL)
......@@ -333,7 +181,7 @@ lto_input_location_bitpack (struct data_in *data_in, struct bitpack_d *bp)
/* Read a location from input block IB. */
static location_t
location_t
lto_input_location (struct lto_input_block *ib, struct data_in *data_in)
{
struct bitpack_d bp;
......@@ -350,7 +198,7 @@ lto_input_location (struct lto_input_block *ib, struct data_in *data_in)
representation of the tree using lto_input_tree. FN is the
function scope for the read tree. */
static tree
tree
lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
struct function *fn, enum LTO_tags tag)
{
......@@ -411,33 +259,6 @@ lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in,
}
/* Read a chain of tree nodes from input block IB. DATA_IN contains
tables and descriptors for the file being read. */
static tree
lto_input_chain (struct lto_input_block *ib, struct data_in *data_in)
{
int i, count;
tree first, prev, curr;
first = prev = NULL_TREE;
count = lto_input_sleb128 (ib);
for (i = 0; i < count; i++)
{
curr = lto_input_tree (ib, data_in);
if (prev)
TREE_CHAIN (prev) = curr;
else
first = curr;
TREE_CHAIN (curr) = NULL_TREE;
prev = curr;
}
return first;
}
/* Read and return a double-linked list of catch handlers from input
block IB, using descriptors in DATA_IN. */
......@@ -641,7 +462,7 @@ fixup_eh_region_pointers (struct function *fn, HOST_WIDE_INT root_region)
/* Initialize EH support. */
static void
void
lto_init_eh (void)
{
static bool eh_initialized_p = false;
......@@ -856,51 +677,6 @@ input_cfg (struct lto_input_block *ib, struct function *fn,
}
/* Read a PHI function for basic block BB in function FN. DATA_IN is
the file being read. IB is the input block to use for reading. */
static gimple
input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
struct function *fn)
{
unsigned HOST_WIDE_INT ix;
tree phi_result;
int i, len;
gimple result;
ix = lto_input_uleb128 (ib);
phi_result = VEC_index (tree, SSANAMES (fn), ix);
len = EDGE_COUNT (bb->preds);
result = create_phi_node (phi_result, bb);
SSA_NAME_DEF_STMT (phi_result) = result;
/* We have to go through a lookup process here because the preds in the
reconstructed graph are generally in a different order than they
were in the original program. */
for (i = 0; i < len; i++)
{
tree def = lto_input_tree (ib, data_in);
int src_index = lto_input_uleb128 (ib);
location_t arg_loc = lto_input_location (ib, data_in);
basic_block sbb = BASIC_BLOCK_FOR_FUNCTION (fn, src_index);
edge e = NULL;
int j;
for (j = 0; j < len; j++)
if (EDGE_PRED (bb, j)->src == sbb)
{
e = EDGE_PRED (bb, j);
break;
}
add_phi_arg (result, def, e, arg_loc);
}
return result;
}
/* Read the SSA names array for function FN from DATA_IN using input
block IB. */
......@@ -934,263 +710,6 @@ input_ssa_names (struct lto_input_block *ib, struct data_in *data_in,
}
}
/* Read a statement with tag TAG in function FN from block IB using
descriptors in DATA_IN. */
static gimple
input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
struct function *fn, enum LTO_tags tag)
{
gimple stmt;
enum gimple_code code;
unsigned HOST_WIDE_INT num_ops;
size_t i;
struct bitpack_d bp;
code = lto_tag_to_gimple_code (tag);
/* Read the tuple header. */
bp = lto_input_bitpack (ib);
num_ops = bp_unpack_var_len_unsigned (&bp);
stmt = gimple_alloc (code, num_ops);
stmt->gsbase.no_warning = bp_unpack_value (&bp, 1);
if (is_gimple_assign (stmt))
stmt->gsbase.nontemporal_move = bp_unpack_value (&bp, 1);
stmt->gsbase.has_volatile_ops = bp_unpack_value (&bp, 1);
stmt->gsbase.subcode = bp_unpack_var_len_unsigned (&bp);
/* Read location information. */
gimple_set_location (stmt, lto_input_location (ib, data_in));
/* Read lexical block reference. */
gimple_set_block (stmt, lto_input_tree (ib, data_in));
/* Read in all the operands. */
switch (code)
{
case GIMPLE_RESX:
gimple_resx_set_region (stmt, lto_input_sleb128 (ib));
break;
case GIMPLE_EH_MUST_NOT_THROW:
gimple_eh_must_not_throw_set_fndecl (stmt, lto_input_tree (ib, data_in));
break;
case GIMPLE_EH_DISPATCH:
gimple_eh_dispatch_set_region (stmt, lto_input_sleb128 (ib));
break;
case GIMPLE_ASM:
{
/* FIXME lto. Move most of this into a new gimple_asm_set_string(). */
tree str;
stmt->gimple_asm.ni = lto_input_uleb128 (ib);
stmt->gimple_asm.no = lto_input_uleb128 (ib);
stmt->gimple_asm.nc = lto_input_uleb128 (ib);
stmt->gimple_asm.nl = lto_input_uleb128 (ib);
str = input_string_cst (data_in, ib);
stmt->gimple_asm.string = TREE_STRING_POINTER (str);
}
/* Fallthru */
case GIMPLE_ASSIGN:
case GIMPLE_CALL:
case GIMPLE_RETURN:
case GIMPLE_SWITCH:
case GIMPLE_LABEL:
case GIMPLE_COND:
case GIMPLE_GOTO:
case GIMPLE_DEBUG:
for (i = 0; i < num_ops; i++)
{
tree op = lto_input_tree (ib, data_in);
gimple_set_op (stmt, i, op);
if (!op)
continue;
/* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled
by decl merging. */
if (TREE_CODE (op) == ADDR_EXPR)
op = TREE_OPERAND (op, 0);
while (handled_component_p (op))
{
if (TREE_CODE (op) == COMPONENT_REF)
{
tree field, type, tem;
tree closest_match = NULL_TREE;
field = TREE_OPERAND (op, 1);
type = DECL_CONTEXT (field);
for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
{
if (tem == field)
break;
if (DECL_NONADDRESSABLE_P (tem)
== DECL_NONADDRESSABLE_P (field)
&& gimple_compare_field_offset (tem, field))
{
if (types_compatible_p (TREE_TYPE (tem),
TREE_TYPE (field)))
break;
else
closest_match = tem;
}
}
/* In case of type mismatches across units we can fail
to unify some types and thus not find a proper
field-decl here. */
if (tem == NULL_TREE)
{
/* Thus, emit a ODR violation warning. */
if (warning_at (gimple_location (stmt), 0,
"use of type %<%E%> with two mismatching "
"declarations at field %<%E%>",
type, TREE_OPERAND (op, 1)))
{
if (TYPE_FIELDS (type))
inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)),
"original type declared here");
inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)),
"field in mismatching type declared here");
if (TYPE_NAME (TREE_TYPE (field))
&& (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
== TYPE_DECL))
inform (DECL_SOURCE_LOCATION
(TYPE_NAME (TREE_TYPE (field))),
"type of field declared here");
if (closest_match
&& TYPE_NAME (TREE_TYPE (closest_match))
&& (TREE_CODE (TYPE_NAME
(TREE_TYPE (closest_match))) == TYPE_DECL))
inform (DECL_SOURCE_LOCATION
(TYPE_NAME (TREE_TYPE (closest_match))),
"type of mismatching field declared here");
}
/* And finally fixup the types. */
TREE_OPERAND (op, 0)
= build1 (VIEW_CONVERT_EXPR, type,
TREE_OPERAND (op, 0));
}
else
TREE_OPERAND (op, 1) = tem;
}
op = TREE_OPERAND (op, 0);
}
}
if (is_gimple_call (stmt))
{
if (gimple_call_internal_p (stmt))
gimple_call_set_internal_fn
(stmt, lto_input_enum (ib, internal_fn, IFN_LAST));
else
gimple_call_set_fntype (stmt, lto_input_tree (ib, data_in));
}
break;
case GIMPLE_NOP:
case GIMPLE_PREDICT:
break;
default:
internal_error ("bytecode stream: unknown GIMPLE statement tag %s",
lto_tag_name (tag));
}
/* Update the properties of symbols, SSA names and labels associated
with STMT. */
if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL)
{
tree lhs = gimple_get_lhs (stmt);
if (lhs && TREE_CODE (lhs) == SSA_NAME)
SSA_NAME_DEF_STMT (lhs) = stmt;
}
else if (code == GIMPLE_LABEL)
gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt))
|| DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl);
else if (code == GIMPLE_ASM)
{
unsigned i;
for (i = 0; i < gimple_asm_noutputs (stmt); i++)
{
tree op = TREE_VALUE (gimple_asm_output_op (stmt, i));
if (TREE_CODE (op) == SSA_NAME)
SSA_NAME_DEF_STMT (op) = stmt;
}
}
/* Reset alias information. */
if (code == GIMPLE_CALL)
gimple_call_reset_alias_info (stmt);
/* Mark the statement modified so its operand vectors can be filled in. */
gimple_set_modified (stmt, true);
return stmt;
}
/* Read a basic block with tag TAG from DATA_IN using input block IB.
FN is the function being processed. */
static void
input_bb (struct lto_input_block *ib, enum LTO_tags tag,
struct data_in *data_in, struct function *fn,
int count_materialization_scale)
{
unsigned int index;
basic_block bb;
gimple_stmt_iterator bsi;
/* This routine assumes that CFUN is set to FN, as it needs to call
basic GIMPLE routines that use CFUN. */
gcc_assert (cfun == fn);
index = lto_input_uleb128 (ib);
bb = BASIC_BLOCK_FOR_FUNCTION (fn, index);
bb->count = (lto_input_sleb128 (ib) * count_materialization_scale
+ REG_BR_PROB_BASE / 2) / REG_BR_PROB_BASE;
bb->loop_depth = lto_input_sleb128 (ib);
bb->frequency = lto_input_sleb128 (ib);
bb->flags = lto_input_sleb128 (ib);
/* LTO_bb1 has statements. LTO_bb0 does not. */
if (tag == LTO_bb0)
return;
bsi = gsi_start_bb (bb);
tag = input_record_start (ib);
while (tag)
{
gimple stmt = input_gimple_stmt (ib, data_in, fn, tag);
if (!is_gimple_debug (stmt))
find_referenced_vars_in (stmt);
gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
/* After the statement, expect a 0 delimiter or the EH region
that the previous statement belongs to. */
tag = input_record_start (ib);
lto_tag_check_set (tag, 2, LTO_eh_region, LTO_null);
if (tag == LTO_eh_region)
{
HOST_WIDE_INT region = lto_input_sleb128 (ib);
gcc_assert (region == (int) region);
add_stmt_to_eh_lp (stmt, region);
}
tag = input_record_start (ib);
}
tag = input_record_start (ib);
while (tag)
{
gimple phi = input_phi (ib, bb, data_in, fn);
find_referenced_vars_in (phi);
tag = input_record_start (ib);
}
}
/* Go through all NODE edges and fixup call_stmt pointers
so they point to STMTS. */
......@@ -1525,994 +1044,13 @@ lto_input_constructors_and_inits (struct lto_file_decl_data *file_data,
}
/* Unpack all the non-pointer fields of the TS_BASE structure of
expression EXPR from bitpack BP. */
static void
unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
{
/* Note that the code for EXPR has already been unpacked to create EXPR in
lto_materialize_tree. */
if (!TYPE_P (expr))
{
TREE_SIDE_EFFECTS (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_CONSTANT (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
/* TREE_PUBLIC is used on types to indicate that the type
has a TYPE_CACHED_VALUES vector. This is not streamed out,
so we skip it here. */
TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1);
}
else
bp_unpack_value (bp, 4);
TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1);
if (DECL_P (expr))
DECL_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
else if (TYPE_P (expr))
TYPE_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
else
bp_unpack_value (bp, 1);
TREE_ASM_WRITTEN (expr) = (unsigned) bp_unpack_value (bp, 1);
if (TYPE_P (expr))
TYPE_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
else
TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_USED (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_NOTHROW (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_STATIC (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_PRIVATE (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_PROTECTED (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_DEPRECATED (expr) = (unsigned) bp_unpack_value (bp, 1);
if (TYPE_P (expr))
TYPE_SATURATING (expr) = (unsigned) bp_unpack_value (bp, 1);
else if (TREE_CODE (expr) == SSA_NAME)
SSA_NAME_IS_DEFAULT_DEF (expr) = (unsigned) bp_unpack_value (bp, 1);
else
bp_unpack_value (bp, 1);
}
/* Unpack all the non-pointer fields of the TS_REAL_CST structure of
expression EXPR from bitpack BP. */
static void
unpack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
{
unsigned i;
REAL_VALUE_TYPE r;
REAL_VALUE_TYPE *rp;
r.cl = (unsigned) bp_unpack_value (bp, 2);
r.decimal = (unsigned) bp_unpack_value (bp, 1);
r.sign = (unsigned) bp_unpack_value (bp, 1);
r.signalling = (unsigned) bp_unpack_value (bp, 1);
r.canonical = (unsigned) bp_unpack_value (bp, 1);
r.uexp = (unsigned) bp_unpack_value (bp, EXP_BITS);
for (i = 0; i < SIGSZ; i++)
r.sig[i] = (unsigned long) bp_unpack_value (bp, HOST_BITS_PER_LONG);
rp = ggc_alloc_real_value ();
memcpy (rp, &r, sizeof (REAL_VALUE_TYPE));
TREE_REAL_CST_PTR (expr) = rp;
}
/* Unpack all the non-pointer fields of the TS_FIXED_CST structure of
expression EXPR from bitpack BP. */
static void
unpack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
{
struct fixed_value fv;
fv.mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
fv.data.low = bp_unpack_var_len_int (bp);
fv.data.high = bp_unpack_var_len_int (bp);
TREE_FIXED_CST (expr) = fv;
}
/* Unpack all the non-pointer fields of the TS_DECL_COMMON structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
{
DECL_MODE (expr) = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
DECL_NONLOCAL (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_VIRTUAL_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IGNORED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_PRESERVE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_DEBUG_EXPR_IS_FROM (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_EXTERNAL (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_GIMPLE_REG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_ALIGN (expr) = (unsigned) bp_unpack_var_len_unsigned (bp);
if (TREE_CODE (expr) == LABEL_DECL)
{
DECL_ERROR_ISSUED (expr) = (unsigned) bp_unpack_value (bp, 1);
EH_LANDING_PAD_NR (expr) = (int) bp_unpack_var_len_unsigned (bp);
/* Always assume an initial value of -1 for LABEL_DECL_UID to
force gimple_set_bb to recreate label_to_block_map. */
LABEL_DECL_UID (expr) = -1;
}
if (TREE_CODE (expr) == FIELD_DECL)
{
DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
expr->decl_common.off_align = bp_unpack_value (bp, 8);
}
if (TREE_CODE (expr) == RESULT_DECL
|| TREE_CODE (expr) == PARM_DECL
|| TREE_CODE (expr) == VAR_DECL)
{
DECL_BY_REFERENCE (expr) = (unsigned) bp_unpack_value (bp, 1);
if (TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
DECL_HAS_VALUE_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_RESTRICTED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
}
}
/* Unpack all the non-pointer fields of the TS_DECL_WRTL structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
{
DECL_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
}
/* Unpack all the non-pointer fields of the TS_DECL_WITH_VIS structure
of expression EXPR from bitpack BP. */
/* LTO streamer hook for reading GIMPLE trees. IB and DATA_IN are as in
lto_read_tree. EXPR is the tree was materialized by lto_read_tree and
needs GIMPLE specific data to be filled in. */
static void
unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
{
DECL_DEFER_OUTPUT (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp, 2);
DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp, 1);
if (TREE_CODE (expr) == VAR_DECL)
{
DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp, 3);
}
if (VAR_OR_FUNCTION_DECL_P (expr))
{
priority_type p;
p = (priority_type) bp_unpack_var_len_unsigned (bp);
SET_DECL_INIT_PRIORITY (expr, p);
}
}
/* Unpack all the non-pointer fields of the TS_FUNCTION_DECL structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
{
DECL_BUILT_IN_CLASS (expr) = bp_unpack_enum (bp, built_in_class,
BUILT_IN_LAST);
DECL_STATIC_CONSTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_STATIC_DESTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_UNINLINABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_POSSIBLY_INLINED (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IS_NOVOPS (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IS_RETURNS_TWICE (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IS_MALLOC (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IS_OPERATOR_NEW (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_DECLARED_INLINE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_STATIC_CHAIN (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr)
= (unsigned) bp_unpack_value (bp, 1);
DECL_NO_LIMIT_STACK (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_DISREGARD_INLINE_LIMITS (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_LOOPING_CONST_OR_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
{
DECL_FUNCTION_CODE (expr) = (enum built_in_function) bp_unpack_value (bp, 11);
if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (expr) >= END_BUILTINS)
fatal_error ("machine independent builtin code out of range");
else if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD)
{
tree result = targetm.builtin_decl (DECL_FUNCTION_CODE (expr), true);
if (!result || result == error_mark_node)
fatal_error ("target specific builtin not available");
}
}
if (DECL_STATIC_DESTRUCTOR (expr))
{
priority_type p;
p = (priority_type) bp_unpack_var_len_unsigned (bp);
SET_DECL_FINI_PRIORITY (expr, p);
}
}
/* Unpack all the non-pointer fields of the TS_TYPE_COMMON structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
{
enum machine_mode mode;
mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
SET_TYPE_MODE (expr, mode);
TYPE_STRING_FLAG (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_NO_FORCE_BLK (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_NEEDS_CONSTRUCTING (expr) = (unsigned) bp_unpack_value (bp, 1);
if (RECORD_OR_UNION_TYPE_P (expr))
TYPE_TRANSPARENT_AGGR (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_RESTRICT (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)
= (unsigned) bp_unpack_value (bp, 2);
TYPE_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_PRECISION (expr) = bp_unpack_var_len_unsigned (bp);
TYPE_ALIGN (expr) = bp_unpack_var_len_unsigned (bp);
TYPE_ALIAS_SET (expr) = bp_unpack_var_len_int (bp);
}
/* Unpack all the non-pointer fields of the TS_BLOCK structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
{
BLOCK_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
/* BLOCK_NUMBER is recomputed. */
}
/* Unpack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL
structure of expression EXPR from bitpack BP. */
static void
unpack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
{
}
/* Unpack all the non-pointer fields in EXPR into a bit pack. */
static void
unpack_value_fields (struct bitpack_d *bp, tree expr)
{
enum tree_code code;
code = TREE_CODE (expr);
/* Note that all these functions are highly sensitive to changes in
the types and sizes of each of the fields being packed. */
unpack_ts_base_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
unpack_ts_real_cst_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
unpack_ts_fixed_cst_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
unpack_ts_decl_common_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
unpack_ts_decl_wrtl_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
unpack_ts_decl_with_vis_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
unpack_ts_function_decl_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
unpack_ts_type_common_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
unpack_ts_block_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
unpack_ts_translation_unit_decl_value_fields (bp, expr);
if (streamer_hooks.unpack_value_fields)
streamer_hooks.unpack_value_fields (bp, expr);
}
/* Materialize a new tree from input block IB using descriptors in
DATA_IN. The code for the new tree should match TAG. Store in
*IX_P the index into the reader cache where the new tree is stored. */
static tree
lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in,
enum LTO_tags tag)
{
struct bitpack_d bp;
enum tree_code code;
tree result;
#ifdef LTO_STREAMER_DEBUG
HOST_WIDEST_INT orig_address_in_writer;
#endif
result = NULL_TREE;
#ifdef LTO_STREAMER_DEBUG
/* Read the word representing the memory address for the tree
as it was written by the writer. This is useful when
debugging differences between the writer and reader. */
orig_address_in_writer = lto_input_sleb128 (ib);
gcc_assert ((intptr_t) orig_address_in_writer == orig_address_in_writer);
#endif
code = lto_tag_to_tree_code (tag);
/* We should never see an SSA_NAME tree. Only the version numbers of
SSA names are ever written out. See input_ssa_names. */
gcc_assert (code != SSA_NAME);
/* Instantiate a new tree using the header data. */
if (CODE_CONTAINS_STRUCT (code, TS_STRING))
result = input_string_cst (data_in, ib);
else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
result = input_identifier (data_in, ib);
else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
{
HOST_WIDE_INT len = lto_input_sleb128 (ib);
result = make_tree_vec (len);
}
else if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
{
unsigned HOST_WIDE_INT len = lto_input_uleb128 (ib);
result = make_tree_binfo (len);
}
else
{
/* 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
/* Store the original address of the tree as seen by the writer
in RESULT's aux field. This is useful when debugging streaming
problems. This way, a debugging session can be started on
both writer and reader with a breakpoint using this address
value in both. */
lto_orig_address_map (result, (intptr_t) orig_address_in_writer);
#endif
/* Read the bitpack of non-pointer values from IB. */
bp = lto_input_bitpack (ib);
/* The first word in BP contains the code of the tree that we
are about to read. */
code = (enum tree_code) bp_unpack_value (&bp, 16);
lto_tag_check (lto_tree_code_to_tag (code), tag);
/* Unpack all the value fields from BP. */
unpack_value_fields (&bp, result);
/* Enter RESULT in the reader cache. This will make RESULT
available so that circular references in the rest of the tree
structure can be resolved in subsequent calls to lto_input_tree. */
lto_streamer_cache_append (data_in->reader_cache, result);
return result;
}
/* Read all pointer fields in the TS_COMMON structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_common_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
if (TREE_CODE (expr) != IDENTIFIER_NODE)
TREE_TYPE (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_VECTOR structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_vector_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
TREE_VECTOR_CST_ELTS (expr) = lto_input_chain (ib, data_in);
}
/* Read all pointer fields in the TS_COMPLEX structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_complex_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
TREE_REALPART (expr) = lto_input_tree (ib, data_in);
TREE_IMAGPART (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_DECL_MINIMAL structure of EXPR
from input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_decl_minimal_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
DECL_NAME (expr) = lto_input_tree (ib, data_in);
DECL_CONTEXT (expr) = lto_input_tree (ib, data_in);
DECL_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in);
}
/* Read all pointer fields in the TS_DECL_COMMON structure of EXPR from
input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_decl_common_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
DECL_SIZE (expr) = lto_input_tree (ib, data_in);
DECL_SIZE_UNIT (expr) = lto_input_tree (ib, data_in);
DECL_ATTRIBUTES (expr) = lto_input_tree (ib, data_in);
/* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
if (TREE_CODE (expr) == PARM_DECL)
TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
if ((TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
SET_DECL_VALUE_EXPR (expr, lto_input_tree (ib, data_in));
if (TREE_CODE (expr) == VAR_DECL)
{
tree dexpr = lto_input_tree (ib, data_in);
if (dexpr)
SET_DECL_DEBUG_EXPR (expr, dexpr);
}
}
/* Read all pointer fields in the TS_DECL_NON_COMMON structure of
EXPR from input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_decl_non_common_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
if (TREE_CODE (expr) == FUNCTION_DECL)
{
DECL_ARGUMENTS (expr) = lto_input_tree (ib, data_in);
DECL_RESULT (expr) = lto_input_tree (ib, data_in);
}
DECL_VINDEX (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
from input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_decl_with_vis_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
tree id;
id = lto_input_tree (ib, data_in);
if (id)
{
gcc_assert (TREE_CODE (id) == IDENTIFIER_NODE);
SET_DECL_ASSEMBLER_NAME (expr, id);
}
DECL_SECTION_NAME (expr) = lto_input_tree (ib, data_in);
DECL_COMDAT_GROUP (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_FIELD_DECL structure of EXPR from
input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_field_decl_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
DECL_FIELD_OFFSET (expr) = lto_input_tree (ib, data_in);
DECL_BIT_FIELD_TYPE (expr) = lto_input_tree (ib, data_in);
DECL_QUALIFIER (expr) = lto_input_tree (ib, data_in);
DECL_FIELD_BIT_OFFSET (expr) = lto_input_tree (ib, data_in);
DECL_FCONTEXT (expr) = lto_input_tree (ib, data_in);
TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
}
/* Read all pointer fields in the TS_FUNCTION_DECL structure of EXPR
from input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_function_decl_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
/* DECL_STRUCT_FUNCTION is handled by lto_input_function. FIXME lto,
maybe it should be handled here? */
DECL_FUNCTION_PERSONALITY (expr) = lto_input_tree (ib, data_in);
DECL_FUNCTION_SPECIFIC_TARGET (expr) = lto_input_tree (ib, data_in);
DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr) = lto_input_tree (ib, data_in);
/* If the file contains a function with an EH personality set,
then it was compiled with -fexceptions. In that case, initialize
the backend EH machinery. */
if (DECL_FUNCTION_PERSONALITY (expr))
lto_init_eh ();
}
/* Read all pointer fields in the TS_TYPE_COMMON structure of EXPR from
input block IB. DATA_IN contains tables and descriptors for the file
being read. */
static void
lto_input_ts_type_common_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
TYPE_SIZE (expr) = lto_input_tree (ib, data_in);
TYPE_SIZE_UNIT (expr) = lto_input_tree (ib, data_in);
TYPE_ATTRIBUTES (expr) = lto_input_tree (ib, data_in);
TYPE_NAME (expr) = lto_input_tree (ib, data_in);
/* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO. They will be
reconstructed during fixup. */
/* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
during fixup. */
TYPE_MAIN_VARIANT (expr) = lto_input_tree (ib, data_in);
TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
/* TYPE_CANONICAL gets re-computed during type merging. */
TYPE_CANONICAL (expr) = NULL_TREE;
TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
from input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_type_non_common_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in,
tree expr)
{
if (TREE_CODE (expr) == ENUMERAL_TYPE)
TYPE_VALUES (expr) = lto_input_tree (ib, data_in);
else if (TREE_CODE (expr) == ARRAY_TYPE)
TYPE_DOMAIN (expr) = lto_input_tree (ib, data_in);
else if (RECORD_OR_UNION_TYPE_P (expr))
TYPE_FIELDS (expr) = lto_input_tree (ib, data_in);
else if (TREE_CODE (expr) == FUNCTION_TYPE
|| TREE_CODE (expr) == METHOD_TYPE)
TYPE_ARG_TYPES (expr) = lto_input_tree (ib, data_in);
if (!POINTER_TYPE_P (expr))
TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
if (RECORD_OR_UNION_TYPE_P (expr))
TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_LIST structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_list_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
TREE_PURPOSE (expr) = lto_input_tree (ib, data_in);
TREE_VALUE (expr) = lto_input_tree (ib, data_in);
TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
}
/* Read all pointer fields in the TS_VEC structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_vec_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
int i;
/* Note that TREE_VEC_LENGTH was read by lto_materialize_tree to
instantiate EXPR. */
for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
TREE_VEC_ELT (expr, i) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_EXP structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_exp_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
int i, length;
location_t loc;
length = lto_input_sleb128 (ib);
gcc_assert (length == TREE_OPERAND_LENGTH (expr));
for (i = 0; i < length; i++)
TREE_OPERAND (expr, i) = lto_input_tree (ib, data_in);
loc = lto_input_location (ib, data_in);
SET_EXPR_LOCATION (expr, loc);
TREE_BLOCK (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_BLOCK structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_block_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
/* Do not stream BLOCK_SOURCE_LOCATION. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
BLOCK_VARS (expr) = lto_input_chain (ib, data_in);
/* Do not stream BLOCK_NONLOCALIZED_VARS. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
BLOCK_SUPERCONTEXT (expr) = lto_input_tree (ib, data_in);
/* Do not stream BLOCK_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
BLOCK_FRAGMENT_ORIGIN (expr) = lto_input_tree (ib, data_in);
BLOCK_FRAGMENT_CHAIN (expr) = lto_input_tree (ib, data_in);
/* We re-compute BLOCK_SUBBLOCKS of our parent here instead
of streaming it. For non-BLOCK BLOCK_SUPERCONTEXTs we still
stream the child relationship explicitly. */
if (BLOCK_SUPERCONTEXT (expr)
&& TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == BLOCK)
{
BLOCK_CHAIN (expr) = BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr));
BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr)) = expr;
}
/* The global block is rooted at the TU decl. Hook it here to
avoid the need to stream in this block during WPA time. */
else if (BLOCK_SUPERCONTEXT (expr)
&& TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == TRANSLATION_UNIT_DECL)
DECL_INITIAL (BLOCK_SUPERCONTEXT (expr)) = expr;
/* The function-level block is connected at the time we read in
function bodies for the same reason. */
}
/* Read all pointer fields in the TS_BINFO structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
unsigned i, len;
tree t;
/* Note that the number of slots in EXPR was read in
lto_materialize_tree when instantiating EXPR. However, the
vector is empty so we cannot rely on VEC_length to know how many
elements to read. So, this list is emitted as a 0-terminated
list on the writer side. */
do
{
t = lto_input_tree (ib, data_in);
if (t)
VEC_quick_push (tree, BINFO_BASE_BINFOS (expr), t);
}
while (t);
BINFO_OFFSET (expr) = lto_input_tree (ib, data_in);
BINFO_VTABLE (expr) = lto_input_tree (ib, data_in);
BINFO_VIRTUALS (expr) = lto_input_tree (ib, data_in);
BINFO_VPTR_FIELD (expr) = lto_input_tree (ib, data_in);
len = lto_input_uleb128 (ib);
if (len > 0)
{
VEC_reserve_exact (tree, gc, BINFO_BASE_ACCESSES (expr), len);
for (i = 0; i < len; i++)
{
tree a = lto_input_tree (ib, data_in);
VEC_quick_push (tree, BINFO_BASE_ACCESSES (expr), a);
}
}
BINFO_INHERITANCE_CHAIN (expr) = lto_input_tree (ib, data_in);
BINFO_SUBVTT_INDEX (expr) = lto_input_tree (ib, data_in);
BINFO_VPTR_INDEX (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_CONSTRUCTOR structure of EXPR from
input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_constructor_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
unsigned i, len;
len = lto_input_uleb128 (ib);
for (i = 0; i < len; i++)
{
tree index, value;
index = lto_input_tree (ib, data_in);
value = lto_input_tree (ib, data_in);
CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (expr), index, value);
}
}
/* Input a TS_TARGET_OPTION tree from IB into EXPR. */
static void
lto_input_ts_target_option (struct lto_input_block *ib, tree expr)
{
unsigned i, len;
struct bitpack_d bp;
struct cl_target_option *t = TREE_TARGET_OPTION (expr);
bp = lto_input_bitpack (ib);
len = sizeof (struct cl_target_option);
for (i = 0; i < len; i++)
((unsigned char *)t)[i] = bp_unpack_value (&bp, 8);
if (bp_unpack_value (&bp, 32) != 0x12345678)
fatal_error ("cl_target_option size mismatch in LTO reader and writer");
}
/* Input a TS_TRANSLATION_UNIT_DECL tree from IB and DATA_IN into EXPR. */
static void
lto_input_ts_translation_unit_decl_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in,
tree expr)
{
TRANSLATION_UNIT_LANGUAGE (expr) = xstrdup (lto_input_string (data_in, ib));
VEC_safe_push (tree, gc, all_translation_units, expr);
}
/* Helper for lto_input_tree. Read all pointer fields in EXPR from
input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
tree expr)
{
enum tree_code code;
code = TREE_CODE (expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
lto_input_ts_common_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
lto_input_ts_vector_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
lto_input_ts_complex_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
lto_input_ts_decl_minimal_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
lto_input_ts_decl_common_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
lto_input_ts_decl_non_common_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
lto_input_ts_decl_with_vis_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
lto_input_ts_field_decl_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
lto_input_ts_function_decl_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
lto_input_ts_type_common_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
lto_input_ts_type_non_common_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_LIST))
lto_input_ts_list_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_VEC))
lto_input_ts_vec_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_EXP))
lto_input_ts_exp_tree_pointers (ib, data_in, expr);
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_CONSTRUCTOR))
lto_input_ts_constructor_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
lto_input_ts_target_option (ib, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
lto_input_ts_translation_unit_decl_tree_pointers (ib, data_in, expr);
}
/* Read an index IX from input block IB and return the tree node at
DATA_IN->FILE_DATA->GLOBALS_INDEX[IX]. */
static tree
lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in)
{
unsigned HOST_WIDE_INT ix;
tree result;
enum LTO_tags expected_tag;
ix = lto_input_uleb128 (ib);
expected_tag = lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
result = lto_streamer_cache_get (data_in->reader_cache, ix);
gcc_assert (result
&& TREE_CODE (result) == lto_tag_to_tree_code (expected_tag));
return result;
}
/* Read a code and class from input block IB and return the
corresponding builtin. DATA_IN is as in lto_input_tree. */
static tree
lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
{
enum built_in_class fclass;
enum built_in_function fcode;
const char *asmname;
tree result;
fclass = lto_input_enum (ib, built_in_class, BUILT_IN_LAST);
gcc_assert (fclass == BUILT_IN_NORMAL || fclass == BUILT_IN_MD);
fcode = (enum built_in_function) lto_input_uleb128 (ib);
if (fclass == BUILT_IN_NORMAL)
{
if (fcode >= END_BUILTINS)
fatal_error ("machine independent builtin code out of range");
result = built_in_decls[fcode];
gcc_assert (result);
}
else if (fclass == BUILT_IN_MD)
{
result = targetm.builtin_decl (fcode, true);
if (!result || result == error_mark_node)
fatal_error ("target specific builtin not available");
}
else
gcc_unreachable ();
asmname = lto_input_string (data_in, ib);
if (asmname)
set_builtin_user_assembler_name (result, asmname);
lto_streamer_cache_append (data_in->reader_cache, result);
return result;
}
/* Read the physical representation of a tree node with tag TAG from
input block IB using the per-file context in DATA_IN. */
static tree
lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
enum LTO_tags tag)
{
tree result;
result = lto_materialize_tree (ib, data_in, tag);
/* Read all the pointer fields in RESULT. */
lto_input_tree_pointers (ib, data_in, result);
/* Call back into the streaming module to read anything else it
may need. */
if (streamer_hooks.read_tree)
streamer_hooks.read_tree (ib, data_in, result);
/* We should never try to instantiate an MD or NORMAL builtin here. */
if (TREE_CODE (result) == FUNCTION_DECL)
gcc_assert (!lto_stream_as_builtin_p (result));
/* end_marker = */ lto_input_1_unsigned (ib);
#ifdef LTO_STREAMER_DEBUG
/* Remove the mapping to RESULT's original address set by
lto_materialize_tree. */
lto_orig_address_remove (result);
#endif
return result;
}
/* LTO streamer hook for reading GIMPLE trees. IB and DATA_IN are as in
lto_read_tree. EXPR is the tree was materialized by lto_read_tree and
needs GIMPLE specific data to be filled in. */
void
lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
tree expr)
void
lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
tree expr)
{
if (DECL_P (expr)
&& TREE_CODE (expr) != FUNCTION_DECL
......@@ -2521,84 +1059,6 @@ lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
}
/* Read and INTEGER_CST node from input block IB using the per-file
context in DATA_IN. */
static tree
lto_input_integer_cst (struct lto_input_block *ib, struct data_in *data_in)
{
tree result, type;
HOST_WIDE_INT low, high;
bool overflow_p;
type = lto_input_tree (ib, data_in);
overflow_p = (lto_input_1_unsigned (ib) != 0);
low = lto_input_uleb128 (ib);
high = lto_input_uleb128 (ib);
result = build_int_cst_wide (type, low, high);
/* If the original constant had overflown, build a replica of RESULT to
avoid modifying the shared constant returned by build_int_cst_wide. */
if (overflow_p)
{
result = copy_node (result);
TREE_OVERFLOW (result) = 1;
}
return result;
}
/* Read a tree from input block IB using the per-file context in
DATA_IN. This context is used, for example, to resolve references
to previously read nodes. */
tree
lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
{
enum LTO_tags tag;
tree result;
tag = input_record_start (ib);
gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS);
if (tag == LTO_null)
result = NULL_TREE;
else if (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
{
/* If TAG is a reference to an indexable tree, the next value
in IB is the index into the table where we expect to find
that tree. */
result = lto_input_tree_ref (ib, data_in, cfun, tag);
}
else if (tag == LTO_tree_pickle_reference)
{
/* If TAG is a reference to a previously read tree, look it up in
the reader cache. */
result = lto_get_pickled_tree (ib, data_in);
}
else if (tag == LTO_builtin_decl)
{
/* If we are going to read a built-in function, all we need is
the code and class. */
result = lto_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. */
result = lto_input_integer_cst (ib, data_in);
}
else
{
/* Otherwise, materialize a new node from IB. */
result = lto_read_tree (ib, data_in, tag);
}
return result;
}
/* Initialization for the LTO reader. */
void
......
......@@ -41,45 +41,10 @@ along with GCC; see the file COPYING3. If not see
#include "vec.h"
#include "lto-symtab.h"
#include "lto-streamer.h"
struct string_slot
{
const char *s;
int len;
unsigned int slot_num;
};
/* Returns a hash code for P.
Shamelessly stollen from libiberty. */
static hashval_t
hash_string_slot_node (const void *p)
{
const struct string_slot *ds = (const struct string_slot *) p;
hashval_t r = ds->len;
int i;
for (i = 0; i < ds->len; i++)
r = r * 67 + (unsigned)ds->s[i] - 113;
return r;
}
/* Returns nonzero if P1 and P2 are equal. */
static int
eq_string_slot_node (const void *p1, const void *p2)
{
const struct string_slot *ds1 = (const struct string_slot *) p1;
const struct string_slot *ds2 = (const struct string_slot *) p2;
if (ds1->len == ds2->len)
return memcmp (ds1->s, ds2->s, ds1->len) == 0;
return 0;
}
#include "data-streamer.h"
#include "gimple-streamer.h"
#include "tree-streamer.h"
#include "streamer-hooks.h"
/* Clear the line info stored in DATA_IN. */
......@@ -120,1319 +85,113 @@ create_output_block (enum lto_section_type section_type)
}
/* Destroy the output block OB. */
void
destroy_output_block (struct output_block *ob)
{
enum lto_section_type section_type = ob->section_type;
htab_delete (ob->string_hash_table);
free (ob->main_stream);
free (ob->string_stream);
if (section_type == LTO_section_function_body)
free (ob->cfg_stream);
lto_streamer_cache_delete (ob->writer_cache);
obstack_free (&ob->obstack, NULL);
free (ob);
}
/* Return index used to reference STRING of LEN characters in the string table
in OB. The string might or might not include a trailing '\0'.
Then put the index onto the INDEX_STREAM.
When PERSISTENT is set, the string S is supposed to not change during
duration of the OB and thus OB can keep pointer into it. */
static unsigned
lto_string_index (struct output_block *ob,
const char *s,
unsigned int len,
bool persistent)
{
struct string_slot **slot;
struct string_slot s_slot;
s_slot.s = s;
s_slot.len = len;
s_slot.slot_num = 0;
slot = (struct string_slot **) htab_find_slot (ob->string_hash_table,
&s_slot, INSERT);
if (*slot == NULL)
{
struct lto_output_stream *string_stream = ob->string_stream;
unsigned int start = string_stream->total_size;
struct string_slot *new_slot
= XOBNEW (&ob->obstack, struct string_slot);
const char *string;
if (!persistent)
{
char *tmp;
string = tmp = XOBNEWVEC (&ob->obstack, char, len);
memcpy (tmp, s, len);
}
else
string = s;
new_slot->s = string;
new_slot->len = len;
new_slot->slot_num = start;
*slot = new_slot;
lto_output_uleb128_stream (string_stream, len);
lto_output_data_stream (string_stream, string, len);
return start + 1;
}
else
{
struct string_slot *old_slot = *slot;
return old_slot->slot_num + 1;
}
}
/* Output STRING of LEN characters to the string
table in OB. The string might or might not include a trailing '\0'.
Then put the index onto the INDEX_STREAM.
When PERSISTENT is set, the string S is supposed to not change during
duration of the OB and thus OB can keep pointer into it. */
static void
lto_output_string_with_length (struct output_block *ob,
struct lto_output_stream *index_stream,
const char *s,
unsigned int len,
bool persistent)
{
if (s)
lto_output_uleb128_stream (index_stream,
lto_string_index (ob, s, len, persistent));
else
lto_output_1_stream (index_stream, 0);
}
/* Output the '\0' terminated STRING to the string
table in OB. Then put the index onto the INDEX_STREAM.
When PERSISTENT is set, the string S is supposed to not change during
duration of the OB and thus OB can keep pointer into it. */
static void
lto_output_string (struct output_block *ob,
struct lto_output_stream *index_stream,
const char *string,
bool persistent)
{
if (string)
lto_output_string_with_length (ob, index_stream, string,
strlen (string) + 1,
persistent);
else
lto_output_1_stream (index_stream, 0);
}
/* Output the STRING constant to the string
table in OB. Then put the index onto the INDEX_STREAM. */
static void
output_string_cst (struct output_block *ob,
struct lto_output_stream *index_stream,
tree string)
{
lto_output_string_with_length (ob, index_stream,
TREE_STRING_POINTER (string),
TREE_STRING_LENGTH (string),
true);
}
/* Output the identifier ID to the string
table in OB. Then put the index onto the INDEX_STREAM. */
static void
output_identifier (struct output_block *ob,
struct lto_output_stream *index_stream,
tree id)
{
lto_output_string_with_length (ob, index_stream,
IDENTIFIER_POINTER (id),
IDENTIFIER_LENGTH (id),
true);
}
/* Write a zero to the output stream. */
static void
output_zero (struct output_block *ob)
{
lto_output_1_stream (ob->main_stream, 0);
}
/* Output an unsigned LEB128 quantity to OB->main_stream. */
static void
output_uleb128 (struct output_block *ob, unsigned HOST_WIDE_INT work)
{
lto_output_uleb128_stream (ob->main_stream, work);
}
/* Output a signed LEB128 quantity to OB->main_stream. */
static void
output_sleb128 (struct output_block *ob, HOST_WIDE_INT work)
{
lto_output_sleb128_stream (ob->main_stream, work);
}
/* Output the start of a record with TAG to output block OB. */
static inline void
output_record_start (struct output_block *ob, enum LTO_tags tag)
{
lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS, tag);
}
/* Look up NODE in the type table and write the index for it to OB. */
static void
output_type_ref (struct output_block *ob, tree node)
{
output_record_start (ob, LTO_type_ref);
lto_output_type_ref_index (ob->decl_state, ob->main_stream, node);
}
/* Pack all the non-pointer fields of the TS_BASE structure of
expression EXPR into bitpack BP. */
static void
pack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_value (bp, TREE_CODE (expr), 16);
if (!TYPE_P (expr))
{
bp_pack_value (bp, TREE_SIDE_EFFECTS (expr), 1);
bp_pack_value (bp, TREE_CONSTANT (expr), 1);
bp_pack_value (bp, TREE_READONLY (expr), 1);
/* TREE_PUBLIC is used on types to indicate that the type
has a TYPE_CACHED_VALUES vector. This is not streamed out,
so we skip it here. */
bp_pack_value (bp, TREE_PUBLIC (expr), 1);
}
else
bp_pack_value (bp, 0, 4);
bp_pack_value (bp, TREE_ADDRESSABLE (expr), 1);
bp_pack_value (bp, TREE_THIS_VOLATILE (expr), 1);
if (DECL_P (expr))
bp_pack_value (bp, DECL_UNSIGNED (expr), 1);
else if (TYPE_P (expr))
bp_pack_value (bp, TYPE_UNSIGNED (expr), 1);
else
bp_pack_value (bp, 0, 1);
/* We write debug info two times, do not confuse the second one. */
bp_pack_value (bp, TYPE_P (expr) ? 0 : TREE_ASM_WRITTEN (expr), 1);
if (TYPE_P (expr))
bp_pack_value (bp, TYPE_ARTIFICIAL (expr), 1);
else
bp_pack_value (bp, TREE_NO_WARNING (expr), 1);
bp_pack_value (bp, TREE_USED (expr), 1);
bp_pack_value (bp, TREE_NOTHROW (expr), 1);
bp_pack_value (bp, TREE_STATIC (expr), 1);
bp_pack_value (bp, TREE_PRIVATE (expr), 1);
bp_pack_value (bp, TREE_PROTECTED (expr), 1);
bp_pack_value (bp, TREE_DEPRECATED (expr), 1);
if (TYPE_P (expr))
bp_pack_value (bp, TYPE_SATURATING (expr), 1);
else if (TREE_CODE (expr) == SSA_NAME)
bp_pack_value (bp, SSA_NAME_IS_DEFAULT_DEF (expr), 1);
else
bp_pack_value (bp, 0, 1);
}
/* Pack all the non-pointer fields of the TS_REAL_CST structure of
expression EXPR into bitpack BP. */
static void
pack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
{
unsigned i;
REAL_VALUE_TYPE r;
r = TREE_REAL_CST (expr);
bp_pack_value (bp, r.cl, 2);
bp_pack_value (bp, r.decimal, 1);
bp_pack_value (bp, r.sign, 1);
bp_pack_value (bp, r.signalling, 1);
bp_pack_value (bp, r.canonical, 1);
bp_pack_value (bp, r.uexp, EXP_BITS);
for (i = 0; i < SIGSZ; i++)
bp_pack_value (bp, r.sig[i], HOST_BITS_PER_LONG);
}
/* Pack all the non-pointer fields of the TS_FIXED_CST structure of
expression EXPR into bitpack BP. */
static void
pack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
{
struct fixed_value fv = TREE_FIXED_CST (expr);
bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, fv.mode);
bp_pack_var_len_int (bp, fv.data.low);
bp_pack_var_len_int (bp, fv.data.high);
}
/* Pack all the non-pointer fields of the TS_DECL_COMMON structure
of expression EXPR into bitpack BP. */
static void
pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, DECL_MODE (expr));
bp_pack_value (bp, DECL_NONLOCAL (expr), 1);
bp_pack_value (bp, DECL_VIRTUAL_P (expr), 1);
bp_pack_value (bp, DECL_IGNORED_P (expr), 1);
bp_pack_value (bp, DECL_ABSTRACT (expr), 1);
bp_pack_value (bp, DECL_ARTIFICIAL (expr), 1);
bp_pack_value (bp, DECL_USER_ALIGN (expr), 1);
bp_pack_value (bp, DECL_PRESERVE_P (expr), 1);
bp_pack_value (bp, DECL_DEBUG_EXPR_IS_FROM (expr), 1);
bp_pack_value (bp, DECL_EXTERNAL (expr), 1);
bp_pack_value (bp, DECL_GIMPLE_REG_P (expr), 1);
bp_pack_var_len_unsigned (bp, DECL_ALIGN (expr));
if (TREE_CODE (expr) == LABEL_DECL)
{
/* Note that we do not write LABEL_DECL_UID. The reader will
always assume an initial value of -1 so that the
label_to_block_map is recreated by gimple_set_bb. */
bp_pack_value (bp, DECL_ERROR_ISSUED (expr), 1);
bp_pack_var_len_unsigned (bp, EH_LANDING_PAD_NR (expr));
}
if (TREE_CODE (expr) == FIELD_DECL)
{
bp_pack_value (bp, DECL_PACKED (expr), 1);
bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
bp_pack_value (bp, expr->decl_common.off_align, 8);
}
if (TREE_CODE (expr) == RESULT_DECL
|| TREE_CODE (expr) == PARM_DECL
|| TREE_CODE (expr) == VAR_DECL)
{
bp_pack_value (bp, DECL_BY_REFERENCE (expr), 1);
if (TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
bp_pack_value (bp, DECL_HAS_VALUE_EXPR_P (expr), 1);
bp_pack_value (bp, DECL_RESTRICTED_P (expr), 1);
}
}
/* Pack all the non-pointer fields of the TS_DECL_WRTL structure
of expression EXPR into bitpack BP. */
static void
pack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_value (bp, DECL_REGISTER (expr), 1);
}
/* Pack all the non-pointer fields of the TS_DECL_WITH_VIS structure
of expression EXPR into bitpack BP. */
static void
pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_value (bp, DECL_DEFER_OUTPUT (expr), 1);
bp_pack_value (bp, DECL_COMMON (expr), 1);
bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1);
bp_pack_value (bp, DECL_WEAK (expr), 1);
bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr), 1);
bp_pack_value (bp, DECL_COMDAT (expr), 1);
bp_pack_value (bp, DECL_VISIBILITY (expr), 2);
bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr), 1);
if (TREE_CODE (expr) == VAR_DECL)
{
bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1);
bp_pack_value (bp, DECL_IN_TEXT_SECTION (expr), 1);
bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1);
bp_pack_value (bp, DECL_TLS_MODEL (expr), 3);
}
if (VAR_OR_FUNCTION_DECL_P (expr))
bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr));
}
/* Pack all the non-pointer fields of the TS_FUNCTION_DECL structure
of expression EXPR into bitpack BP. */
static void
pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
{
/* For normal/md builtins we only write the class and code, so they
should never be handled here. */
gcc_assert (!lto_stream_as_builtin_p (expr));
bp_pack_enum (bp, built_in_class, BUILT_IN_LAST,
DECL_BUILT_IN_CLASS (expr));
bp_pack_value (bp, DECL_STATIC_CONSTRUCTOR (expr), 1);
bp_pack_value (bp, DECL_STATIC_DESTRUCTOR (expr), 1);
bp_pack_value (bp, DECL_UNINLINABLE (expr), 1);
bp_pack_value (bp, DECL_POSSIBLY_INLINED (expr), 1);
bp_pack_value (bp, DECL_IS_NOVOPS (expr), 1);
bp_pack_value (bp, DECL_IS_RETURNS_TWICE (expr), 1);
bp_pack_value (bp, DECL_IS_MALLOC (expr), 1);
bp_pack_value (bp, DECL_IS_OPERATOR_NEW (expr), 1);
bp_pack_value (bp, DECL_DECLARED_INLINE_P (expr), 1);
bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1);
bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1);
bp_pack_value (bp, DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr), 1);
bp_pack_value (bp, DECL_NO_LIMIT_STACK (expr), 1);
bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1);
bp_pack_value (bp, DECL_PURE_P (expr), 1);
bp_pack_value (bp, DECL_LOOPING_CONST_OR_PURE_P (expr), 1);
if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
bp_pack_value (bp, DECL_FUNCTION_CODE (expr), 11);
if (DECL_STATIC_DESTRUCTOR (expr))
bp_pack_var_len_unsigned (bp, DECL_FINI_PRIORITY (expr));
}
/* Pack all the non-pointer fields of the TS_TYPE_COMMON structure
of expression EXPR into bitpack BP. */
static void
pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, TYPE_MODE (expr));
bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1);
bp_pack_value (bp, TYPE_NO_FORCE_BLK (expr), 1);
bp_pack_value (bp, TYPE_NEEDS_CONSTRUCTING (expr), 1);
if (RECORD_OR_UNION_TYPE_P (expr))
bp_pack_value (bp, TYPE_TRANSPARENT_AGGR (expr), 1);
bp_pack_value (bp, TYPE_PACKED (expr), 1);
bp_pack_value (bp, TYPE_RESTRICT (expr), 1);
bp_pack_value (bp, TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr), 2);
bp_pack_value (bp, TYPE_USER_ALIGN (expr), 1);
bp_pack_value (bp, TYPE_READONLY (expr), 1);
bp_pack_var_len_unsigned (bp, TYPE_PRECISION (expr));
bp_pack_var_len_unsigned (bp, TYPE_ALIGN (expr));
bp_pack_var_len_int (bp, TYPE_ALIAS_SET (expr) == 0 ? 0 : -1);
}
/* Pack all the non-pointer fields of the TS_BLOCK structure
of expression EXPR into bitpack BP. */
static void
pack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_value (bp, BLOCK_ABSTRACT (expr), 1);
/* BLOCK_NUMBER is recomputed. */
}
/* Pack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL structure
of expression EXPR into bitpack BP. */
static void
pack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
{
}
/* Pack all the non-pointer fields in EXPR into a bit pack. */
static void
pack_value_fields (struct bitpack_d *bp, tree expr)
{
enum tree_code code;
code = TREE_CODE (expr);
/* Note that all these functions are highly sensitive to changes in
the types and sizes of each of the fields being packed. */
pack_ts_base_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
pack_ts_real_cst_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
pack_ts_fixed_cst_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
pack_ts_decl_common_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
pack_ts_decl_wrtl_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
pack_ts_decl_with_vis_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
pack_ts_function_decl_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
pack_ts_type_common_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
pack_ts_block_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
pack_ts_translation_unit_decl_value_fields (bp, expr);
if (streamer_hooks.pack_value_fields)
streamer_hooks.pack_value_fields (bp, expr);
}
/* Output info about new location into bitpack BP.
After outputting bitpack, lto_output_location_data has
to be done to output actual data. */
static inline void
lto_output_location_bitpack (struct bitpack_d *bp,
struct output_block *ob,
location_t loc)
{
expanded_location xloc;
bp_pack_value (bp, loc == UNKNOWN_LOCATION, 1);
if (loc == UNKNOWN_LOCATION)
return;
xloc = expand_location (loc);
bp_pack_value (bp, ob->current_file != xloc.file, 1);
if (ob->current_file != xloc.file)
bp_pack_var_len_unsigned (bp, lto_string_index (ob,
xloc.file,
strlen (xloc.file) + 1,
true));
ob->current_file = xloc.file;
bp_pack_value (bp, ob->current_line != xloc.line, 1);
if (ob->current_line != xloc.line)
bp_pack_var_len_unsigned (bp, xloc.line);
ob->current_line = xloc.line;
bp_pack_value (bp, ob->current_col != xloc.column, 1);
if (ob->current_col != xloc.column)
bp_pack_var_len_unsigned (bp, xloc.column);
ob->current_col = xloc.column;
}
/* Emit location LOC to output block OB.
When bitpack is handy, it is more space effecient to call
lto_output_location_bitpack with existing bitpack. */
static void
lto_output_location (struct output_block *ob, location_t loc)
{
struct bitpack_d bp = bitpack_create (ob->main_stream);
lto_output_location_bitpack (&bp, ob, loc);
lto_output_bitpack (&bp);
}
/* Return true if tree node T is written to various tables. For these
nodes, we sometimes want to write their phyiscal representation
(via lto_output_tree), and sometimes we need to emit an index
reference into a table (via lto_output_tree_ref). */
static bool
tree_is_indexable (tree t)
{
if (TREE_CODE (t) == PARM_DECL)
return false;
else if (TREE_CODE (t) == VAR_DECL && decl_function_context (t)
&& !TREE_STATIC (t))
return false;
else
return (TYPE_P (t) || DECL_P (t) || TREE_CODE (t) == SSA_NAME);
}
/* If EXPR is an indexable tree node, output a reference to it to
output block OB. Otherwise, output the physical representation of
EXPR to OB. */
static void
lto_output_tree_ref (struct output_block *ob, tree expr)
{
enum tree_code code;
if (expr == NULL_TREE)
{
output_record_start (ob, LTO_null);
return;
}
if (!tree_is_indexable (expr))
{
/* Even though we are emitting the physical representation of
EXPR, its leaves must be emitted as references. */
lto_output_tree (ob, expr, true);
return;
}
if (TYPE_P (expr))
{
output_type_ref (ob, expr);
return;
}
code = TREE_CODE (expr);
switch (code)
{
case SSA_NAME:
output_record_start (ob, LTO_ssa_name_ref);
output_uleb128 (ob, SSA_NAME_VERSION (expr));
break;
case FIELD_DECL:
output_record_start (ob, LTO_field_decl_ref);
lto_output_field_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case FUNCTION_DECL:
output_record_start (ob, LTO_function_decl_ref);
lto_output_fn_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case VAR_DECL:
case DEBUG_EXPR_DECL:
gcc_assert (decl_function_context (expr) == NULL
|| TREE_STATIC (expr));
output_record_start (ob, LTO_global_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case CONST_DECL:
output_record_start (ob, LTO_const_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case IMPORTED_DECL:
gcc_assert (decl_function_context (expr) == NULL);
output_record_start (ob, LTO_imported_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case TYPE_DECL:
output_record_start (ob, LTO_type_decl_ref);
lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case NAMESPACE_DECL:
output_record_start (ob, LTO_namespace_decl_ref);
lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case LABEL_DECL:
output_record_start (ob, LTO_label_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case RESULT_DECL:
output_record_start (ob, LTO_result_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case TRANSLATION_UNIT_DECL:
output_record_start (ob, LTO_translation_unit_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
default:
{
/* See if the streamer allows this node to be indexable
like other global declarations. */
if (streamer_hooks.indexable_with_decls_p
&& streamer_hooks.indexable_with_decls_p (expr))
{
output_record_start (ob, LTO_global_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
}
else
{
/* No other node is indexable, so it should have been
handled by lto_output_tree. */
gcc_unreachable ();
}
}
}
}
/* If REF_P is true, emit a reference to EXPR in output block OB,
otherwise emit the physical representation of EXPR in OB. */
static inline void
lto_output_tree_or_ref (struct output_block *ob, tree expr, bool ref_p)
{
if (ref_p)
lto_output_tree_ref (ob, expr);
else
lto_output_tree (ob, expr, false);
}
/* Emit the chain of tree nodes starting at T. OB is the output block
to write to. REF_P is true if chain elements should be emitted
as references. */
static void
lto_output_chain (struct output_block *ob, tree t, bool ref_p)
{
int i, count;
count = list_length (t);
output_sleb128 (ob, count);
for (i = 0; i < count; i++)
{
tree saved_chain;
/* Clear TREE_CHAIN to avoid blindly recursing into the rest
of the list. */
saved_chain = TREE_CHAIN (t);
TREE_CHAIN (t) = NULL_TREE;
lto_output_tree_or_ref (ob, t, ref_p);
TREE_CHAIN (t) = saved_chain;
t = TREE_CHAIN (t);
}
}
/* Write all pointer fields in the TS_COMMON structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_common_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
if (TREE_CODE (expr) != IDENTIFIER_NODE)
lto_output_tree_or_ref (ob, TREE_TYPE (expr), ref_p);
}
/* Write all pointer fields in the TS_VECTOR structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_vector_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_chain (ob, TREE_VECTOR_CST_ELTS (expr), ref_p);
}
/* Write all pointer fields in the TS_COMPLEX structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_complex_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, TREE_REALPART (expr), ref_p);
lto_output_tree_or_ref (ob, TREE_IMAGPART (expr), ref_p);
}
/* Write all pointer fields in the TS_DECL_MINIMAL structure of EXPR
to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_decl_minimal_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, DECL_NAME (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_CONTEXT (expr), ref_p);
lto_output_location (ob, DECL_SOURCE_LOCATION (expr));
}
/* Write all pointer fields in the TS_DECL_COMMON structure of EXPR to
output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_decl_common_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, DECL_SIZE (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_SIZE_UNIT (expr), ref_p);
/* Note, DECL_INITIAL is not handled here. Since DECL_INITIAL needs
special handling in LTO, it must be handled by streamer hooks. */
lto_output_tree_or_ref (ob, DECL_ATTRIBUTES (expr), ref_p);
/* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
if (TREE_CODE (expr) == PARM_DECL)
lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
if ((TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
lto_output_tree_or_ref (ob, DECL_VALUE_EXPR (expr), ref_p);
if (TREE_CODE (expr) == VAR_DECL)
lto_output_tree_or_ref (ob, DECL_DEBUG_EXPR (expr), ref_p);
}
/* Write all pointer fields in the TS_DECL_NON_COMMON structure of
EXPR to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_decl_non_common_tree_pointers (struct output_block *ob,
tree expr, bool ref_p)
{
if (TREE_CODE (expr) == FUNCTION_DECL)
{
lto_output_tree_or_ref (ob, DECL_ARGUMENTS (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_RESULT (expr), ref_p);
}
lto_output_tree_or_ref (ob, DECL_VINDEX (expr), ref_p);
}
/* Write all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_decl_with_vis_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
/* Make sure we don't inadvertently set the assembler name. */
if (DECL_ASSEMBLER_NAME_SET_P (expr))
lto_output_tree_or_ref (ob, DECL_ASSEMBLER_NAME (expr), ref_p);
else
output_record_start (ob, LTO_null);
lto_output_tree_or_ref (ob, DECL_SECTION_NAME (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_COMDAT_GROUP (expr), ref_p);
}
/* Write all pointer fields in the TS_FIELD_DECL structure of EXPR to
output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_field_decl_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, DECL_FIELD_OFFSET (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_BIT_FIELD_TYPE (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_QUALIFIER (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_FIELD_BIT_OFFSET (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_FCONTEXT (expr), ref_p);
lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
}
/* Write all pointer fields in the TS_FUNCTION_DECL structure of EXPR
to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_function_decl_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
/* DECL_STRUCT_FUNCTION is handled by lto_output_function. FIXME lto,
maybe it should be handled here? */
lto_output_tree_or_ref (ob, DECL_FUNCTION_PERSONALITY (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_TARGET (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr),
ref_p);
}
/* Write all pointer fields in the TS_TYPE_COMMON structure of EXPR to
output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_type_common_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, TYPE_SIZE (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_SIZE_UNIT (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_ATTRIBUTES (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p);
/* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO. They will be
reconstructed during fixup. */
/* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
during fixup. */
lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p);
/* TYPE_CANONICAL is re-computed during type merging, so no need
to stream it here. */
lto_output_tree_or_ref (ob, TYPE_STUB_DECL (expr), ref_p);
}
/* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_type_non_common_tree_pointers (struct output_block *ob,
tree expr, bool ref_p)
{
if (TREE_CODE (expr) == ENUMERAL_TYPE)
lto_output_tree_or_ref (ob, TYPE_VALUES (expr), ref_p);
else if (TREE_CODE (expr) == ARRAY_TYPE)
lto_output_tree_or_ref (ob, TYPE_DOMAIN (expr), ref_p);
else if (RECORD_OR_UNION_TYPE_P (expr))
lto_output_tree_or_ref (ob, TYPE_FIELDS (expr), ref_p);
else if (TREE_CODE (expr) == FUNCTION_TYPE
|| TREE_CODE (expr) == METHOD_TYPE)
lto_output_tree_or_ref (ob, TYPE_ARG_TYPES (expr), ref_p);
if (!POINTER_TYPE_P (expr))
lto_output_tree_or_ref (ob, TYPE_MINVAL (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MAXVAL (expr), ref_p);
if (RECORD_OR_UNION_TYPE_P (expr))
lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
}
/* Write all pointer fields in the TS_LIST structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_list_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, TREE_PURPOSE (expr), ref_p);
lto_output_tree_or_ref (ob, TREE_VALUE (expr), ref_p);
lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
}
/* Write all pointer fields in the TS_VEC structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_vec_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
{
int i;
/* Note that the number of slots for EXPR has already been emitted
in EXPR's header (see lto_output_tree_header). */
for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
lto_output_tree_or_ref (ob, TREE_VEC_ELT (expr, i), ref_p);
}
/* Write all pointer fields in the TS_EXP structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_exp_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
{
int i;
output_sleb128 (ob, TREE_OPERAND_LENGTH (expr));
for (i = 0; i < TREE_OPERAND_LENGTH (expr); i++)
lto_output_tree_or_ref (ob, TREE_OPERAND (expr, i), ref_p);
lto_output_location (ob, EXPR_LOCATION (expr));
lto_output_tree_or_ref (ob, TREE_BLOCK (expr), ref_p);
}
/* Write all pointer fields in the TS_BLOCK structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_block_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
/* Do not stream BLOCK_SOURCE_LOCATION. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
lto_output_chain (ob, BLOCK_VARS (expr), ref_p);
/* Do not stream BLOCK_NONLOCALIZED_VARS. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
lto_output_tree_or_ref (ob, BLOCK_SUPERCONTEXT (expr), ref_p);
/* Do not stream BLOCK_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
lto_output_tree_or_ref (ob, BLOCK_FRAGMENT_ORIGIN (expr), ref_p);
lto_output_tree_or_ref (ob, BLOCK_FRAGMENT_CHAIN (expr), ref_p);
/* Do not output BLOCK_SUBBLOCKS. Instead on streaming-in this
list is re-constructed from BLOCK_SUPERCONTEXT. */
}
/* Write all pointer fields in the TS_BINFO structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_binfo_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
unsigned i;
tree t;
/* Note that the number of BINFO slots has already been emitted in
EXPR's header (see lto_output_tree_header) because this length
is needed to build the empty BINFO node on the reader side. */
FOR_EACH_VEC_ELT (tree, BINFO_BASE_BINFOS (expr), i, t)
lto_output_tree_or_ref (ob, t, ref_p);
output_record_start (ob, LTO_null);
lto_output_tree_or_ref (ob, BINFO_OFFSET (expr), ref_p);
lto_output_tree_or_ref (ob, BINFO_VTABLE (expr), ref_p);
/* BINFO_VIRTUALS is used to drive type based devirtualizatoin. It often links
together large portions of programs making it harder to partition. Becuase
devirtualization is interesting before inlining, only, there is no real
need to ship it into ltrans partition. */
lto_output_tree_or_ref (ob, flag_wpa ? NULL : BINFO_VIRTUALS (expr), ref_p);
lto_output_tree_or_ref (ob, BINFO_VPTR_FIELD (expr), ref_p);
output_uleb128 (ob, VEC_length (tree, BINFO_BASE_ACCESSES (expr)));
FOR_EACH_VEC_ELT (tree, BINFO_BASE_ACCESSES (expr), i, t)
lto_output_tree_or_ref (ob, t, ref_p);
lto_output_tree_or_ref (ob, BINFO_INHERITANCE_CHAIN (expr), ref_p);
lto_output_tree_or_ref (ob, BINFO_SUBVTT_INDEX (expr), ref_p);
lto_output_tree_or_ref (ob, BINFO_VPTR_INDEX (expr), ref_p);
}
/* Write all pointer fields in the TS_CONSTRUCTOR structure of EXPR to
output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_constructor_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
unsigned i;
tree index, value;
output_uleb128 (ob, CONSTRUCTOR_NELTS (expr));
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, index, value)
{
lto_output_tree_or_ref (ob, index, ref_p);
lto_output_tree_or_ref (ob, value, ref_p);
}
}
/* Write a TS_TARGET_OPTION tree in EXPR to OB. */
static void
lto_output_ts_target_option (struct output_block *ob, tree expr)
{
struct cl_target_option *t = TREE_TARGET_OPTION (expr);
struct bitpack_d bp;
unsigned i, len;
/* The cl_target_option is target specific and generated by the options
awk script, so we just recreate a byte-by-byte copy here. */
bp = bitpack_create (ob->main_stream);
len = sizeof (struct cl_target_option);
for (i = 0; i < len; i++)
bp_pack_value (&bp, ((unsigned char *)t)[i], 8);
/* Catch struct size mismatches between reader and writer. */
bp_pack_value (&bp, 0x12345678, 32);
lto_output_bitpack (&bp);
}
/* Write a TS_TRANSLATION_UNIT_DECL tree in EXPR to OB. */
static void
lto_output_ts_translation_unit_decl_tree_pointers (struct output_block *ob,
tree expr)
{
lto_output_string (ob, ob->main_stream,
TRANSLATION_UNIT_LANGUAGE (expr), true);
}
/* Helper for lto_output_tree. Write all pointer fields in EXPR to output
block OB. If REF_P is true, the leaves of EXPR are emitted as
references. */
static void
lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
{
enum tree_code code;
code = TREE_CODE (expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
lto_output_ts_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
lto_output_ts_vector_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
lto_output_ts_complex_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
lto_output_ts_decl_minimal_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
lto_output_ts_decl_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
lto_output_ts_decl_non_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
lto_output_ts_decl_with_vis_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
lto_output_ts_field_decl_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
lto_output_ts_function_decl_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
lto_output_ts_type_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
lto_output_ts_type_non_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_LIST))
lto_output_ts_list_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_VEC))
lto_output_ts_vec_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_EXP))
lto_output_ts_exp_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
lto_output_ts_block_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
lto_output_ts_binfo_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
lto_output_ts_constructor_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
lto_output_ts_target_option (ob, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
lto_output_ts_translation_unit_decl_tree_pointers (ob, expr);
}
/* Emit header information for tree EXPR to output block OB. The header
contains everything needed to instantiate an empty skeleton for
EXPR on the reading side. IX is the index into the streamer cache
where EXPR is stored. REF_P is as in lto_output_tree. */
/* Destroy the output block OB. */
static void
lto_output_tree_header (struct output_block *ob, tree expr)
void
destroy_output_block (struct output_block *ob)
{
enum LTO_tags tag;
enum tree_code code;
enum lto_section_type section_type = ob->section_type;
/* We should not see any tree nodes not handled by the streamer. */
code = TREE_CODE (expr);
if (!streamer_hooks.is_streamable (expr))
internal_error ("tree code %qs is not supported in %s streams",
tree_code_name[code], streamer_hooks.name);
/* The header of a tree node consists of its tag, the size of
the node, and any other information needed to instantiate
EXPR on the reading side (such as the number of slots in
variable sized nodes). */
tag = lto_tree_code_to_tag (code);
output_record_start (ob, tag);
htab_delete (ob->string_hash_table);
/* The following will cause bootstrap miscomparisons. Enable with care. */
#ifdef LTO_STREAMER_DEBUG
/* This is used mainly for debugging purposes. When the reader
and the writer do not agree on a streamed node, the pointer
value for EXPR can be used to track down the differences in
the debugger. */
gcc_assert ((HOST_WIDEST_INT) (intptr_t) expr == (intptr_t) expr);
output_sleb128 (ob, (HOST_WIDEST_INT) (intptr_t) expr);
#endif
free (ob->main_stream);
free (ob->string_stream);
if (section_type == LTO_section_function_body)
free (ob->cfg_stream);
lto_streamer_cache_delete (ob->writer_cache);
obstack_free (&ob->obstack, NULL);
/* The text in strings and identifiers are completely emitted in
the header. */
if (CODE_CONTAINS_STRUCT (code, TS_STRING))
output_string_cst (ob, ob->main_stream, expr);
else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
output_identifier (ob, ob->main_stream, expr);
else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
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);
free (ob);
}
/* Write the code and class of builtin EXPR to output block OB. IX is
the index into the streamer cache where EXPR is stored.*/
/* Look up NODE in the type table and write the index for it to OB. */
static void
lto_output_builtin_tree (struct output_block *ob, tree expr)
output_type_ref (struct output_block *ob, tree node)
{
gcc_assert (lto_stream_as_builtin_p (expr));
output_record_start (ob, LTO_type_ref);
lto_output_type_ref_index (ob->decl_state, ob->main_stream, node);
}
if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD
&& !targetm.builtin_decl)
sorry ("gimple bytecode streams do not support machine specific builtin "
"functions on this target");
output_record_start (ob, LTO_builtin_decl);
lto_output_enum (ob->main_stream, built_in_class, BUILT_IN_LAST,
DECL_BUILT_IN_CLASS (expr));
output_uleb128 (ob, DECL_FUNCTION_CODE (expr));
/* Return true if tree node T is written to various tables. For these
nodes, we sometimes want to write their phyiscal representation
(via lto_output_tree), and sometimes we need to emit an index
reference into a table (via lto_output_tree_ref). */
if (DECL_ASSEMBLER_NAME_SET_P (expr))
{
/* When the assembler name of a builtin gets a user name,
the new name is always prefixed with '*' by
set_builtin_user_assembler_name. So, to prevent the
reader side from adding a second '*', we omit it here. */
const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (expr));
if (strlen (str) > 1 && str[0] == '*')
lto_output_string (ob, ob->main_stream, &str[1], true);
else
lto_output_string (ob, ob->main_stream, NULL, true);
}
static bool
tree_is_indexable (tree t)
{
if (TREE_CODE (t) == PARM_DECL)
return false;
else if (TREE_CODE (t) == VAR_DECL && decl_function_context (t)
&& !TREE_STATIC (t))
return false;
else
lto_output_string (ob, ob->main_stream, NULL, true);
return (TYPE_P (t) || DECL_P (t) || TREE_CODE (t) == SSA_NAME);
}
/* Write a physical representation of tree node EXPR to output block
OB. If REF_P is true, the leaves of EXPR are emitted as references
via lto_output_tree_ref. IX is the index into the streamer cache
where EXPR is stored. */
/* Output info about new location into bitpack BP.
After outputting bitpack, lto_output_location_data has
to be done to output actual data. */
static void
lto_write_tree (struct output_block *ob, tree expr, bool ref_p)
static inline void
lto_output_location_bitpack (struct bitpack_d *bp,
struct output_block *ob,
location_t loc)
{
struct bitpack_d bp;
expanded_location xloc;
/* Write the header, containing everything needed to materialize
EXPR on the reading side. */
lto_output_tree_header (ob, expr);
bp_pack_value (bp, loc == UNKNOWN_LOCATION, 1);
if (loc == UNKNOWN_LOCATION)
return;
/* Pack all the non-pointer fields in EXPR into a bitpack and write
the resulting bitpack. */
bp = bitpack_create (ob->main_stream);
pack_value_fields (&bp, expr);
lto_output_bitpack (&bp);
xloc = expand_location (loc);
/* Write all the pointer fields in EXPR. */
lto_output_tree_pointers (ob, expr, ref_p);
bp_pack_value (bp, ob->current_file != xloc.file, 1);
if (ob->current_file != xloc.file)
bp_pack_var_len_unsigned (bp, lto_string_index (ob,
xloc.file,
strlen (xloc.file) + 1,
true));
ob->current_file = xloc.file;
/* Call back into the streaming module to see if it needs to write
anything that was not written by the common streamer. */
if (streamer_hooks.write_tree)
streamer_hooks.write_tree (ob, expr, ref_p);
bp_pack_value (bp, ob->current_line != xloc.line, 1);
if (ob->current_line != xloc.line)
bp_pack_var_len_unsigned (bp, xloc.line);
ob->current_line = xloc.line;
/* Mark the end of EXPR. */
output_zero (ob);
bp_pack_value (bp, ob->current_col != xloc.column, 1);
if (ob->current_col != xloc.column)
bp_pack_var_len_unsigned (bp, xloc.column);
ob->current_col = xloc.column;
}
/* GIMPLE hook for writing GIMPLE-specific parts of trees. OB, EXPR
and REF_P are as in lto_write_tree. */
/* Emit location LOC to output block OB.
When bitpack is handy, it is more space effecient to call
lto_output_location_bitpack with existing bitpack. */
void
lto_streamer_write_tree (struct output_block *ob, tree expr, bool ref_p)
{
if (DECL_P (expr)
&& TREE_CODE (expr) != FUNCTION_DECL
&& TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
{
/* Handle DECL_INITIAL for symbols. */
tree initial = DECL_INITIAL (expr);
if (TREE_CODE (expr) == VAR_DECL
&& (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
&& initial)
{
lto_varpool_encoder_t varpool_encoder;
struct varpool_node *vnode;
varpool_encoder = ob->decl_state->varpool_node_encoder;
vnode = varpool_get_node (expr);
if (!vnode)
initial = error_mark_node;
else if (!lto_varpool_encoder_encode_initializer_p (varpool_encoder,
vnode))
initial = NULL;
}
lto_output_tree_or_ref (ob, initial, ref_p);
}
}
/* Emit the integer constant CST to output block OB. If REF_P is true,
CST's type will be emitted as a reference. */
static void
lto_output_integer_cst (struct output_block *ob, tree cst, bool ref_p)
lto_output_location (struct output_block *ob, location_t loc)
{
output_record_start (ob, lto_tree_code_to_tag (INTEGER_CST));
lto_output_tree_or_ref (ob, TREE_TYPE (cst), ref_p);
lto_output_1_stream (ob->main_stream, TREE_OVERFLOW_P (cst));
output_uleb128 (ob, TREE_INT_CST_LOW (cst));
output_uleb128 (ob, TREE_INT_CST_HIGH (cst));
struct bitpack_d bp = bitpack_create (ob->main_stream);
lto_output_location_bitpack (&bp, ob, loc);
lto_output_bitpack (&bp);
}
/* Emit the physical representation of tree node EXPR to output block
OB. If REF_P is true, the leaves of EXPR are emitted as references
via lto_output_tree_ref. */
/* If EXPR is an indexable tree node, output a reference to it to
output block OB. Otherwise, output the physical representation of
EXPR to OB. */
void
lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
lto_output_tree_ref (struct output_block *ob, tree expr)
{
unsigned ix;
bool existed_p;
enum tree_code code;
if (expr == NULL_TREE)
{
......@@ -1440,39 +199,99 @@ lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
return;
}
/* INTEGER_CST nodes are special because they need their original type
to be materialized by the reader (to implement TYPE_CACHED_VALUES). */
if (TREE_CODE (expr) == INTEGER_CST)
if (!tree_is_indexable (expr))
{
lto_output_integer_cst (ob, expr, ref_p);
/* Even though we are emitting the physical representation of
EXPR, its leaves must be emitted as references. */
lto_output_tree (ob, expr, true);
return;
}
existed_p = lto_streamer_cache_insert (ob->writer_cache, expr, &ix);
if (existed_p)
if (TYPE_P (expr))
{
/* If a node has already been streamed out, make sure that
we don't write it more than once. Otherwise, the reader
will instantiate two different nodes for the same object. */
output_record_start (ob, LTO_tree_pickle_reference);
output_uleb128 (ob, ix);
lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS,
lto_tree_code_to_tag (TREE_CODE (expr)));
output_type_ref (ob, expr);
return;
}
else if (lto_stream_as_builtin_p (expr))
code = TREE_CODE (expr);
switch (code)
{
case SSA_NAME:
output_record_start (ob, LTO_ssa_name_ref);
output_uleb128 (ob, SSA_NAME_VERSION (expr));
break;
case FIELD_DECL:
output_record_start (ob, LTO_field_decl_ref);
lto_output_field_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case FUNCTION_DECL:
output_record_start (ob, LTO_function_decl_ref);
lto_output_fn_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case VAR_DECL:
case DEBUG_EXPR_DECL:
gcc_assert (decl_function_context (expr) == NULL
|| TREE_STATIC (expr));
output_record_start (ob, LTO_global_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case CONST_DECL:
output_record_start (ob, LTO_const_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case IMPORTED_DECL:
gcc_assert (decl_function_context (expr) == NULL);
output_record_start (ob, LTO_imported_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case TYPE_DECL:
output_record_start (ob, LTO_type_decl_ref);
lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case NAMESPACE_DECL:
output_record_start (ob, LTO_namespace_decl_ref);
lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case LABEL_DECL:
output_record_start (ob, LTO_label_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case RESULT_DECL:
output_record_start (ob, LTO_result_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
case TRANSLATION_UNIT_DECL:
output_record_start (ob, LTO_translation_unit_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
break;
default:
{
/* 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. */
lto_output_builtin_tree (ob, expr);
/* See if the streamer allows this node to be indexable
like other global declarations. */
if (streamer_hooks.indexable_with_decls_p
&& streamer_hooks.indexable_with_decls_p (expr))
{
output_record_start (ob, LTO_global_decl_ref);
lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
}
else
{
/* This is the first time we see EXPR, write its fields
to OB. */
lto_write_tree (ob, expr, ref_p);
/* No other node is indexable, so it should have been
handled by lto_output_tree. */
gcc_unreachable ();
}
}
}
}
......@@ -1722,190 +541,6 @@ output_cfg (struct output_block *ob, struct function *fn)
}
/* Output PHI function PHI to the main stream in OB. */
static void
output_phi (struct output_block *ob, gimple phi)
{
unsigned i, len = gimple_phi_num_args (phi);
output_record_start (ob, lto_gimple_code_to_tag (GIMPLE_PHI));
output_uleb128 (ob, SSA_NAME_VERSION (PHI_RESULT (phi)));
for (i = 0; i < len; i++)
{
lto_output_tree_ref (ob, gimple_phi_arg_def (phi, i));
output_uleb128 (ob, gimple_phi_arg_edge (phi, i)->src->index);
lto_output_location (ob, gimple_phi_arg_location (phi, i));
}
}
/* Emit statement STMT on the main stream of output block OB. */
static void
output_gimple_stmt (struct output_block *ob, gimple stmt)
{
unsigned i;
enum gimple_code code;
enum LTO_tags tag;
struct bitpack_d bp;
/* Emit identifying tag. */
code = gimple_code (stmt);
tag = lto_gimple_code_to_tag (code);
output_record_start (ob, tag);
/* Emit the tuple header. */
bp = bitpack_create (ob->main_stream);
bp_pack_var_len_unsigned (&bp, gimple_num_ops (stmt));
bp_pack_value (&bp, gimple_no_warning_p (stmt), 1);
if (is_gimple_assign (stmt))
bp_pack_value (&bp, gimple_assign_nontemporal_move_p (stmt), 1);
bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1);
bp_pack_var_len_unsigned (&bp, stmt->gsbase.subcode);
lto_output_bitpack (&bp);
/* Emit location information for the statement. */
lto_output_location (ob, gimple_location (stmt));
/* Emit the lexical block holding STMT. */
lto_output_tree (ob, gimple_block (stmt), true);
/* Emit the operands. */
switch (gimple_code (stmt))
{
case GIMPLE_RESX:
output_sleb128 (ob, gimple_resx_region (stmt));
break;
case GIMPLE_EH_MUST_NOT_THROW:
lto_output_tree_ref (ob, gimple_eh_must_not_throw_fndecl (stmt));
break;
case GIMPLE_EH_DISPATCH:
output_sleb128 (ob, gimple_eh_dispatch_region (stmt));
break;
case GIMPLE_ASM:
lto_output_uleb128_stream (ob->main_stream, gimple_asm_ninputs (stmt));
lto_output_uleb128_stream (ob->main_stream, gimple_asm_noutputs (stmt));
lto_output_uleb128_stream (ob->main_stream, gimple_asm_nclobbers (stmt));
lto_output_uleb128_stream (ob->main_stream, gimple_asm_nlabels (stmt));
lto_output_string (ob, ob->main_stream, gimple_asm_string (stmt), true);
/* Fallthru */
case GIMPLE_ASSIGN:
case GIMPLE_CALL:
case GIMPLE_RETURN:
case GIMPLE_SWITCH:
case GIMPLE_LABEL:
case GIMPLE_COND:
case GIMPLE_GOTO:
case GIMPLE_DEBUG:
for (i = 0; i < gimple_num_ops (stmt); i++)
{
tree op = gimple_op (stmt, i);
/* Wrap all uses of non-automatic variables inside MEM_REFs
so that we do not have to deal with type mismatches on
merged symbols during IL read in. The first operand
of GIMPLE_DEBUG must be a decl, not MEM_REF, though. */
if (op && (i || !is_gimple_debug (stmt)))
{
tree *basep = &op;
while (handled_component_p (*basep))
basep = &TREE_OPERAND (*basep, 0);
if (TREE_CODE (*basep) == VAR_DECL
&& !auto_var_in_fn_p (*basep, current_function_decl)
&& !DECL_REGISTER (*basep))
{
bool volatilep = TREE_THIS_VOLATILE (*basep);
*basep = build2 (MEM_REF, TREE_TYPE (*basep),
build_fold_addr_expr (*basep),
build_int_cst (build_pointer_type
(TREE_TYPE (*basep)), 0));
TREE_THIS_VOLATILE (*basep) = volatilep;
}
}
lto_output_tree_ref (ob, op);
}
if (is_gimple_call (stmt))
{
if (gimple_call_internal_p (stmt))
lto_output_enum (ob->main_stream, internal_fn,
IFN_LAST, gimple_call_internal_fn (stmt));
else
lto_output_tree_ref (ob, gimple_call_fntype (stmt));
}
break;
case GIMPLE_NOP:
case GIMPLE_PREDICT:
break;
default:
gcc_unreachable ();
}
}
/* Output a basic block BB to the main stream in OB for this FN. */
static void
output_bb (struct output_block *ob, basic_block bb, struct function *fn)
{
gimple_stmt_iterator bsi = gsi_start_bb (bb);
output_record_start (ob,
(!gsi_end_p (bsi)) || phi_nodes (bb)
? LTO_bb1
: LTO_bb0);
output_uleb128 (ob, bb->index);
output_sleb128 (ob, bb->count);
output_sleb128 (ob, bb->loop_depth);
output_sleb128 (ob, bb->frequency);
output_sleb128 (ob, bb->flags);
if (!gsi_end_p (bsi) || phi_nodes (bb))
{
/* Output the statements. The list of statements is terminated
with a zero. */
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
int region;
gimple stmt = gsi_stmt (bsi);
output_gimple_stmt (ob, stmt);
/* Emit the EH region holding STMT. */
region = lookup_stmt_eh_lp_fn (fn, stmt);
if (region != 0)
{
output_record_start (ob, LTO_eh_region);
output_sleb128 (ob, region);
}
else
output_record_start (ob, LTO_null);
}
output_record_start (ob, LTO_null);
for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
gimple phi = gsi_stmt (bsi);
/* Only emit PHIs for gimple registers. PHI nodes for .MEM
will be filled in on reading when the SSA form is
updated. */
if (is_gimple_reg (gimple_phi_result (phi)))
output_phi (ob, phi);
}
output_record_start (ob, LTO_null);
}
}
/* Create the header in the file using OB. If the section type is for
a function, set FN to the decl for that function. */
......
......@@ -32,14 +32,13 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "bitmap.h"
#include "vec.h"
#include "tree-streamer.h"
#include "lto-streamer.h"
#include "streamer-hooks.h"
/* Statistics gathered during LTO, WPA and LTRANS. */
struct lto_stats_d lto_stats;
/* Streamer hooks. */
struct streamer_hooks streamer_hooks;
/* LTO uses bitmaps with different life-times. So use a seperate
obstack for all LTO bitmaps. */
static bitmap_obstack lto_obstack;
......@@ -258,226 +257,6 @@ print_lto_report (void)
}
/* Check that all the TS_* structures handled by the lto_output_* and
lto_input_* routines are exactly ALL the structures defined in
treestruct.def. */
static void
check_handled_ts_structures (void)
{
bool handled_p[LAST_TS_ENUM];
unsigned i;
memset (&handled_p, 0, sizeof (handled_p));
/* These are the TS_* structures that are either handled or
explicitly ignored by the streamer routines. */
handled_p[TS_BASE] = true;
handled_p[TS_TYPED] = true;
handled_p[TS_COMMON] = true;
handled_p[TS_INT_CST] = true;
handled_p[TS_REAL_CST] = true;
handled_p[TS_FIXED_CST] = true;
handled_p[TS_VECTOR] = true;
handled_p[TS_STRING] = true;
handled_p[TS_COMPLEX] = true;
handled_p[TS_IDENTIFIER] = true;
handled_p[TS_DECL_MINIMAL] = true;
handled_p[TS_DECL_COMMON] = true;
handled_p[TS_DECL_WRTL] = true;
handled_p[TS_DECL_NON_COMMON] = true;
handled_p[TS_DECL_WITH_VIS] = true;
handled_p[TS_FIELD_DECL] = true;
handled_p[TS_VAR_DECL] = true;
handled_p[TS_PARM_DECL] = true;
handled_p[TS_LABEL_DECL] = true;
handled_p[TS_RESULT_DECL] = true;
handled_p[TS_CONST_DECL] = true;
handled_p[TS_TYPE_DECL] = true;
handled_p[TS_FUNCTION_DECL] = true;
handled_p[TS_TYPE_COMMON] = true;
handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
handled_p[TS_TYPE_NON_COMMON] = true;
handled_p[TS_LIST] = true;
handled_p[TS_VEC] = true;
handled_p[TS_EXP] = true;
handled_p[TS_SSA_NAME] = true;
handled_p[TS_BLOCK] = true;
handled_p[TS_BINFO] = true;
handled_p[TS_STATEMENT_LIST] = true;
handled_p[TS_CONSTRUCTOR] = true;
handled_p[TS_OMP_CLAUSE] = true;
handled_p[TS_OPTIMIZATION] = true;
handled_p[TS_TARGET_OPTION] = true;
handled_p[TS_TRANSLATION_UNIT_DECL] = true;
/* Anything not marked above will trigger the following assertion.
If this assertion triggers, it means that there is a new TS_*
structure that should be handled by the streamer. */
for (i = 0; i < LAST_TS_ENUM; i++)
gcc_assert (handled_p[i]);
}
/* Helper for lto_streamer_cache_insert_1. Add T to CACHE->NODES at
slot IX. */
static void
lto_streamer_cache_add_to_node_array (struct lto_streamer_cache_d *cache,
unsigned ix, tree t)
{
/* Make sure we're either replacing an old element or
appending consecutively. */
gcc_assert (ix <= VEC_length (tree, cache->nodes));
if (ix == VEC_length (tree, cache->nodes))
VEC_safe_push (tree, heap, cache->nodes, t);
else
VEC_replace (tree, cache->nodes, ix, t);
}
/* Helper for lto_streamer_cache_insert and lto_streamer_cache_insert_at.
CACHE, T, and IX_P are as in lto_streamer_cache_insert.
If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
slot in the cache. Otherwise, T is inserted at the position indicated
in *IX_P.
If T already existed in CACHE, return true. Otherwise,
return false. */
static bool
lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache,
tree t, unsigned *ix_p,
bool insert_at_next_slot_p)
{
void **slot;
unsigned ix;
bool existed_p;
gcc_assert (t);
slot = pointer_map_insert (cache->node_map, t);
if (!*slot)
{
/* Determine the next slot to use in the cache. */
if (insert_at_next_slot_p)
ix = VEC_length (tree, cache->nodes);
else
ix = *ix_p;
*slot = (void *)(size_t) (ix + 1);
lto_streamer_cache_add_to_node_array (cache, ix, t);
/* Indicate that the item was not present in the cache. */
existed_p = false;
}
else
{
ix = (size_t) *slot - 1;
if (!insert_at_next_slot_p && ix != *ix_p)
{
/* If the caller wants to insert T at a specific slot
location, and ENTRY->TO does not match *IX_P, add T to
the requested location slot. */
ix = *ix_p;
lto_streamer_cache_add_to_node_array (cache, ix, t);
}
/* Indicate that T was already in the cache. */
existed_p = true;
}
if (ix_p)
*ix_p = ix;
return existed_p;
}
/* Insert tree node T in CACHE. If T already existed in the cache
return true. Otherwise, return false.
If IX_P is non-null, update it with the index into the cache where
T has been stored. */
bool
lto_streamer_cache_insert (struct lto_streamer_cache_d *cache, tree t,
unsigned *ix_p)
{
return lto_streamer_cache_insert_1 (cache, t, ix_p, true);
}
/* Insert tree node T in CACHE at slot IX. If T already
existed in the cache return true. Otherwise, return false. */
bool
lto_streamer_cache_insert_at (struct lto_streamer_cache_d *cache,
tree t, unsigned ix)
{
return lto_streamer_cache_insert_1 (cache, t, &ix, false);
}
/* Appends tree node T to CACHE, even if T already existed in it. */
void
lto_streamer_cache_append (struct lto_streamer_cache_d *cache, tree t)
{
unsigned ix = VEC_length (tree, cache->nodes);
lto_streamer_cache_insert_1 (cache, t, &ix, false);
}
/* Return true if tree node T exists in CACHE, otherwise false. If IX_P is
not NULL, write to *IX_P the index into the cache where T is stored
((unsigned)-1 if T is not found). */
bool
lto_streamer_cache_lookup (struct lto_streamer_cache_d *cache, tree t,
unsigned *ix_p)
{
void **slot;
bool retval;
unsigned ix;
gcc_assert (t);
slot = pointer_map_contains (cache->node_map, t);
if (slot == NULL)
{
retval = false;
ix = -1;
}
else
{
retval = true;
ix = (size_t) *slot - 1;
}
if (ix_p)
*ix_p = ix;
return retval;
}
/* Return the tree node at slot IX in CACHE. */
tree
lto_streamer_cache_get (struct lto_streamer_cache_d *cache, unsigned ix)
{
gcc_assert (cache);
/* Make sure we're not requesting something we don't have. */
gcc_assert (ix < VEC_length (tree, cache->nodes));
return VEC_index (tree, cache->nodes, ix);
}
/* Record NODE in CACHE. */
static void
......@@ -557,39 +336,6 @@ lto_preload_common_nodes (struct lto_streamer_cache_d *cache)
lto_record_common_node (cache, global_trees[i]);
}
/* Create a cache of pickled nodes. */
struct lto_streamer_cache_d *
lto_streamer_cache_create (void)
{
struct lto_streamer_cache_d *cache;
cache = XCNEW (struct lto_streamer_cache_d);
cache->node_map = pointer_map_create ();
/* Load all the well-known tree nodes that are always created by
the compiler on startup. This prevents writing them out
unnecessarily. */
streamer_hooks.preload_common_nodes (cache);
return cache;
}
/* Delete the streamer cache C. */
void
lto_streamer_cache_delete (struct lto_streamer_cache_d *c)
{
if (c == NULL)
return;
pointer_map_destroy (c->node_map);
VEC_free (tree, heap, c->nodes);
free (c);
}
#ifdef LTO_STREAMER_DEBUG
static htab_t tree_htab;
......@@ -756,12 +502,3 @@ lto_streamer_hooks_init (void)
streamer_hooks.write_tree = lto_streamer_write_tree;
streamer_hooks.read_tree = lto_streamer_read_tree;
}
/* Initialize the current set of streamer hooks. */
void
streamer_hooks_init (void)
{
memset (&streamer_hooks, 0, sizeof (streamer_hooks));
}
......@@ -32,12 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "vecprim.h"
#include "alloc-pool.h"
#include "gcov-io.h"
/* Forward declarations to avoid including unnecessary headers. */
struct output_block;
struct lto_input_block;
struct data_in;
struct bitpack_d;
#include "diagnostic.h"
/* Define when debugging the LTO streamer. This causes the writer
to output the numeric value for the memory address of the tree node
......@@ -152,27 +147,6 @@ struct bitpack_d;
typedef unsigned char lto_decl_flags_t;
/* Data structures used to pack values and bitflags into a vector of
words. Used to stream values of a fixed number of bits in a space
efficient way. */
static unsigned const BITS_PER_BITPACK_WORD = HOST_BITS_PER_WIDE_INT;
typedef unsigned HOST_WIDE_INT bitpack_word_t;
DEF_VEC_I(bitpack_word_t);
DEF_VEC_ALLOC_I(bitpack_word_t, heap);
struct bitpack_d
{
/* The position of the first unused or unconsumed bit in the word. */
unsigned pos;
/* The current word we are (un)packing. */
bitpack_word_t word;
/* The lto_output_stream or the lto_input_block we are streaming to/from. */
void *stream;
};
/* Tags representing the various IL objects written to the bytecode file
(GIMPLE statements, basic blocks, EH regions, tree nodes, etc).
......@@ -332,33 +306,6 @@ typedef void (lto_free_section_data_f) (struct lto_file_decl_data *,
const char *,
size_t);
/* Cache of pickled nodes. Used to avoid writing the same node more
than once. The first time a tree node is streamed out, it is
entered in this cache. Subsequent references to the same node are
resolved by looking it up in this cache.
This is used in two ways:
- On the writing side, the first time T is added to STREAMER_CACHE,
a new reference index is created for T and T is emitted on the
stream. If T needs to be emitted again to the stream, instead of
pickling it again, the reference index is emitted.
- On the reading side, the first time T is read from the stream, it
is reconstructed in memory and a new reference index created for
T. The reconstructed T is inserted in some array so that when
the reference index for T is found in the input stream, it can be
used to look up into the array to get the reconstructed T. */
struct lto_streamer_cache_d
{
/* The mapping between tree nodes and slots into the nodes array. */
struct pointer_map_t *node_map;
/* The nodes pickled so far. */
VEC(tree,heap) *nodes;
};
/* Structure used as buffer for reading an LTO file. */
struct lto_input_block
{
......@@ -747,86 +694,6 @@ struct data_in
};
/* Streamer hooks. These functions do additional processing as
needed by the module. There are two types of callbacks, those that
replace the default behavior and those that supplement it.
Hooks marked [REQ] are required to be set. Those marked [OPT] may
be NULL, if the streamer does not need to implement them. */
struct streamer_hooks {
/* [REQ] A string identifying this streamer. */
const char *name;
/* [REQ] Called by lto_streamer_cache_create to instantiate a cache of
well-known nodes. These are tree nodes that are always
instantiated by the compiler on startup. Additionally, these
nodes need to be shared. This function should call
lto_streamer_cache_append on every tree node that it wishes to
preload in the streamer cache. This way, the writer will only
write out a reference to the tree and the reader will instantiate
the tree out of this pre-populated cache. */
void (*preload_common_nodes) (struct lto_streamer_cache_d *);
/* [REQ] Return true if the given tree is supported by this streamer. */
bool (*is_streamable) (tree);
/* [OPT] Called by lto_write_tree after writing all the common parts of
a tree. If defined, the callback is in charge of writing all
the fields that lto_write_tree did not write out. Arguments
are as in lto_write_tree.
The following tree fields are not handled by common code:
DECL_ABSTRACT_ORIGIN
DECL_INITIAL
DECL_SAVED_TREE
Callbacks may choose to ignore or handle them. If handled,
the reader should read them in the exact same sequence written
by the writer. */
void (*write_tree) (struct output_block *, tree, bool);
/* [OPT] Called by lto_read_tree after reading all the common parts of
a tree. If defined, the callback is in charge of reading all
the fields that lto_read_tree did not read in. Arguments
are as in lto_read_tree. */
void (*read_tree) (struct lto_input_block *, struct data_in *, tree);
/* [OPT] Called by lto_output_tree_ref to determine if the given tree node
should be emitted as a reference to the table of declarations
(the same table that holds global declarations). */
bool (*indexable_with_decls_p) (tree);
/* [OPT] Called by pack_value_fields to store any non-pointer fields
in the tree structure. The arguments are as in pack_value_fields. */
void (*pack_value_fields) (struct bitpack_d *, tree);
/* [OPT] 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);
/* [OPT] 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 *);
/* [OPT] 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);
};
/* Streamer hooks. */
extern struct streamer_hooks streamer_hooks;
/* In lto-section-in.c */
extern struct lto_input_block * lto_create_simple_input_block (
struct lto_file_decl_data *,
......@@ -864,10 +731,6 @@ extern void lto_section_overrun (struct lto_input_block *) ATTRIBUTE_NORETURN;
extern void lto_value_range_error (const char *,
HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT) ATTRIBUTE_NORETURN;
extern void bp_pack_var_len_unsigned (struct bitpack_d *, unsigned HOST_WIDE_INT);
extern void bp_pack_var_len_int (struct bitpack_d *, HOST_WIDE_INT);
extern unsigned HOST_WIDE_INT bp_unpack_var_len_unsigned (struct bitpack_d *);
extern HOST_WIDE_INT bp_unpack_var_len_int (struct bitpack_d *);
/* In lto-section-out.c */
extern hashval_t lto_hash_decl_slot_node (const void *);
......@@ -919,16 +782,6 @@ extern bitmap lto_bitmap_alloc (void);
extern void lto_bitmap_free (bitmap);
extern char *lto_get_section_name (int, const char *, struct lto_file_decl_data *);
extern void print_lto_report (void);
extern bool lto_streamer_cache_insert (struct lto_streamer_cache_d *, tree,
unsigned *);
extern bool lto_streamer_cache_insert_at (struct lto_streamer_cache_d *, tree,
unsigned);
extern void lto_streamer_cache_append (struct lto_streamer_cache_d *, tree);
extern bool lto_streamer_cache_lookup (struct lto_streamer_cache_d *, tree,
unsigned *);
extern tree lto_streamer_cache_get (struct lto_streamer_cache_d *, unsigned);
extern struct lto_streamer_cache_d *lto_streamer_cache_create (void);
extern void lto_streamer_cache_delete (struct lto_streamer_cache_d *);
extern void lto_streamer_init (void);
extern bool gate_lto_out (void);
#ifdef LTO_STREAMER_DEBUG
......@@ -938,15 +791,10 @@ extern void lto_orig_address_remove (tree);
#endif
extern void lto_check_version (int, int);
extern void lto_streamer_hooks_init (void);
extern void lto_streamer_write_tree (struct output_block *, tree, bool);
extern void lto_streamer_read_tree (struct lto_input_block *,
struct data_in *, tree);
extern void streamer_hooks_init (void);
/* In lto-streamer-in.c */
extern void lto_input_cgraph (struct lto_file_decl_data *, const char *);
extern void lto_reader_init (void);
extern tree lto_input_tree (struct lto_input_block *, struct data_in *);
extern void lto_input_function_body (struct lto_file_decl_data *, tree,
const char *);
extern void lto_input_constructors_and_inits (struct lto_file_decl_data *,
......@@ -955,9 +803,12 @@ extern struct data_in *lto_data_in_create (struct lto_file_decl_data *,
const char *, unsigned,
VEC(ld_plugin_symbol_resolution_t,heap) *);
extern void lto_data_in_delete (struct data_in *);
extern const char *lto_input_string (struct data_in *,
struct lto_input_block *);
extern void lto_input_data_block (struct lto_input_block *, void *, size_t);
location_t lto_input_location (struct lto_input_block *, struct data_in *);
tree lto_input_tree_ref (struct lto_input_block *, struct data_in *,
struct function *, enum LTO_tags);
void lto_tag_check_set (enum LTO_tags, int, ...);
void lto_init_eh (void);
/* In lto-streamer-out.c */
......@@ -971,6 +822,8 @@ void lto_output_decl_state_streams (struct output_block *,
void lto_output_decl_state_refs (struct output_block *,
struct lto_output_stream *,
struct lto_out_decl_state *);
void lto_output_tree_ref (struct output_block *, tree);
void lto_output_location (struct output_block *, location_t);
/* In lto-cgraph.c */
......@@ -1096,6 +949,28 @@ lto_tag_to_tree_code (enum LTO_tags tag)
return (enum tree_code) ((unsigned) tag - 1);
}
/* Check that tag ACTUAL == EXPECTED. */
static inline void
lto_tag_check (enum LTO_tags actual, enum LTO_tags expected)
{
if (actual != expected)
internal_error ("bytecode stream: expected tag %s instead of %s",
lto_tag_name (expected), lto_tag_name (actual));
}
/* Check that tag ACTUAL is in the range [TAG1, TAG2]. */
static inline void
lto_tag_check_range (enum LTO_tags actual, enum LTO_tags tag1,
enum LTO_tags tag2)
{
if (actual < tag1 || actual > tag2)
internal_error ("bytecode stream: tag %s is not in the expected range "
"[%s, %s]",
lto_tag_name (actual),
lto_tag_name (tag1),
lto_tag_name (tag2));
}
/* Initialize an lto_out_decl_buffer ENCODER. */
static inline void
lto_init_tree_ref_encoder (struct lto_tree_ref_encoder *encoder,
......@@ -1160,232 +1035,4 @@ DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, type_decl)
DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl)
DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl)
/* Returns a new bit-packing context for bit-packing into S. */
static inline struct bitpack_d
bitpack_create (struct lto_output_stream *s)
{
struct bitpack_d bp;
bp.pos = 0;
bp.word = 0;
bp.stream = (void *)s;
return bp;
}
/* Pack the NBITS bit sized value VAL into the bit-packing context BP. */
static inline void
bp_pack_value (struct bitpack_d *bp, bitpack_word_t val, unsigned nbits)
{
bitpack_word_t word = bp->word;
int pos = bp->pos;
/* Verify that VAL fits in the NBITS. */
gcc_checking_assert (nbits == BITS_PER_BITPACK_WORD
|| !(val & ~(((bitpack_word_t)1<<nbits)-1)));
/* If val does not fit into the current bitpack word switch to the
next one. */
if (pos + nbits > BITS_PER_BITPACK_WORD)
{
lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream, word);
word = val;
pos = nbits;
}
else
{
word |= val << pos;
pos += nbits;
}
bp->word = word;
bp->pos = pos;
}
/* Finishes bit-packing of BP. */
static inline void
lto_output_bitpack (struct bitpack_d *bp)
{
lto_output_uleb128_stream ((struct lto_output_stream *) bp->stream,
bp->word);
bp->word = 0;
bp->pos = 0;
}
/* Returns a new bit-packing context for bit-unpacking from IB. */
static inline struct bitpack_d
lto_input_bitpack (struct lto_input_block *ib)
{
struct bitpack_d bp;
bp.word = lto_input_uleb128 (ib);
bp.pos = 0;
bp.stream = (void *)ib;
return bp;
}
/* Unpacks NBITS bits from the bit-packing context BP and returns them. */
static inline bitpack_word_t
bp_unpack_value (struct bitpack_d *bp, unsigned nbits)
{
bitpack_word_t mask, val;
int pos = bp->pos;
mask = (nbits == BITS_PER_BITPACK_WORD
? (bitpack_word_t) -1
: ((bitpack_word_t) 1 << nbits) - 1);
/* If there are not continuous nbits in the current bitpack word
switch to the next one. */
if (pos + nbits > BITS_PER_BITPACK_WORD)
{
bp->word = val = lto_input_uleb128 ((struct lto_input_block *)bp->stream);
bp->pos = nbits;
return val & mask;
}
val = bp->word;
val >>= pos;
bp->pos = pos + nbits;
return val & mask;
}
/* Write a character to the output block. */
static inline void
lto_output_1_stream (struct lto_output_stream *obs, char c)
{
/* No space left. */
if (obs->left_in_block == 0)
lto_append_block (obs);
/* Write the actual character. */
*obs->current_pointer = c;
obs->current_pointer++;
obs->total_size++;
obs->left_in_block--;
}
/* Read byte from the input block. */
static inline unsigned char
lto_input_1_unsigned (struct lto_input_block *ib)
{
if (ib->p >= ib->len)
lto_section_overrun (ib);
return (ib->data[ib->p++]);
}
/* Output VAL into OBS and verify it is in range MIN...MAX that is supposed
to be compile time constant.
Be host independent, limit range to 31bits. */
static inline void
lto_output_int_in_range (struct lto_output_stream *obs,
HOST_WIDE_INT min,
HOST_WIDE_INT max,
HOST_WIDE_INT val)
{
HOST_WIDE_INT range = max - min;
gcc_checking_assert (val >= min && val <= max && range > 0
&& range < 0x7fffffff);
val -= min;
lto_output_1_stream (obs, val & 255);
if (range >= 0xff)
lto_output_1_stream (obs, (val >> 8) & 255);
if (range >= 0xffff)
lto_output_1_stream (obs, (val >> 16) & 255);
if (range >= 0xffffff)
lto_output_1_stream (obs, (val >> 24) & 255);
}
/* Input VAL into OBS and verify it is in range MIN...MAX that is supposed
to be compile time constant. PURPOSE is used for error reporting. */
static inline HOST_WIDE_INT
lto_input_int_in_range (struct lto_input_block *ib,
const char *purpose,
HOST_WIDE_INT min,
HOST_WIDE_INT max)
{
HOST_WIDE_INT range = max - min;
HOST_WIDE_INT val = lto_input_1_unsigned (ib);
gcc_checking_assert (range > 0 && range < 0x7fffffff);
if (range >= 0xff)
val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 8;
if (range >= 0xffff)
val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 16;
if (range >= 0xffffff)
val |= ((HOST_WIDE_INT)lto_input_1_unsigned (ib)) << 24;
val += min;
if (val < min || val > max)
lto_value_range_error (purpose, val, min, max);
return val;
}
/* Output VAL into BP and verify it is in range MIN...MAX that is supposed
to be compile time constant.
Be host independent, limit range to 31bits. */
static inline void
bp_pack_int_in_range (struct bitpack_d *bp,
HOST_WIDE_INT min,
HOST_WIDE_INT max,
HOST_WIDE_INT val)
{
HOST_WIDE_INT range = max - min;
int nbits = floor_log2 (range) + 1;
gcc_checking_assert (val >= min && val <= max && range > 0
&& range < 0x7fffffff);
val -= min;
bp_pack_value (bp, val, nbits);
}
/* Input VAL into BP and verify it is in range MIN...MAX that is supposed
to be compile time constant. PURPOSE is used for error reporting. */
static inline HOST_WIDE_INT
bp_unpack_int_in_range (struct bitpack_d *bp,
const char *purpose,
HOST_WIDE_INT min,
HOST_WIDE_INT max)
{
HOST_WIDE_INT range = max - min;
int nbits = floor_log2 (range) + 1;
HOST_WIDE_INT val = bp_unpack_value (bp, nbits);
gcc_checking_assert (range > 0 && range < 0x7fffffff);
if (val < min || val > max)
lto_value_range_error (purpose, val, min, max);
return val;
}
/* Output VAL of type "enum enum_name" into OBS.
Assume range 0...ENUM_LAST - 1. */
#define lto_output_enum(obs,enum_name,enum_last,val) \
lto_output_int_in_range ((obs), 0, (int)(enum_last) - 1, (int)(val))
/* Input enum of type "enum enum_name" from IB.
Assume range 0...ENUM_LAST - 1. */
#define lto_input_enum(ib,enum_name,enum_last) \
(enum enum_name)lto_input_int_in_range ((ib), #enum_name, 0, \
(int)(enum_last) - 1)
/* Output VAL of type "enum enum_name" into BP.
Assume range 0...ENUM_LAST - 1. */
#define bp_pack_enum(bp,enum_name,enum_last,val) \
bp_pack_int_in_range ((bp), 0, (int)(enum_last) - 1, (int)(val))
/* Input enum of type "enum enum_name" from BP.
Assume range 0...ENUM_LAST - 1. */
#define bp_unpack_enum(bp,enum_name,enum_last) \
(enum enum_name)bp_unpack_int_in_range ((bp), #enum_name, 0, \
(int)(enum_last) - 1)
#endif /* GCC_LTO_STREAMER_H */
2011-08-08 Diego Novillo <dnovillo@google.com>
* Make-lang.in (lto/lto.o): Add TREE_STREAMER_H.
* lto.c: Include tree-streamer.h.
2011-07-06 Richard Guenther <rguenther@suse.de>
* lto-lang.c (lto_init):
......
......@@ -86,7 +86,7 @@ lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
langhooks.h $(VEC_H) $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \
$(COMMON_H) debug.h $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \
$(LTO_TAGS_H) $(LTO_STREAMER_H) $(SPLAY_TREE_H) gt-lto-lto.h $(PARAMS_H) \
ipa-inline.h $(IPA_UTILS_H)
ipa-inline.h $(IPA_UTILS_H) $(TREE_STREAMER_H)
lto/lto-object.o: lto/lto-object.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(DIAGNOSTIC_CORE_H) $(LTO_H) $(TM_H) $(LTO_STREAMER_H) \
../include/simple-object.h
......
......@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "lto.h"
#include "lto-tree.h"
#include "lto-streamer.h"
#include "tree-streamer.h"
#include "splay-tree.h"
#include "params.h"
#include "ipa-inline.h"
......
/* Streamer hooks. Support for adding streamer-specific callbacks to
generic streaming routines.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "streamer-hooks.h"
/* Streamer hooks. */
struct streamer_hooks streamer_hooks;
/* Initialize the current set of streamer hooks. */
void
streamer_hooks_init (void)
{
memset (&streamer_hooks, 0, sizeof (streamer_hooks));
}
/* Streamer hooks. Support for adding streamer-specific callbacks to
generic streaming routines.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#ifndef GCC_STREAMER_HOOKS_H
#define GCC_STREAMER_HOOKS_H
#include "tree.h"
/* Forward declarations to avoid including unnecessary headers. */
struct output_block;
struct lto_input_block;
struct data_in;
struct bitpack_d;
struct lto_streamer_cache_d;
/* Streamer hooks. These functions do additional processing as
needed by the module. There are two types of callbacks, those that
replace the default behavior and those that supplement it.
Hooks marked [REQ] are required to be set. Those marked [OPT] may
be NULL, if the streamer does not need to implement them. */
struct streamer_hooks {
/* [REQ] A string identifying this streamer. */
const char *name;
/* [REQ] Called by lto_streamer_cache_create to instantiate a cache of
well-known nodes. These are tree nodes that are always
instantiated by the compiler on startup. Additionally, these
nodes need to be shared. This function should call
lto_streamer_cache_append on every tree node that it wishes to
preload in the streamer cache. This way, the writer will only
write out a reference to the tree and the reader will instantiate
the tree out of this pre-populated cache. */
void (*preload_common_nodes) (struct lto_streamer_cache_d *);
/* [REQ] Return true if the given tree is supported by this streamer. */
bool (*is_streamable) (tree);
/* [OPT] Called by lto_write_tree after writing all the common parts of
a tree. If defined, the callback is in charge of writing all
the fields that lto_write_tree did not write out. Arguments
are as in lto_write_tree.
The following tree fields are not handled by common code:
DECL_ABSTRACT_ORIGIN
DECL_INITIAL
DECL_SAVED_TREE
Callbacks may choose to ignore or handle them. If handled,
the reader should read them in the exact same sequence written
by the writer. */
void (*write_tree) (struct output_block *, tree, bool);
/* [OPT] Called by lto_read_tree after reading all the common parts of
a tree. If defined, the callback is in charge of reading all
the fields that lto_read_tree did not read in. Arguments
are as in lto_read_tree. */
void (*read_tree) (struct lto_input_block *, struct data_in *, tree);
/* [OPT] Called by lto_output_tree_ref to determine if the given tree node
should be emitted as a reference to the table of declarations
(the same table that holds global declarations). */
bool (*indexable_with_decls_p) (tree);
/* [OPT] Called by pack_value_fields to store any non-pointer fields
in the tree structure. The arguments are as in pack_value_fields. */
void (*pack_value_fields) (struct bitpack_d *, tree);
/* [OPT] 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);
/* [OPT] 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 *);
/* [OPT] 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);
};
/* Streamer hooks. */
extern struct streamer_hooks streamer_hooks;
/* In streamer-hooks.c. */
void streamer_hooks_init (void);
#endif /* GCC_STREAMER_HOOKS_H */
/* Routines for reading trees from a file stream.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
#include "tree.h"
#include "tree-flow.h"
#include "tree-streamer.h"
#include "data-streamer.h"
#include "streamer-hooks.h"
#include "lto-streamer.h"
/* Read a STRING_CST from the string table in DATA_IN using input
block IB. */
tree
input_string_cst (struct data_in *data_in, struct lto_input_block *ib)
{
unsigned int len;
const char * ptr;
ptr = input_string_internal (data_in, ib, &len);
if (!ptr)
return NULL;
return build_string (len, ptr);
}
/* Read an IDENTIFIER from the string table in DATA_IN using input
block IB. */
static tree
input_identifier (struct data_in *data_in, struct lto_input_block *ib)
{
unsigned int len;
const char *ptr;
ptr = input_string_internal (data_in, ib, &len);
if (!ptr)
return NULL;
return get_identifier_with_length (ptr, len);
}
/* Read a chain of tree nodes from input block IB. DATA_IN contains
tables and descriptors for the file being read. */
static tree
lto_input_chain (struct lto_input_block *ib, struct data_in *data_in)
{
int i, count;
tree first, prev, curr;
first = prev = NULL_TREE;
count = lto_input_sleb128 (ib);
for (i = 0; i < count; i++)
{
curr = lto_input_tree (ib, data_in);
if (prev)
TREE_CHAIN (prev) = curr;
else
first = curr;
TREE_CHAIN (curr) = NULL_TREE;
prev = curr;
}
return first;
}
/* Unpack all the non-pointer fields of the TS_BASE structure of
expression EXPR from bitpack BP. */
static void
unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
{
/* Note that the code for EXPR has already been unpacked to create EXPR in
lto_materialize_tree. */
if (!TYPE_P (expr))
{
TREE_SIDE_EFFECTS (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_CONSTANT (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
/* TREE_PUBLIC is used on types to indicate that the type
has a TYPE_CACHED_VALUES vector. This is not streamed out,
so we skip it here. */
TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1);
}
else
bp_unpack_value (bp, 4);
TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1);
if (DECL_P (expr))
DECL_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
else if (TYPE_P (expr))
TYPE_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1);
else
bp_unpack_value (bp, 1);
TREE_ASM_WRITTEN (expr) = (unsigned) bp_unpack_value (bp, 1);
if (TYPE_P (expr))
TYPE_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
else
TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_USED (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_NOTHROW (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_STATIC (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_PRIVATE (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_PROTECTED (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_DEPRECATED (expr) = (unsigned) bp_unpack_value (bp, 1);
if (TYPE_P (expr))
TYPE_SATURATING (expr) = (unsigned) bp_unpack_value (bp, 1);
else if (TREE_CODE (expr) == SSA_NAME)
SSA_NAME_IS_DEFAULT_DEF (expr) = (unsigned) bp_unpack_value (bp, 1);
else
bp_unpack_value (bp, 1);
}
/* Unpack all the non-pointer fields of the TS_REAL_CST structure of
expression EXPR from bitpack BP. */
static void
unpack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
{
unsigned i;
REAL_VALUE_TYPE r;
REAL_VALUE_TYPE *rp;
r.cl = (unsigned) bp_unpack_value (bp, 2);
r.decimal = (unsigned) bp_unpack_value (bp, 1);
r.sign = (unsigned) bp_unpack_value (bp, 1);
r.signalling = (unsigned) bp_unpack_value (bp, 1);
r.canonical = (unsigned) bp_unpack_value (bp, 1);
r.uexp = (unsigned) bp_unpack_value (bp, EXP_BITS);
for (i = 0; i < SIGSZ; i++)
r.sig[i] = (unsigned long) bp_unpack_value (bp, HOST_BITS_PER_LONG);
rp = ggc_alloc_real_value ();
memcpy (rp, &r, sizeof (REAL_VALUE_TYPE));
TREE_REAL_CST_PTR (expr) = rp;
}
/* Unpack all the non-pointer fields of the TS_FIXED_CST structure of
expression EXPR from bitpack BP. */
static void
unpack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
{
struct fixed_value fv;
fv.mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
fv.data.low = bp_unpack_var_len_int (bp);
fv.data.high = bp_unpack_var_len_int (bp);
TREE_FIXED_CST (expr) = fv;
}
/* Unpack all the non-pointer fields of the TS_DECL_COMMON structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
{
DECL_MODE (expr) = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
DECL_NONLOCAL (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_VIRTUAL_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IGNORED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_PRESERVE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_DEBUG_EXPR_IS_FROM (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_EXTERNAL (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_GIMPLE_REG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_ALIGN (expr) = (unsigned) bp_unpack_var_len_unsigned (bp);
if (TREE_CODE (expr) == LABEL_DECL)
{
DECL_ERROR_ISSUED (expr) = (unsigned) bp_unpack_value (bp, 1);
EH_LANDING_PAD_NR (expr) = (int) bp_unpack_var_len_unsigned (bp);
/* Always assume an initial value of -1 for LABEL_DECL_UID to
force gimple_set_bb to recreate label_to_block_map. */
LABEL_DECL_UID (expr) = -1;
}
if (TREE_CODE (expr) == FIELD_DECL)
{
DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
expr->decl_common.off_align = bp_unpack_value (bp, 8);
}
if (TREE_CODE (expr) == RESULT_DECL
|| TREE_CODE (expr) == PARM_DECL
|| TREE_CODE (expr) == VAR_DECL)
{
DECL_BY_REFERENCE (expr) = (unsigned) bp_unpack_value (bp, 1);
if (TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
DECL_HAS_VALUE_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_RESTRICTED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
}
}
/* Unpack all the non-pointer fields of the TS_DECL_WRTL structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
{
DECL_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
}
/* Unpack all the non-pointer fields of the TS_DECL_WITH_VIS structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
{
DECL_DEFER_OUTPUT (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp, 2);
DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp, 1);
if (TREE_CODE (expr) == VAR_DECL)
{
DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp, 3);
}
if (VAR_OR_FUNCTION_DECL_P (expr))
{
priority_type p;
p = (priority_type) bp_unpack_var_len_unsigned (bp);
SET_DECL_INIT_PRIORITY (expr, p);
}
}
/* Unpack all the non-pointer fields of the TS_FUNCTION_DECL structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
{
DECL_BUILT_IN_CLASS (expr) = bp_unpack_enum (bp, built_in_class,
BUILT_IN_LAST);
DECL_STATIC_CONSTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_STATIC_DESTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_UNINLINABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_POSSIBLY_INLINED (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IS_NOVOPS (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IS_RETURNS_TWICE (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IS_MALLOC (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_IS_OPERATOR_NEW (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_DECLARED_INLINE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_STATIC_CHAIN (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr)
= (unsigned) bp_unpack_value (bp, 1);
DECL_NO_LIMIT_STACK (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_DISREGARD_INLINE_LIMITS (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
DECL_LOOPING_CONST_OR_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
{
DECL_FUNCTION_CODE (expr) = (enum built_in_function) bp_unpack_value (bp,
11);
if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (expr) >= END_BUILTINS)
fatal_error ("machine independent builtin code out of range");
else if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD)
{
tree result = targetm.builtin_decl (DECL_FUNCTION_CODE (expr), true);
if (!result || result == error_mark_node)
fatal_error ("target specific builtin not available");
}
}
if (DECL_STATIC_DESTRUCTOR (expr))
{
priority_type p;
p = (priority_type) bp_unpack_var_len_unsigned (bp);
SET_DECL_FINI_PRIORITY (expr, p);
}
}
/* Unpack all the non-pointer fields of the TS_TYPE_COMMON structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
{
enum machine_mode mode;
mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
SET_TYPE_MODE (expr, mode);
TYPE_STRING_FLAG (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_NO_FORCE_BLK (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_NEEDS_CONSTRUCTING (expr) = (unsigned) bp_unpack_value (bp, 1);
if (RECORD_OR_UNION_TYPE_P (expr))
TYPE_TRANSPARENT_AGGR (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_RESTRICT (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)
= (unsigned) bp_unpack_value (bp, 2);
TYPE_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
TYPE_PRECISION (expr) = bp_unpack_var_len_unsigned (bp);
TYPE_ALIGN (expr) = bp_unpack_var_len_unsigned (bp);
TYPE_ALIAS_SET (expr) = bp_unpack_var_len_int (bp);
}
/* Unpack all the non-pointer fields of the TS_BLOCK structure
of expression EXPR from bitpack BP. */
static void
unpack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
{
BLOCK_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1);
/* BLOCK_NUMBER is recomputed. */
}
/* Unpack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL
structure of expression EXPR from bitpack BP. */
static void
unpack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
{
}
/* Unpack all the non-pointer fields in EXPR into a bit pack. */
static void
unpack_value_fields (struct bitpack_d *bp, tree expr)
{
enum tree_code code;
code = TREE_CODE (expr);
/* Note that all these functions are highly sensitive to changes in
the types and sizes of each of the fields being packed. */
unpack_ts_base_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
unpack_ts_real_cst_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
unpack_ts_fixed_cst_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
unpack_ts_decl_common_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
unpack_ts_decl_wrtl_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
unpack_ts_decl_with_vis_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
unpack_ts_function_decl_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
unpack_ts_type_common_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
unpack_ts_block_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
unpack_ts_translation_unit_decl_value_fields (bp, expr);
if (streamer_hooks.unpack_value_fields)
streamer_hooks.unpack_value_fields (bp, expr);
}
/* Materialize a new tree from input block IB using descriptors in
DATA_IN. The code for the new tree should match TAG. Store in
*IX_P the index into the reader cache where the new tree is stored. */
static tree
lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in,
enum LTO_tags tag)
{
struct bitpack_d bp;
enum tree_code code;
tree result;
#ifdef LTO_STREAMER_DEBUG
HOST_WIDEST_INT orig_address_in_writer;
#endif
result = NULL_TREE;
#ifdef LTO_STREAMER_DEBUG
/* Read the word representing the memory address for the tree
as it was written by the writer. This is useful when
debugging differences between the writer and reader. */
orig_address_in_writer = lto_input_sleb128 (ib);
gcc_assert ((intptr_t) orig_address_in_writer == orig_address_in_writer);
#endif
code = lto_tag_to_tree_code (tag);
/* We should never see an SSA_NAME tree. Only the version numbers of
SSA names are ever written out. See input_ssa_names. */
gcc_assert (code != SSA_NAME);
/* Instantiate a new tree using the header data. */
if (CODE_CONTAINS_STRUCT (code, TS_STRING))
result = input_string_cst (data_in, ib);
else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
result = input_identifier (data_in, ib);
else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
{
HOST_WIDE_INT len = lto_input_sleb128 (ib);
result = make_tree_vec (len);
}
else if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
{
unsigned HOST_WIDE_INT len = lto_input_uleb128 (ib);
result = make_tree_binfo (len);
}
else
{
/* 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
/* Store the original address of the tree as seen by the writer
in RESULT's aux field. This is useful when debugging streaming
problems. This way, a debugging session can be started on
both writer and reader with a breakpoint using this address
value in both. */
lto_orig_address_map (result, (intptr_t) orig_address_in_writer);
#endif
/* Read the bitpack of non-pointer values from IB. */
bp = lto_input_bitpack (ib);
/* The first word in BP contains the code of the tree that we
are about to read. */
code = (enum tree_code) bp_unpack_value (&bp, 16);
lto_tag_check (lto_tree_code_to_tag (code), tag);
/* Unpack all the value fields from BP. */
unpack_value_fields (&bp, result);
/* Enter RESULT in the reader cache. This will make RESULT
available so that circular references in the rest of the tree
structure can be resolved in subsequent calls to lto_input_tree. */
lto_streamer_cache_append (data_in->reader_cache, result);
return result;
}
/* Read all pointer fields in the TS_COMMON structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_common_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
if (TREE_CODE (expr) != IDENTIFIER_NODE)
TREE_TYPE (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_VECTOR structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_vector_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
TREE_VECTOR_CST_ELTS (expr) = lto_input_chain (ib, data_in);
}
/* Read all pointer fields in the TS_COMPLEX structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_complex_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
TREE_REALPART (expr) = lto_input_tree (ib, data_in);
TREE_IMAGPART (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_DECL_MINIMAL structure of EXPR
from input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_decl_minimal_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
DECL_NAME (expr) = lto_input_tree (ib, data_in);
DECL_CONTEXT (expr) = lto_input_tree (ib, data_in);
DECL_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in);
}
/* Read all pointer fields in the TS_DECL_COMMON structure of EXPR from
input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_decl_common_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
DECL_SIZE (expr) = lto_input_tree (ib, data_in);
DECL_SIZE_UNIT (expr) = lto_input_tree (ib, data_in);
DECL_ATTRIBUTES (expr) = lto_input_tree (ib, data_in);
/* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
if (TREE_CODE (expr) == PARM_DECL)
TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
if ((TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
SET_DECL_VALUE_EXPR (expr, lto_input_tree (ib, data_in));
if (TREE_CODE (expr) == VAR_DECL)
{
tree dexpr = lto_input_tree (ib, data_in);
if (dexpr)
SET_DECL_DEBUG_EXPR (expr, dexpr);
}
}
/* Read all pointer fields in the TS_DECL_NON_COMMON structure of
EXPR from input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_decl_non_common_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
if (TREE_CODE (expr) == FUNCTION_DECL)
{
DECL_ARGUMENTS (expr) = lto_input_tree (ib, data_in);
DECL_RESULT (expr) = lto_input_tree (ib, data_in);
}
DECL_VINDEX (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
from input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_decl_with_vis_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
tree id;
id = lto_input_tree (ib, data_in);
if (id)
{
gcc_assert (TREE_CODE (id) == IDENTIFIER_NODE);
SET_DECL_ASSEMBLER_NAME (expr, id);
}
DECL_SECTION_NAME (expr) = lto_input_tree (ib, data_in);
DECL_COMDAT_GROUP (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_FIELD_DECL structure of EXPR from
input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_field_decl_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
DECL_FIELD_OFFSET (expr) = lto_input_tree (ib, data_in);
DECL_BIT_FIELD_TYPE (expr) = lto_input_tree (ib, data_in);
DECL_QUALIFIER (expr) = lto_input_tree (ib, data_in);
DECL_FIELD_BIT_OFFSET (expr) = lto_input_tree (ib, data_in);
DECL_FCONTEXT (expr) = lto_input_tree (ib, data_in);
TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
}
/* Read all pointer fields in the TS_FUNCTION_DECL structure of EXPR
from input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_function_decl_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
/* DECL_STRUCT_FUNCTION is handled by lto_input_function. FIXME lto,
maybe it should be handled here? */
DECL_FUNCTION_PERSONALITY (expr) = lto_input_tree (ib, data_in);
DECL_FUNCTION_SPECIFIC_TARGET (expr) = lto_input_tree (ib, data_in);
DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr) = lto_input_tree (ib, data_in);
/* If the file contains a function with an EH personality set,
then it was compiled with -fexceptions. In that case, initialize
the backend EH machinery. */
if (DECL_FUNCTION_PERSONALITY (expr))
lto_init_eh ();
}
/* Read all pointer fields in the TS_TYPE_COMMON structure of EXPR from
input block IB. DATA_IN contains tables and descriptors for the file
being read. */
static void
lto_input_ts_type_common_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
TYPE_SIZE (expr) = lto_input_tree (ib, data_in);
TYPE_SIZE_UNIT (expr) = lto_input_tree (ib, data_in);
TYPE_ATTRIBUTES (expr) = lto_input_tree (ib, data_in);
TYPE_NAME (expr) = lto_input_tree (ib, data_in);
/* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO. They will be
reconstructed during fixup. */
/* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
during fixup. */
TYPE_MAIN_VARIANT (expr) = lto_input_tree (ib, data_in);
TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
/* TYPE_CANONICAL gets re-computed during type merging. */
TYPE_CANONICAL (expr) = NULL_TREE;
TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
from input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_type_non_common_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in,
tree expr)
{
if (TREE_CODE (expr) == ENUMERAL_TYPE)
TYPE_VALUES (expr) = lto_input_tree (ib, data_in);
else if (TREE_CODE (expr) == ARRAY_TYPE)
TYPE_DOMAIN (expr) = lto_input_tree (ib, data_in);
else if (RECORD_OR_UNION_TYPE_P (expr))
TYPE_FIELDS (expr) = lto_input_tree (ib, data_in);
else if (TREE_CODE (expr) == FUNCTION_TYPE
|| TREE_CODE (expr) == METHOD_TYPE)
TYPE_ARG_TYPES (expr) = lto_input_tree (ib, data_in);
if (!POINTER_TYPE_P (expr))
TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
if (RECORD_OR_UNION_TYPE_P (expr))
TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_LIST structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_list_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
TREE_PURPOSE (expr) = lto_input_tree (ib, data_in);
TREE_VALUE (expr) = lto_input_tree (ib, data_in);
TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
}
/* Read all pointer fields in the TS_VEC structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_vec_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
int i;
/* Note that TREE_VEC_LENGTH was read by lto_materialize_tree to
instantiate EXPR. */
for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
TREE_VEC_ELT (expr, i) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_EXP structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_exp_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
int i, length;
location_t loc;
length = lto_input_sleb128 (ib);
gcc_assert (length == TREE_OPERAND_LENGTH (expr));
for (i = 0; i < length; i++)
TREE_OPERAND (expr, i) = lto_input_tree (ib, data_in);
loc = lto_input_location (ib, data_in);
SET_EXPR_LOCATION (expr, loc);
TREE_BLOCK (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_BLOCK structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_block_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
/* Do not stream BLOCK_SOURCE_LOCATION. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
BLOCK_VARS (expr) = lto_input_chain (ib, data_in);
/* Do not stream BLOCK_NONLOCALIZED_VARS. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
BLOCK_SUPERCONTEXT (expr) = lto_input_tree (ib, data_in);
/* Do not stream BLOCK_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
BLOCK_FRAGMENT_ORIGIN (expr) = lto_input_tree (ib, data_in);
BLOCK_FRAGMENT_CHAIN (expr) = lto_input_tree (ib, data_in);
/* We re-compute BLOCK_SUBBLOCKS of our parent here instead
of streaming it. For non-BLOCK BLOCK_SUPERCONTEXTs we still
stream the child relationship explicitly. */
if (BLOCK_SUPERCONTEXT (expr)
&& TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == BLOCK)
{
BLOCK_CHAIN (expr) = BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr));
BLOCK_SUBBLOCKS (BLOCK_SUPERCONTEXT (expr)) = expr;
}
/* The global block is rooted at the TU decl. Hook it here to
avoid the need to stream in this block during WPA time. */
else if (BLOCK_SUPERCONTEXT (expr)
&& TREE_CODE (BLOCK_SUPERCONTEXT (expr)) == TRANSLATION_UNIT_DECL)
DECL_INITIAL (BLOCK_SUPERCONTEXT (expr)) = expr;
/* The function-level block is connected at the time we read in
function bodies for the same reason. */
}
/* Read all pointer fields in the TS_BINFO structure of EXPR from input
block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
unsigned i, len;
tree t;
/* Note that the number of slots in EXPR was read in
lto_materialize_tree when instantiating EXPR. However, the
vector is empty so we cannot rely on VEC_length to know how many
elements to read. So, this list is emitted as a 0-terminated
list on the writer side. */
do
{
t = lto_input_tree (ib, data_in);
if (t)
VEC_quick_push (tree, BINFO_BASE_BINFOS (expr), t);
}
while (t);
BINFO_OFFSET (expr) = lto_input_tree (ib, data_in);
BINFO_VTABLE (expr) = lto_input_tree (ib, data_in);
BINFO_VIRTUALS (expr) = lto_input_tree (ib, data_in);
BINFO_VPTR_FIELD (expr) = lto_input_tree (ib, data_in);
len = lto_input_uleb128 (ib);
if (len > 0)
{
VEC_reserve_exact (tree, gc, BINFO_BASE_ACCESSES (expr), len);
for (i = 0; i < len; i++)
{
tree a = lto_input_tree (ib, data_in);
VEC_quick_push (tree, BINFO_BASE_ACCESSES (expr), a);
}
}
BINFO_INHERITANCE_CHAIN (expr) = lto_input_tree (ib, data_in);
BINFO_SUBVTT_INDEX (expr) = lto_input_tree (ib, data_in);
BINFO_VPTR_INDEX (expr) = lto_input_tree (ib, data_in);
}
/* Read all pointer fields in the TS_CONSTRUCTOR structure of EXPR from
input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_ts_constructor_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in, tree expr)
{
unsigned i, len;
len = lto_input_uleb128 (ib);
for (i = 0; i < len; i++)
{
tree index, value;
index = lto_input_tree (ib, data_in);
value = lto_input_tree (ib, data_in);
CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (expr), index, value);
}
}
/* Input a TS_TARGET_OPTION tree from IB into EXPR. */
static void
lto_input_ts_target_option (struct lto_input_block *ib, tree expr)
{
unsigned i, len;
struct bitpack_d bp;
struct cl_target_option *t = TREE_TARGET_OPTION (expr);
bp = lto_input_bitpack (ib);
len = sizeof (struct cl_target_option);
for (i = 0; i < len; i++)
((unsigned char *)t)[i] = bp_unpack_value (&bp, 8);
if (bp_unpack_value (&bp, 32) != 0x12345678)
fatal_error ("cl_target_option size mismatch in LTO reader and writer");
}
/* Input a TS_TRANSLATION_UNIT_DECL tree from IB and DATA_IN into EXPR. */
static void
lto_input_ts_translation_unit_decl_tree_pointers (struct lto_input_block *ib,
struct data_in *data_in,
tree expr)
{
TRANSLATION_UNIT_LANGUAGE (expr) = xstrdup (lto_input_string (data_in, ib));
VEC_safe_push (tree, gc, all_translation_units, expr);
}
/* Helper for lto_input_tree. Read all pointer fields in EXPR from
input block IB. DATA_IN contains tables and descriptors for the
file being read. */
static void
lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
tree expr)
{
enum tree_code code;
code = TREE_CODE (expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
lto_input_ts_common_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
lto_input_ts_vector_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
lto_input_ts_complex_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
lto_input_ts_decl_minimal_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
lto_input_ts_decl_common_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
lto_input_ts_decl_non_common_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
lto_input_ts_decl_with_vis_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
lto_input_ts_field_decl_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
lto_input_ts_function_decl_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
lto_input_ts_type_common_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
lto_input_ts_type_non_common_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_LIST))
lto_input_ts_list_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_VEC))
lto_input_ts_vec_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_EXP))
lto_input_ts_exp_tree_pointers (ib, data_in, expr);
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_CONSTRUCTOR))
lto_input_ts_constructor_tree_pointers (ib, data_in, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
lto_input_ts_target_option (ib, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
lto_input_ts_translation_unit_decl_tree_pointers (ib, data_in, expr);
}
/* Read the physical representation of a tree node with tag TAG from
input block IB using the per-file context in DATA_IN. */
static tree
lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
enum LTO_tags tag)
{
tree result;
result = lto_materialize_tree (ib, data_in, tag);
/* Read all the pointer fields in RESULT. */
lto_input_tree_pointers (ib, data_in, result);
/* Call back into the streaming module to read anything else it
may need. */
if (streamer_hooks.read_tree)
streamer_hooks.read_tree (ib, data_in, result);
/* We should never try to instantiate an MD or NORMAL builtin here. */
if (TREE_CODE (result) == FUNCTION_DECL)
gcc_assert (!lto_stream_as_builtin_p (result));
/* end_marker = */ lto_input_1_unsigned (ib);
#ifdef LTO_STREAMER_DEBUG
/* Remove the mapping to RESULT's original address set by
lto_materialize_tree. */
lto_orig_address_remove (result);
#endif
return result;
}
/* Read and INTEGER_CST node from input block IB using the per-file
context in DATA_IN. */
static tree
lto_input_integer_cst (struct lto_input_block *ib, struct data_in *data_in)
{
tree result, type;
HOST_WIDE_INT low, high;
bool overflow_p;
type = lto_input_tree (ib, data_in);
overflow_p = (lto_input_1_unsigned (ib) != 0);
low = lto_input_uleb128 (ib);
high = lto_input_uleb128 (ib);
result = build_int_cst_wide (type, low, high);
/* If the original constant had overflown, build a replica of RESULT to
avoid modifying the shared constant returned by build_int_cst_wide. */
if (overflow_p)
{
result = copy_node (result);
TREE_OVERFLOW (result) = 1;
}
return result;
}
/* Read an index IX from input block IB and return the tree node at
DATA_IN->FILE_DATA->GLOBALS_INDEX[IX]. */
static tree
lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in)
{
unsigned HOST_WIDE_INT ix;
tree result;
enum LTO_tags expected_tag;
ix = lto_input_uleb128 (ib);
expected_tag = lto_input_enum (ib, LTO_tags, LTO_NUM_TAGS);
result = lto_streamer_cache_get (data_in->reader_cache, ix);
gcc_assert (result
&& TREE_CODE (result) == lto_tag_to_tree_code (expected_tag));
return result;
}
/* Read a code and class from input block IB and return the
corresponding builtin. DATA_IN is as in lto_input_tree. */
static tree
lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
{
enum built_in_class fclass;
enum built_in_function fcode;
const char *asmname;
tree result;
fclass = lto_input_enum (ib, built_in_class, BUILT_IN_LAST);
gcc_assert (fclass == BUILT_IN_NORMAL || fclass == BUILT_IN_MD);
fcode = (enum built_in_function) lto_input_uleb128 (ib);
if (fclass == BUILT_IN_NORMAL)
{
if (fcode >= END_BUILTINS)
fatal_error ("machine independent builtin code out of range");
result = built_in_decls[fcode];
gcc_assert (result);
}
else if (fclass == BUILT_IN_MD)
{
result = targetm.builtin_decl (fcode, true);
if (!result || result == error_mark_node)
fatal_error ("target specific builtin not available");
}
else
gcc_unreachable ();
asmname = lto_input_string (data_in, ib);
if (asmname)
set_builtin_user_assembler_name (result, asmname);
lto_streamer_cache_append (data_in->reader_cache, result);
return result;
}
/* Read a tree from input block IB using the per-file context in
DATA_IN. This context is used, for example, to resolve references
to previously read nodes. */
tree
lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
{
enum LTO_tags tag;
tree result;
tag = input_record_start (ib);
gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS);
if (tag == LTO_null)
result = NULL_TREE;
else if (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
{
/* If TAG is a reference to an indexable tree, the next value
in IB is the index into the table where we expect to find
that tree. */
result = lto_input_tree_ref (ib, data_in, cfun, tag);
}
else if (tag == LTO_tree_pickle_reference)
{
/* If TAG is a reference to a previously read tree, look it up in
the reader cache. */
result = lto_get_pickled_tree (ib, data_in);
}
else if (tag == LTO_builtin_decl)
{
/* If we are going to read a built-in function, all we need is
the code and class. */
result = lto_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. */
result = lto_input_integer_cst (ib, data_in);
}
else
{
/* Otherwise, materialize a new node from IB. */
result = lto_read_tree (ib, data_in, tag);
}
return result;
}
/* Routines for emitting trees to a file stream.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
#include "tree.h"
#include "tree-streamer.h"
#include "data-streamer.h"
#include "streamer-hooks.h"
/* Output the STRING constant to the string
table in OB. Then put the index onto the INDEX_STREAM. */
static void
output_string_cst (struct output_block *ob,
struct lto_output_stream *index_stream,
tree string)
{
lto_output_string_with_length (ob, index_stream,
TREE_STRING_POINTER (string),
TREE_STRING_LENGTH (string),
true);
}
/* Output the identifier ID to the string
table in OB. Then put the index onto the INDEX_STREAM. */
static void
output_identifier (struct output_block *ob,
struct lto_output_stream *index_stream,
tree id)
{
lto_output_string_with_length (ob, index_stream,
IDENTIFIER_POINTER (id),
IDENTIFIER_LENGTH (id),
true);
}
/* Pack all the non-pointer fields of the TS_BASE structure of
expression EXPR into bitpack BP. */
static void
pack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_value (bp, TREE_CODE (expr), 16);
if (!TYPE_P (expr))
{
bp_pack_value (bp, TREE_SIDE_EFFECTS (expr), 1);
bp_pack_value (bp, TREE_CONSTANT (expr), 1);
bp_pack_value (bp, TREE_READONLY (expr), 1);
/* TREE_PUBLIC is used on types to indicate that the type
has a TYPE_CACHED_VALUES vector. This is not streamed out,
so we skip it here. */
bp_pack_value (bp, TREE_PUBLIC (expr), 1);
}
else
bp_pack_value (bp, 0, 4);
bp_pack_value (bp, TREE_ADDRESSABLE (expr), 1);
bp_pack_value (bp, TREE_THIS_VOLATILE (expr), 1);
if (DECL_P (expr))
bp_pack_value (bp, DECL_UNSIGNED (expr), 1);
else if (TYPE_P (expr))
bp_pack_value (bp, TYPE_UNSIGNED (expr), 1);
else
bp_pack_value (bp, 0, 1);
/* We write debug info two times, do not confuse the second one. */
bp_pack_value (bp, TYPE_P (expr) ? 0 : TREE_ASM_WRITTEN (expr), 1);
if (TYPE_P (expr))
bp_pack_value (bp, TYPE_ARTIFICIAL (expr), 1);
else
bp_pack_value (bp, TREE_NO_WARNING (expr), 1);
bp_pack_value (bp, TREE_USED (expr), 1);
bp_pack_value (bp, TREE_NOTHROW (expr), 1);
bp_pack_value (bp, TREE_STATIC (expr), 1);
bp_pack_value (bp, TREE_PRIVATE (expr), 1);
bp_pack_value (bp, TREE_PROTECTED (expr), 1);
bp_pack_value (bp, TREE_DEPRECATED (expr), 1);
if (TYPE_P (expr))
bp_pack_value (bp, TYPE_SATURATING (expr), 1);
else if (TREE_CODE (expr) == SSA_NAME)
bp_pack_value (bp, SSA_NAME_IS_DEFAULT_DEF (expr), 1);
else
bp_pack_value (bp, 0, 1);
}
/* Pack all the non-pointer fields of the TS_REAL_CST structure of
expression EXPR into bitpack BP. */
static void
pack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr)
{
unsigned i;
REAL_VALUE_TYPE r;
r = TREE_REAL_CST (expr);
bp_pack_value (bp, r.cl, 2);
bp_pack_value (bp, r.decimal, 1);
bp_pack_value (bp, r.sign, 1);
bp_pack_value (bp, r.signalling, 1);
bp_pack_value (bp, r.canonical, 1);
bp_pack_value (bp, r.uexp, EXP_BITS);
for (i = 0; i < SIGSZ; i++)
bp_pack_value (bp, r.sig[i], HOST_BITS_PER_LONG);
}
/* Pack all the non-pointer fields of the TS_FIXED_CST structure of
expression EXPR into bitpack BP. */
static void
pack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
{
struct fixed_value fv = TREE_FIXED_CST (expr);
bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, fv.mode);
bp_pack_var_len_int (bp, fv.data.low);
bp_pack_var_len_int (bp, fv.data.high);
}
/* Pack all the non-pointer fields of the TS_DECL_COMMON structure
of expression EXPR into bitpack BP. */
static void
pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, DECL_MODE (expr));
bp_pack_value (bp, DECL_NONLOCAL (expr), 1);
bp_pack_value (bp, DECL_VIRTUAL_P (expr), 1);
bp_pack_value (bp, DECL_IGNORED_P (expr), 1);
bp_pack_value (bp, DECL_ABSTRACT (expr), 1);
bp_pack_value (bp, DECL_ARTIFICIAL (expr), 1);
bp_pack_value (bp, DECL_USER_ALIGN (expr), 1);
bp_pack_value (bp, DECL_PRESERVE_P (expr), 1);
bp_pack_value (bp, DECL_DEBUG_EXPR_IS_FROM (expr), 1);
bp_pack_value (bp, DECL_EXTERNAL (expr), 1);
bp_pack_value (bp, DECL_GIMPLE_REG_P (expr), 1);
bp_pack_var_len_unsigned (bp, DECL_ALIGN (expr));
if (TREE_CODE (expr) == LABEL_DECL)
{
/* Note that we do not write LABEL_DECL_UID. The reader will
always assume an initial value of -1 so that the
label_to_block_map is recreated by gimple_set_bb. */
bp_pack_value (bp, DECL_ERROR_ISSUED (expr), 1);
bp_pack_var_len_unsigned (bp, EH_LANDING_PAD_NR (expr));
}
if (TREE_CODE (expr) == FIELD_DECL)
{
bp_pack_value (bp, DECL_PACKED (expr), 1);
bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
bp_pack_value (bp, expr->decl_common.off_align, 8);
}
if (TREE_CODE (expr) == RESULT_DECL
|| TREE_CODE (expr) == PARM_DECL
|| TREE_CODE (expr) == VAR_DECL)
{
bp_pack_value (bp, DECL_BY_REFERENCE (expr), 1);
if (TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
bp_pack_value (bp, DECL_HAS_VALUE_EXPR_P (expr), 1);
bp_pack_value (bp, DECL_RESTRICTED_P (expr), 1);
}
}
/* Pack all the non-pointer fields of the TS_DECL_WRTL structure
of expression EXPR into bitpack BP. */
static void
pack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_value (bp, DECL_REGISTER (expr), 1);
}
/* Pack all the non-pointer fields of the TS_DECL_WITH_VIS structure
of expression EXPR into bitpack BP. */
static void
pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_value (bp, DECL_DEFER_OUTPUT (expr), 1);
bp_pack_value (bp, DECL_COMMON (expr), 1);
bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1);
bp_pack_value (bp, DECL_WEAK (expr), 1);
bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr), 1);
bp_pack_value (bp, DECL_COMDAT (expr), 1);
bp_pack_value (bp, DECL_VISIBILITY (expr), 2);
bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr), 1);
if (TREE_CODE (expr) == VAR_DECL)
{
bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1);
bp_pack_value (bp, DECL_IN_TEXT_SECTION (expr), 1);
bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1);
bp_pack_value (bp, DECL_TLS_MODEL (expr), 3);
}
if (VAR_OR_FUNCTION_DECL_P (expr))
bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr));
}
/* Pack all the non-pointer fields of the TS_FUNCTION_DECL structure
of expression EXPR into bitpack BP. */
static void
pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
{
/* For normal/md builtins we only write the class and code, so they
should never be handled here. */
gcc_assert (!lto_stream_as_builtin_p (expr));
bp_pack_enum (bp, built_in_class, BUILT_IN_LAST,
DECL_BUILT_IN_CLASS (expr));
bp_pack_value (bp, DECL_STATIC_CONSTRUCTOR (expr), 1);
bp_pack_value (bp, DECL_STATIC_DESTRUCTOR (expr), 1);
bp_pack_value (bp, DECL_UNINLINABLE (expr), 1);
bp_pack_value (bp, DECL_POSSIBLY_INLINED (expr), 1);
bp_pack_value (bp, DECL_IS_NOVOPS (expr), 1);
bp_pack_value (bp, DECL_IS_RETURNS_TWICE (expr), 1);
bp_pack_value (bp, DECL_IS_MALLOC (expr), 1);
bp_pack_value (bp, DECL_IS_OPERATOR_NEW (expr), 1);
bp_pack_value (bp, DECL_DECLARED_INLINE_P (expr), 1);
bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1);
bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1);
bp_pack_value (bp, DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr), 1);
bp_pack_value (bp, DECL_NO_LIMIT_STACK (expr), 1);
bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1);
bp_pack_value (bp, DECL_PURE_P (expr), 1);
bp_pack_value (bp, DECL_LOOPING_CONST_OR_PURE_P (expr), 1);
if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
bp_pack_value (bp, DECL_FUNCTION_CODE (expr), 11);
if (DECL_STATIC_DESTRUCTOR (expr))
bp_pack_var_len_unsigned (bp, DECL_FINI_PRIORITY (expr));
}
/* Pack all the non-pointer fields of the TS_TYPE_COMMON structure
of expression EXPR into bitpack BP. */
static void
pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, TYPE_MODE (expr));
bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1);
bp_pack_value (bp, TYPE_NO_FORCE_BLK (expr), 1);
bp_pack_value (bp, TYPE_NEEDS_CONSTRUCTING (expr), 1);
if (RECORD_OR_UNION_TYPE_P (expr))
bp_pack_value (bp, TYPE_TRANSPARENT_AGGR (expr), 1);
bp_pack_value (bp, TYPE_PACKED (expr), 1);
bp_pack_value (bp, TYPE_RESTRICT (expr), 1);
bp_pack_value (bp, TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr), 2);
bp_pack_value (bp, TYPE_USER_ALIGN (expr), 1);
bp_pack_value (bp, TYPE_READONLY (expr), 1);
bp_pack_var_len_unsigned (bp, TYPE_PRECISION (expr));
bp_pack_var_len_unsigned (bp, TYPE_ALIGN (expr));
bp_pack_var_len_int (bp, TYPE_ALIAS_SET (expr) == 0 ? 0 : -1);
}
/* Pack all the non-pointer fields of the TS_BLOCK structure
of expression EXPR into bitpack BP. */
static void
pack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_value (bp, BLOCK_ABSTRACT (expr), 1);
/* BLOCK_NUMBER is recomputed. */
}
/* Pack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL structure
of expression EXPR into bitpack BP. */
static void
pack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED)
{
}
/* Pack all the non-pointer fields in EXPR into a bit pack. */
static void
pack_value_fields (struct bitpack_d *bp, tree expr)
{
enum tree_code code;
code = TREE_CODE (expr);
/* Note that all these functions are highly sensitive to changes in
the types and sizes of each of the fields being packed. */
pack_ts_base_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
pack_ts_real_cst_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST))
pack_ts_fixed_cst_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
pack_ts_decl_common_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL))
pack_ts_decl_wrtl_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
pack_ts_decl_with_vis_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
pack_ts_function_decl_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
pack_ts_type_common_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
pack_ts_block_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
pack_ts_translation_unit_decl_value_fields (bp, expr);
if (streamer_hooks.pack_value_fields)
streamer_hooks.pack_value_fields (bp, expr);
}
/* If REF_P is true, emit a reference to EXPR in output block OB,
otherwise emit the physical representation of EXPR in OB. */
static inline void
lto_output_tree_or_ref (struct output_block *ob, tree expr, bool ref_p)
{
if (ref_p)
lto_output_tree_ref (ob, expr);
else
lto_output_tree (ob, expr, false);
}
/* Write the code and class of builtin EXPR to output block OB. IX is
the index into the streamer cache where EXPR is stored.*/
static void
lto_output_builtin_tree (struct output_block *ob, tree expr)
{
gcc_assert (lto_stream_as_builtin_p (expr));
if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD
&& !targetm.builtin_decl)
sorry ("gimple bytecode streams do not support machine specific builtin "
"functions on this target");
output_record_start (ob, LTO_builtin_decl);
lto_output_enum (ob->main_stream, built_in_class, BUILT_IN_LAST,
DECL_BUILT_IN_CLASS (expr));
output_uleb128 (ob, DECL_FUNCTION_CODE (expr));
if (DECL_ASSEMBLER_NAME_SET_P (expr))
{
/* When the assembler name of a builtin gets a user name,
the new name is always prefixed with '*' by
set_builtin_user_assembler_name. So, to prevent the
reader side from adding a second '*', we omit it here. */
const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (expr));
if (strlen (str) > 1 && str[0] == '*')
lto_output_string (ob, ob->main_stream, &str[1], true);
else
lto_output_string (ob, ob->main_stream, NULL, true);
}
else
lto_output_string (ob, ob->main_stream, NULL, true);
}
/* GIMPLE hook for writing GIMPLE-specific parts of trees. OB, EXPR
and REF_P are as in lto_write_tree. */
void
lto_streamer_write_tree (struct output_block *ob, tree expr, bool ref_p)
{
if (DECL_P (expr)
&& TREE_CODE (expr) != FUNCTION_DECL
&& TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
{
/* Handle DECL_INITIAL for symbols. */
tree initial = DECL_INITIAL (expr);
if (TREE_CODE (expr) == VAR_DECL
&& (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
&& initial)
{
lto_varpool_encoder_t varpool_encoder;
struct varpool_node *vnode;
varpool_encoder = ob->decl_state->varpool_node_encoder;
vnode = varpool_get_node (expr);
if (!vnode)
initial = error_mark_node;
else if (!lto_varpool_encoder_encode_initializer_p (varpool_encoder,
vnode))
initial = NULL;
}
lto_output_tree_or_ref (ob, initial, ref_p);
}
}
/* Emit the chain of tree nodes starting at T. OB is the output block
to write to. REF_P is true if chain elements should be emitted
as references. */
static void
lto_output_chain (struct output_block *ob, tree t, bool ref_p)
{
int i, count;
count = list_length (t);
output_sleb128 (ob, count);
for (i = 0; i < count; i++)
{
tree saved_chain;
/* Clear TREE_CHAIN to avoid blindly recursing into the rest
of the list. */
saved_chain = TREE_CHAIN (t);
TREE_CHAIN (t) = NULL_TREE;
lto_output_tree_or_ref (ob, t, ref_p);
TREE_CHAIN (t) = saved_chain;
t = TREE_CHAIN (t);
}
}
/* Write all pointer fields in the TS_COMMON structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_common_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
if (TREE_CODE (expr) != IDENTIFIER_NODE)
lto_output_tree_or_ref (ob, TREE_TYPE (expr), ref_p);
}
/* Write all pointer fields in the TS_VECTOR structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_vector_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_chain (ob, TREE_VECTOR_CST_ELTS (expr), ref_p);
}
/* Write all pointer fields in the TS_COMPLEX structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_complex_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, TREE_REALPART (expr), ref_p);
lto_output_tree_or_ref (ob, TREE_IMAGPART (expr), ref_p);
}
/* Write all pointer fields in the TS_DECL_MINIMAL structure of EXPR
to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_decl_minimal_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, DECL_NAME (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_CONTEXT (expr), ref_p);
lto_output_location (ob, DECL_SOURCE_LOCATION (expr));
}
/* Write all pointer fields in the TS_DECL_COMMON structure of EXPR to
output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_decl_common_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, DECL_SIZE (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_SIZE_UNIT (expr), ref_p);
/* Note, DECL_INITIAL is not handled here. Since DECL_INITIAL needs
special handling in LTO, it must be handled by streamer hooks. */
lto_output_tree_or_ref (ob, DECL_ATTRIBUTES (expr), ref_p);
/* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
if (TREE_CODE (expr) == PARM_DECL)
lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
if ((TREE_CODE (expr) == VAR_DECL
|| TREE_CODE (expr) == PARM_DECL)
&& DECL_HAS_VALUE_EXPR_P (expr))
lto_output_tree_or_ref (ob, DECL_VALUE_EXPR (expr), ref_p);
if (TREE_CODE (expr) == VAR_DECL)
lto_output_tree_or_ref (ob, DECL_DEBUG_EXPR (expr), ref_p);
}
/* Write all pointer fields in the TS_DECL_NON_COMMON structure of
EXPR to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_decl_non_common_tree_pointers (struct output_block *ob,
tree expr, bool ref_p)
{
if (TREE_CODE (expr) == FUNCTION_DECL)
{
lto_output_tree_or_ref (ob, DECL_ARGUMENTS (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_RESULT (expr), ref_p);
}
lto_output_tree_or_ref (ob, DECL_VINDEX (expr), ref_p);
}
/* Write all pointer fields in the TS_DECL_WITH_VIS structure of EXPR
to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_decl_with_vis_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
/* Make sure we don't inadvertently set the assembler name. */
if (DECL_ASSEMBLER_NAME_SET_P (expr))
lto_output_tree_or_ref (ob, DECL_ASSEMBLER_NAME (expr), ref_p);
else
output_record_start (ob, LTO_null);
lto_output_tree_or_ref (ob, DECL_SECTION_NAME (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_COMDAT_GROUP (expr), ref_p);
}
/* Write all pointer fields in the TS_FIELD_DECL structure of EXPR to
output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_field_decl_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, DECL_FIELD_OFFSET (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_BIT_FIELD_TYPE (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_QUALIFIER (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_FIELD_BIT_OFFSET (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_FCONTEXT (expr), ref_p);
lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
}
/* Write all pointer fields in the TS_FUNCTION_DECL structure of EXPR
to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_function_decl_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
/* DECL_STRUCT_FUNCTION is handled by lto_output_function. FIXME lto,
maybe it should be handled here? */
lto_output_tree_or_ref (ob, DECL_FUNCTION_PERSONALITY (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_TARGET (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr),
ref_p);
}
/* Write all pointer fields in the TS_TYPE_COMMON structure of EXPR to
output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_type_common_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, TYPE_SIZE (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_SIZE_UNIT (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_ATTRIBUTES (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p);
/* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO. They will be
reconstructed during fixup. */
/* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
during fixup. */
lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p);
/* TYPE_CANONICAL is re-computed during type merging, so no need
to stream it here. */
lto_output_tree_or_ref (ob, TYPE_STUB_DECL (expr), ref_p);
}
/* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
to output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_type_non_common_tree_pointers (struct output_block *ob,
tree expr, bool ref_p)
{
if (TREE_CODE (expr) == ENUMERAL_TYPE)
lto_output_tree_or_ref (ob, TYPE_VALUES (expr), ref_p);
else if (TREE_CODE (expr) == ARRAY_TYPE)
lto_output_tree_or_ref (ob, TYPE_DOMAIN (expr), ref_p);
else if (RECORD_OR_UNION_TYPE_P (expr))
lto_output_tree_or_ref (ob, TYPE_FIELDS (expr), ref_p);
else if (TREE_CODE (expr) == FUNCTION_TYPE
|| TREE_CODE (expr) == METHOD_TYPE)
lto_output_tree_or_ref (ob, TYPE_ARG_TYPES (expr), ref_p);
if (!POINTER_TYPE_P (expr))
lto_output_tree_or_ref (ob, TYPE_MINVAL (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MAXVAL (expr), ref_p);
if (RECORD_OR_UNION_TYPE_P (expr))
lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
}
/* Write all pointer fields in the TS_LIST structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_list_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
lto_output_tree_or_ref (ob, TREE_PURPOSE (expr), ref_p);
lto_output_tree_or_ref (ob, TREE_VALUE (expr), ref_p);
lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
}
/* Write all pointer fields in the TS_VEC structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_vec_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
{
int i;
/* Note that the number of slots for EXPR has already been emitted
in EXPR's header (see lto_output_tree_header). */
for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
lto_output_tree_or_ref (ob, TREE_VEC_ELT (expr, i), ref_p);
}
/* Write all pointer fields in the TS_EXP structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_exp_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
{
int i;
output_sleb128 (ob, TREE_OPERAND_LENGTH (expr));
for (i = 0; i < TREE_OPERAND_LENGTH (expr); i++)
lto_output_tree_or_ref (ob, TREE_OPERAND (expr, i), ref_p);
lto_output_location (ob, EXPR_LOCATION (expr));
lto_output_tree_or_ref (ob, TREE_BLOCK (expr), ref_p);
}
/* Write all pointer fields in the TS_BLOCK structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_block_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
/* Do not stream BLOCK_SOURCE_LOCATION. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
lto_output_chain (ob, BLOCK_VARS (expr), ref_p);
/* Do not stream BLOCK_NONLOCALIZED_VARS. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
lto_output_tree_or_ref (ob, BLOCK_SUPERCONTEXT (expr), ref_p);
/* Do not stream BLOCK_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
lto_output_tree_or_ref (ob, BLOCK_FRAGMENT_ORIGIN (expr), ref_p);
lto_output_tree_or_ref (ob, BLOCK_FRAGMENT_CHAIN (expr), ref_p);
/* Do not output BLOCK_SUBBLOCKS. Instead on streaming-in this
list is re-constructed from BLOCK_SUPERCONTEXT. */
}
/* Write all pointer fields in the TS_BINFO structure of EXPR to output
block OB. If REF_P is true, write a reference to EXPR's pointer
fields. */
static void
lto_output_ts_binfo_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
unsigned i;
tree t;
/* Note that the number of BINFO slots has already been emitted in
EXPR's header (see lto_output_tree_header) because this length
is needed to build the empty BINFO node on the reader side. */
FOR_EACH_VEC_ELT (tree, BINFO_BASE_BINFOS (expr), i, t)
lto_output_tree_or_ref (ob, t, ref_p);
output_record_start (ob, LTO_null);
lto_output_tree_or_ref (ob, BINFO_OFFSET (expr), ref_p);
lto_output_tree_or_ref (ob, BINFO_VTABLE (expr), ref_p);
/* BINFO_VIRTUALS is used to drive type based devirtualizatoin. It often links
together large portions of programs making it harder to partition. Becuase
devirtualization is interesting before inlining, only, there is no real
need to ship it into ltrans partition. */
lto_output_tree_or_ref (ob, flag_wpa ? NULL : BINFO_VIRTUALS (expr), ref_p);
lto_output_tree_or_ref (ob, BINFO_VPTR_FIELD (expr), ref_p);
output_uleb128 (ob, VEC_length (tree, BINFO_BASE_ACCESSES (expr)));
FOR_EACH_VEC_ELT (tree, BINFO_BASE_ACCESSES (expr), i, t)
lto_output_tree_or_ref (ob, t, ref_p);
lto_output_tree_or_ref (ob, BINFO_INHERITANCE_CHAIN (expr), ref_p);
lto_output_tree_or_ref (ob, BINFO_SUBVTT_INDEX (expr), ref_p);
lto_output_tree_or_ref (ob, BINFO_VPTR_INDEX (expr), ref_p);
}
/* Write all pointer fields in the TS_CONSTRUCTOR structure of EXPR to
output block OB. If REF_P is true, write a reference to EXPR's
pointer fields. */
static void
lto_output_ts_constructor_tree_pointers (struct output_block *ob, tree expr,
bool ref_p)
{
unsigned i;
tree index, value;
output_uleb128 (ob, CONSTRUCTOR_NELTS (expr));
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, index, value)
{
lto_output_tree_or_ref (ob, index, ref_p);
lto_output_tree_or_ref (ob, value, ref_p);
}
}
/* Write a TS_TARGET_OPTION tree in EXPR to OB. */
static void
lto_output_ts_target_option (struct output_block *ob, tree expr)
{
struct cl_target_option *t = TREE_TARGET_OPTION (expr);
struct bitpack_d bp;
unsigned i, len;
/* The cl_target_option is target specific and generated by the options
awk script, so we just recreate a byte-by-byte copy here. */
bp = bitpack_create (ob->main_stream);
len = sizeof (struct cl_target_option);
for (i = 0; i < len; i++)
bp_pack_value (&bp, ((unsigned char *)t)[i], 8);
/* Catch struct size mismatches between reader and writer. */
bp_pack_value (&bp, 0x12345678, 32);
lto_output_bitpack (&bp);
}
/* Write a TS_TRANSLATION_UNIT_DECL tree in EXPR to OB. */
static void
lto_output_ts_translation_unit_decl_tree_pointers (struct output_block *ob,
tree expr)
{
lto_output_string (ob, ob->main_stream,
TRANSLATION_UNIT_LANGUAGE (expr), true);
}
/* Helper for lto_output_tree. Write all pointer fields in EXPR to output
block OB. If REF_P is true, the leaves of EXPR are emitted as
references. */
static void
lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
{
enum tree_code code;
code = TREE_CODE (expr);
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
lto_output_ts_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
lto_output_ts_vector_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX))
lto_output_ts_complex_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL))
lto_output_ts_decl_minimal_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
lto_output_ts_decl_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
lto_output_ts_decl_non_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
lto_output_ts_decl_with_vis_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL))
lto_output_ts_field_decl_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
lto_output_ts_function_decl_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
lto_output_ts_type_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
lto_output_ts_type_non_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_LIST))
lto_output_ts_list_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_VEC))
lto_output_ts_vec_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_EXP))
lto_output_ts_exp_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
lto_output_ts_block_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
lto_output_ts_binfo_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
lto_output_ts_constructor_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
lto_output_ts_target_option (ob, expr);
if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
lto_output_ts_translation_unit_decl_tree_pointers (ob, expr);
}
/* Emit header information for tree EXPR to output block OB. The header
contains everything needed to instantiate an empty skeleton for
EXPR on the reading side. IX is the index into the streamer cache
where EXPR is stored. REF_P is as in lto_output_tree. */
static void
lto_output_tree_header (struct output_block *ob, tree expr)
{
enum LTO_tags tag;
enum tree_code code;
/* We should not see any tree nodes not handled by the streamer. */
code = TREE_CODE (expr);
if (!streamer_hooks.is_streamable (expr))
internal_error ("tree code %qs is not supported in %s streams",
tree_code_name[code], streamer_hooks.name);
/* The header of a tree node consists of its tag, the size of
the node, and any other information needed to instantiate
EXPR on the reading side (such as the number of slots in
variable sized nodes). */
tag = lto_tree_code_to_tag (code);
output_record_start (ob, tag);
/* The following will cause bootstrap miscomparisons. Enable with care. */
#ifdef LTO_STREAMER_DEBUG
/* This is used mainly for debugging purposes. When the reader
and the writer do not agree on a streamed node, the pointer
value for EXPR can be used to track down the differences in
the debugger. */
gcc_assert ((HOST_WIDEST_INT) (intptr_t) expr == (intptr_t) expr);
output_sleb128 (ob, (HOST_WIDEST_INT) (intptr_t) expr);
#endif
/* The text in strings and identifiers are completely emitted in
the header. */
if (CODE_CONTAINS_STRUCT (code, TS_STRING))
output_string_cst (ob, ob->main_stream, expr);
else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
output_identifier (ob, ob->main_stream, expr);
else if (CODE_CONTAINS_STRUCT (code, TS_VEC))
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);
}
/* Emit the integer constant CST to output block OB. If REF_P is true,
CST's type will be emitted as a reference. */
static void
lto_output_integer_cst (struct output_block *ob, tree cst, bool ref_p)
{
output_record_start (ob, lto_tree_code_to_tag (INTEGER_CST));
lto_output_tree_or_ref (ob, TREE_TYPE (cst), ref_p);
lto_output_1_stream (ob->main_stream, TREE_OVERFLOW_P (cst));
output_uleb128 (ob, TREE_INT_CST_LOW (cst));
output_uleb128 (ob, TREE_INT_CST_HIGH (cst));
}
/* Write a physical representation of tree node EXPR to output block
OB. If REF_P is true, the leaves of EXPR are emitted as references
via lto_output_tree_ref. IX is the index into the streamer cache
where EXPR is stored. */
static void
lto_write_tree (struct output_block *ob, tree expr, bool ref_p)
{
struct bitpack_d bp;
/* Write the header, containing everything needed to materialize
EXPR on the reading side. */
lto_output_tree_header (ob, expr);
/* Pack all the non-pointer fields in EXPR into a bitpack and write
the resulting bitpack. */
bp = bitpack_create (ob->main_stream);
pack_value_fields (&bp, expr);
lto_output_bitpack (&bp);
/* Write all the pointer fields in EXPR. */
lto_output_tree_pointers (ob, expr, ref_p);
/* Call back into the streaming module to see if it needs to write
anything that was not written by the common streamer. */
if (streamer_hooks.write_tree)
streamer_hooks.write_tree (ob, expr, ref_p);
/* Mark the end of EXPR. */
output_zero (ob);
}
/* Emit the physical representation of tree node EXPR to output block
OB. If REF_P is true, the leaves of EXPR are emitted as references
via lto_output_tree_ref. */
void
lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
{
unsigned ix;
bool existed_p;
if (expr == NULL_TREE)
{
output_record_start (ob, LTO_null);
return;
}
/* INTEGER_CST nodes are special because they need their original type
to be materialized by the reader (to implement TYPE_CACHED_VALUES). */
if (TREE_CODE (expr) == INTEGER_CST)
{
lto_output_integer_cst (ob, expr, ref_p);
return;
}
existed_p = lto_streamer_cache_insert (ob->writer_cache, expr, &ix);
if (existed_p)
{
/* If a node has already been streamed out, make sure that
we don't write it more than once. Otherwise, the reader
will instantiate two different nodes for the same object. */
output_record_start (ob, LTO_tree_pickle_reference);
output_uleb128 (ob, ix);
lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS,
lto_tree_code_to_tag (TREE_CODE (expr)));
}
else if (lto_stream_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. */
lto_output_builtin_tree (ob, expr);
}
else
{
/* This is the first time we see EXPR, write its fields
to OB. */
lto_write_tree (ob, expr, ref_p);
}
}
/* Miscellaneous utilities for tree streaming. Things that are used
in both input and output are here.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "streamer-hooks.h"
#include "tree-streamer.h"
/* Check that all the TS_* structures handled by the lto_output_* and
lto_input_* routines are exactly ALL the structures defined in
treestruct.def. */
void
check_handled_ts_structures (void)
{
bool handled_p[LAST_TS_ENUM];
unsigned i;
memset (&handled_p, 0, sizeof (handled_p));
/* These are the TS_* structures that are either handled or
explicitly ignored by the streamer routines. */
handled_p[TS_BASE] = true;
handled_p[TS_TYPED] = true;
handled_p[TS_COMMON] = true;
handled_p[TS_INT_CST] = true;
handled_p[TS_REAL_CST] = true;
handled_p[TS_FIXED_CST] = true;
handled_p[TS_VECTOR] = true;
handled_p[TS_STRING] = true;
handled_p[TS_COMPLEX] = true;
handled_p[TS_IDENTIFIER] = true;
handled_p[TS_DECL_MINIMAL] = true;
handled_p[TS_DECL_COMMON] = true;
handled_p[TS_DECL_WRTL] = true;
handled_p[TS_DECL_NON_COMMON] = true;
handled_p[TS_DECL_WITH_VIS] = true;
handled_p[TS_FIELD_DECL] = true;
handled_p[TS_VAR_DECL] = true;
handled_p[TS_PARM_DECL] = true;
handled_p[TS_LABEL_DECL] = true;
handled_p[TS_RESULT_DECL] = true;
handled_p[TS_CONST_DECL] = true;
handled_p[TS_TYPE_DECL] = true;
handled_p[TS_FUNCTION_DECL] = true;
handled_p[TS_TYPE_COMMON] = true;
handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
handled_p[TS_TYPE_NON_COMMON] = true;
handled_p[TS_LIST] = true;
handled_p[TS_VEC] = true;
handled_p[TS_EXP] = true;
handled_p[TS_SSA_NAME] = true;
handled_p[TS_BLOCK] = true;
handled_p[TS_BINFO] = true;
handled_p[TS_STATEMENT_LIST] = true;
handled_p[TS_CONSTRUCTOR] = true;
handled_p[TS_OMP_CLAUSE] = true;
handled_p[TS_OPTIMIZATION] = true;
handled_p[TS_TARGET_OPTION] = true;
handled_p[TS_TRANSLATION_UNIT_DECL] = true;
/* Anything not marked above will trigger the following assertion.
If this assertion triggers, it means that there is a new TS_*
structure that should be handled by the streamer. */
for (i = 0; i < LAST_TS_ENUM; i++)
gcc_assert (handled_p[i]);
}
/* Helper for lto_streamer_cache_insert_1. Add T to CACHE->NODES at
slot IX. */
static void
lto_streamer_cache_add_to_node_array (struct lto_streamer_cache_d *cache,
unsigned ix, tree t)
{
/* Make sure we're either replacing an old element or
appending consecutively. */
gcc_assert (ix <= VEC_length (tree, cache->nodes));
if (ix == VEC_length (tree, cache->nodes))
VEC_safe_push (tree, heap, cache->nodes, t);
else
VEC_replace (tree, cache->nodes, ix, t);
}
/* Helper for lto_streamer_cache_insert and lto_streamer_cache_insert_at.
CACHE, T, and IX_P are as in lto_streamer_cache_insert.
If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
slot in the cache. Otherwise, T is inserted at the position indicated
in *IX_P.
If T already existed in CACHE, return true. Otherwise,
return false. */
static bool
lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache,
tree t, unsigned *ix_p,
bool insert_at_next_slot_p)
{
void **slot;
unsigned ix;
bool existed_p;
gcc_assert (t);
slot = pointer_map_insert (cache->node_map, t);
if (!*slot)
{
/* Determine the next slot to use in the cache. */
if (insert_at_next_slot_p)
ix = VEC_length (tree, cache->nodes);
else
ix = *ix_p;
*slot = (void *)(size_t) (ix + 1);
lto_streamer_cache_add_to_node_array (cache, ix, t);
/* Indicate that the item was not present in the cache. */
existed_p = false;
}
else
{
ix = (size_t) *slot - 1;
if (!insert_at_next_slot_p && ix != *ix_p)
{
/* If the caller wants to insert T at a specific slot
location, and ENTRY->TO does not match *IX_P, add T to
the requested location slot. */
ix = *ix_p;
lto_streamer_cache_add_to_node_array (cache, ix, t);
}
/* Indicate that T was already in the cache. */
existed_p = true;
}
if (ix_p)
*ix_p = ix;
return existed_p;
}
/* Insert tree node T in CACHE. If T already existed in the cache
return true. Otherwise, return false.
If IX_P is non-null, update it with the index into the cache where
T has been stored. */
bool
lto_streamer_cache_insert (struct lto_streamer_cache_d *cache, tree t,
unsigned *ix_p)
{
return lto_streamer_cache_insert_1 (cache, t, ix_p, true);
}
/* Insert tree node T in CACHE at slot IX. If T already
existed in the cache return true. Otherwise, return false. */
bool
lto_streamer_cache_insert_at (struct lto_streamer_cache_d *cache,
tree t, unsigned ix)
{
return lto_streamer_cache_insert_1 (cache, t, &ix, false);
}
/* Appends tree node T to CACHE, even if T already existed in it. */
void
lto_streamer_cache_append (struct lto_streamer_cache_d *cache, tree t)
{
unsigned ix = VEC_length (tree, cache->nodes);
lto_streamer_cache_insert_1 (cache, t, &ix, false);
}
/* Return true if tree node T exists in CACHE, otherwise false. If IX_P is
not NULL, write to *IX_P the index into the cache where T is stored
((unsigned)-1 if T is not found). */
bool
lto_streamer_cache_lookup (struct lto_streamer_cache_d *cache, tree t,
unsigned *ix_p)
{
void **slot;
bool retval;
unsigned ix;
gcc_assert (t);
slot = pointer_map_contains (cache->node_map, t);
if (slot == NULL)
{
retval = false;
ix = -1;
}
else
{
retval = true;
ix = (size_t) *slot - 1;
}
if (ix_p)
*ix_p = ix;
return retval;
}
/* Return the tree node at slot IX in CACHE. */
tree
lto_streamer_cache_get (struct lto_streamer_cache_d *cache, unsigned ix)
{
gcc_assert (cache);
/* Make sure we're not requesting something we don't have. */
gcc_assert (ix < VEC_length (tree, cache->nodes));
return VEC_index (tree, cache->nodes, ix);
}
/* Create a cache of pickled nodes. */
struct lto_streamer_cache_d *
lto_streamer_cache_create (void)
{
struct lto_streamer_cache_d *cache;
cache = XCNEW (struct lto_streamer_cache_d);
cache->node_map = pointer_map_create ();
/* Load all the well-known tree nodes that are always created by
the compiler on startup. This prevents writing them out
unnecessarily. */
streamer_hooks.preload_common_nodes (cache);
return cache;
}
/* Delete the streamer cache C. */
void
lto_streamer_cache_delete (struct lto_streamer_cache_d *c)
{
if (c == NULL)
return;
pointer_map_destroy (c->node_map);
VEC_free (tree, heap, c->nodes);
free (c);
}
/* Data structures and functions for streaming trees.
Copyright 2011 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
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
<http://www.gnu.org/licenses/>. */
#ifndef GCC_TREE_STREAMER_H
#define GCC_TREE_STREAMER_H
#include "tree.h"
#include "lto-streamer.h"
/* Cache of pickled nodes. Used to avoid writing the same node more
than once. The first time a tree node is streamed out, it is
entered in this cache. Subsequent references to the same node are
resolved by looking it up in this cache.
This is used in two ways:
- On the writing side, the first time T is added to STREAMER_CACHE,
a new reference index is created for T and T is emitted on the
stream. If T needs to be emitted again to the stream, instead of
pickling it again, the reference index is emitted.
- On the reading side, the first time T is read from the stream, it
is reconstructed in memory and a new reference index created for
T. The reconstructed T is inserted in some array so that when
the reference index for T is found in the input stream, it can be
used to look up into the array to get the reconstructed T. */
struct lto_streamer_cache_d
{
/* The mapping between tree nodes and slots into the nodes array. */
struct pointer_map_t *node_map;
/* The nodes pickled so far. */
VEC(tree,heap) *nodes;
};
/* In tree-streamer-in.c. */
tree input_string_cst (struct data_in *, struct lto_input_block *);
tree lto_input_tree (struct lto_input_block *, struct data_in *);
void lto_streamer_read_tree (struct lto_input_block *,
struct data_in *, tree);
/* In tree-streamer-out.c. */
void lto_streamer_write_tree (struct output_block *, tree, bool);
/* In tree-streamer.c. */
void check_handled_ts_structures (void);
bool lto_streamer_cache_insert (struct lto_streamer_cache_d *, tree,
unsigned *);
bool lto_streamer_cache_insert_at (struct lto_streamer_cache_d *, tree,
unsigned);
void lto_streamer_cache_append (struct lto_streamer_cache_d *, tree);
bool lto_streamer_cache_lookup (struct lto_streamer_cache_d *, tree,
unsigned *);
tree lto_streamer_cache_get (struct lto_streamer_cache_d *, unsigned);
struct lto_streamer_cache_d *lto_streamer_cache_create (void);
void lto_streamer_cache_delete (struct lto_streamer_cache_d *);
#endif /* GCC_TREE_STREAMER_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment