diff options
Diffstat (limited to 'gcc/tree-streamer-in.c')
-rw-r--r-- | gcc/tree-streamer-in.c | 1153 |
1 files changed, 1153 insertions, 0 deletions
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c new file mode 100644 index 00000000000..cd2f221d639 --- /dev/null +++ b/gcc/tree-streamer-in.c @@ -0,0 +1,1153 @@ +/* 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; +} |