aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Maddox <maddox@google.com>2008-05-29 06:25:52 +0000
committerBill Maddox <maddox@google.com>2008-05-29 06:25:52 +0000
commit7bf2b9b44e215b21a7dcc137772ad6112e6325ca (patch)
treee69cf721dc565003384939ca9d3214b8e0c74798
parentcf699012bd823d1fbcdc6db0973464c6c37f873f (diff)
In gcc:
* lto-tree-flags.def: Add flags for *_DECL and *_TYPE for use by g lobal streamer. * lto-function-out.c: Include lto-tree-out.h. (struct output_block): Moved to lto-tree-out.h. (create_output_block, destroy_output_block): Make non-static, now exported. (output_tree_flags, debug_tree_flags): Add ADD_CLASS_TYPE, ADD_TYPE_FLAG, ADD_FUN_FLAG macros. Fix bug where stream debugging info was sometimes omitted. (lto_static_init): Adjust lto_flags_needed_for and lto_types_needed_for for node types now newly handled by the global streamer. (output_tree, output_type_tree, output_global_record_start, output_field_decl, output_function_decl, output_var_decl, output_parm_decl, output_result_decl, output_type_decl, output_namespace_decl, output_translation_unit_decl, output_binfo, output_type, output_global_constructor) New functions. * lto_function-in.c: Include lto-tree-in.h. (struct data_in): Moved to lto-tree-in.h. (input_string_internal): Initialize input_block before reading string table size from the stream. (process_tree_flags): Add ADD_CLASS_TYPE_FLAG, ADD_TYPE_FLAG, ADD_FUN_FLAG. (input_local_var): Handle stream debugging information that was previously omitted due to a bug in the writer. (lto_static_init_local): Make non-static, now exported. Add ADD_CLASS_TYPE_FLAG, ADD_TYPE_FLAG, ADD_FUN_FLAG. (input_tree, input_type_tree, input_tree_operand, global_vector_enter, global_vector_fixup, input_field_decl, input_function_decl, input_var_decl, input_parm_decl, input_result_decl, input_type_decl, input_namespace_decl, input_translation_unit_decl, input_binfo, input_type): New functions. * lto-section.h (struct lto_decl_header): Add fields for sizes of globals stream and its associated debug and string table streams. * lto-tree-tags.def: MAP_EXPR_TAG and SET_NAME macro calls for newly-handled tree codes for global decls and types. * lto-section-in.c (dump_debug_stream): Fix typo in error message. * lto-section-in.h (lto_input_function_body, lto_input_constructors_and_inits): Moved to lto-tree-in.h. * lto-tags.h (enum LTO_tags): Added literals LTO_tree_vec, LTO_translation_unit_decl, LTO_*_type, LTO_tree_binfo, LTO_pickle_reference. In gcc/lto: * lto.c: Include lto-tree-in.h, lto-tags.h. (enum DWARF2_class, DW_cl_constant, struct DWARF2_form_data, struct lto_context, lto_fd_init, lto_info_fd_init, lto_abbrev_fd_init, lto_info_fd_close, lto_file_init, lto_file_close, lto_file_corrupt_error, lto_abi_mismatch_error, LTO_CHECK_INT_VAL, LTO_READ_TYPE, lto_read_uleb128, lto_read_sleb128, lto_read_initial_length, lto_abbrev_read_attrs, lto_abbrev_read, lto_abbrev_read_lookup, lto_read_section_offset, lto_read_comp_unit_header, find_cu_for_offset, lto_get_file_name, lto_resolve_reference,lto_read_form, attribute_value_as_int, make_signed_host_wide_int, attribute_value_as_constant, lto_cache_hash, lto_cache_eq, lto_cache_store_DIE, lto_cache_lookup_DIE, lto_find_integral_type, lto_find_integral_type_1, LTO_BEGIN_READ_ATTRS_UNCHECKED, LTO_BEGIN_READ_ATTRS, LTO_END_READ_ATTRS, lto_unsupported_attr_error, lto_get_identifier, lto_read_referenced_type_DIE, lto_read_compile_unit_DIE, lto_read_array_type_DIE, lto_read_structure_union_class_type_DIE, lto_read_enumerator_DIE, lto_read_enumeration_type_DIE, lto_read_only_for_child_DIEs, lto_read_only_for_child_DIEs, lto_read_member_DIE, lto_read_abbrev, lto_read_variable_formal_parameter_constant_DIE, lto_get_body): Removed. (preload_common_nodes): New function. (lto_read_decls): Convert for new global streamer. (lto_materialze_file_data, lto_read_subroutine_type_subprogram_die, lto_read_unspecified_parameters_DIE, lto_read_typedef_DIE, lto_read_pointer_reference_type_DIE, lto_read_subrange_type_DIE, lto_read_base_type_DIE, lto_read_const_volatile_restrict_type_DIE, lto_read_namespace_DIE, lto_read_unspecified_type_DIE, lto_read_DIE, lto_read_child_DIEs, lto_collect_child_DIEs): Removed. (lto_info_read, lto_set_cu_context): Removed. (lto_file_read): Convert for new global streamer. (lto_resolve_type_ref, lto_read_DIE_at_ptr, lto_resolve_var_ref, lto_resolve_fn_ref, lto_resolve_field_ref, lto_resolve_typedecl_ref, lto_resolve_namespacedecl_ref): Removed. (lto_file_init, lto_file_close): Moved to lto-elf.c. * lto-tree.h (lto_symtab_merge_var, lto_symtab_mergee_fun): Declare here. * lto-elf.c (lto_file_init, lto_file_close): Moved from lto.c. (lto_elf_file_open): Removed code to read DWARF debug sections. * lto.h (lto_context, DWARF2_attr, DWARF2_abbrev, DWARF2_CompUnit, lto_die_ptr, lto_die_cache_entry, lto_fd, lto_info_fd, lto_abbrev_fd): Removed. (lto_file): Removed debug_info and debug_abbrev fields. (lto_ref): Removed. (lto_file_init, lto_file_close, lto_resolve_type_ref, lto_resolve_var_ref, lto_resolve_fn_ref, lto_resolve_field_ref, lto_resolve_typedecl_ref, lto_resolve_namespacedecl_ref, lto_get_file_name): Removed declarations. (lto_symtab_merge_var, lto_symtab_merge_fn): Declarations moved to lto-tree.h. * lto-symtab.c (lto_compatible_attributes_p): Lobotomize this, as it barfs on "Hello, world!". * lto-section-out.c: Include lto-tree-out.h. (lto_hash_global_slot_node, lto_eq_global_slot_node, preload_common_nodes, write_global_stream, write_global_references): New functions. (produce_asm_for_decls): Convert for new global streamer. * lto-section-out.h (lto_hash_global_slot_node, lto_eq_global_slot_node): Declare. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/lto-streamer@136137 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog.lto53
-rw-r--r--gcc/lto-function-in.c1213
-rw-r--r--gcc/lto-function-out.c1100
-rw-r--r--gcc/lto-section-in.c2
-rw-r--r--gcc/lto-section-in.h23
-rw-r--r--gcc/lto-section-out.c216
-rw-r--r--gcc/lto-section-out.h4
-rw-r--r--gcc/lto-section.h5
-rw-r--r--gcc/lto-tags.h34
-rw-r--r--gcc/lto-tree-flags.def107
-rw-r--r--gcc/lto-tree-tags.def70
-rw-r--r--gcc/lto/ChangeLog60
-rw-r--r--gcc/lto/lto-elf.c48
-rw-r--r--gcc/lto/lto-symtab.c7
-rw-r--r--gcc/lto/lto-tree.h18
-rw-r--r--gcc/lto/lto.c3863
-rw-r--r--gcc/lto/lto.h186
17 files changed, 2869 insertions, 4140 deletions
diff --git a/gcc/ChangeLog.lto b/gcc/ChangeLog.lto
index ea449b8c0e6..cb04b9255b6 100644
--- a/gcc/ChangeLog.lto
+++ b/gcc/ChangeLog.lto
@@ -1,4 +1,55 @@
-2008-04-27 Kenneth Zadeck <zadeck@naturalbridge.com>
+2008-05-28 Bill Maddox <maddox@google.com>
+
+Replace the DWARF reader in the LTO front-end.
+
+ * lto-tree-flags.def: Add flags for *_DECL
+ and *_TYPE for use by g lobal streamer.
+ * lto-function-out.c: Include lto-tree-out.h.
+ (struct output_block): Moved to lto-tree-out.h.
+ (create_output_block, destroy_output_block):
+ Make non-static, now exported.
+ (output_tree_flags, debug_tree_flags): Add ADD_CLASS_TYPE,
+ ADD_TYPE_FLAG, ADD_FUN_FLAG macros. Fix bug where stream
+ debugging info was sometimes omitted.
+ (lto_static_init): Adjust lto_flags_needed_for and
+ lto_types_needed_for for node types now newly handled by
+ the global streamer.
+ (output_tree, output_type_tree, output_global_record_start,
+ output_field_decl, output_function_decl, output_var_decl,
+ output_parm_decl, output_result_decl, output_type_decl,
+ output_namespace_decl, output_translation_unit_decl,
+ output_binfo, output_type, output_global_constructor)
+ New functions.
+ * lto_function-in.c: Include lto-tree-in.h.
+ (struct data_in): Moved to lto-tree-in.h.
+ (input_string_internal): Initialize input_block before
+ reading string table size from the stream.
+ (process_tree_flags): Add ADD_CLASS_TYPE_FLAG, ADD_TYPE_FLAG,
+ ADD_FUN_FLAG.
+ (input_local_var): Handle stream debugging information
+ that was previously omitted due to a bug in the writer.
+ (lto_static_init_local): Make non-static, now exported.
+ Add ADD_CLASS_TYPE_FLAG, ADD_TYPE_FLAG, ADD_FUN_FLAG.
+ (input_tree, input_type_tree, input_tree_operand,
+ global_vector_enter, global_vector_fixup, input_field_decl,
+ input_function_decl, input_var_decl, input_parm_decl,
+ input_result_decl, input_type_decl, input_namespace_decl,
+ input_translation_unit_decl, input_binfo, input_type):
+ New functions.
+ * lto-section.h (struct lto_decl_header): Add fields for
+ sizes of globals stream and its associated debug and string
+ table streams.
+ * lto-tree-tags.def: MAP_EXPR_TAG and SET_NAME macro calls
+ for newly-handled tree codes for global decls and types.
+ * lto-section-in.c (dump_debug_stream): Fix typo in error message.
+ * lto-section-in.h (lto_input_function_body,
+ lto_input_constructors_and_inits): Moved to lto-tree-in.h.
+ * lto-tags.h (enum LTO_tags): Added literals LTO_tree_vec,
+ LTO_translation_unit_decl, LTO_*_type, LTO_tree_binfo,
+ LTO_pickle_reference.
+
+
+2008-05-27 Kenneth Zadeck <zadeck@naturalbridge.com>
* cgraph.h (lto_file_decl_data): Removed.
* lto-function-in.c: Moved from lto directory.
diff --git a/gcc/lto-function-in.c b/gcc/lto-function-in.c
index a29fe06c49b..558f51f2316 100644
--- a/gcc/lto-function-in.c
+++ b/gcc/lto-function-in.c
@@ -51,6 +51,7 @@ Boston, MA 02110-1301, USA. */
#include "output.h"
#include "lto-tags.h"
#include "lto-section-in.h"
+#include "lto-tree-in.h"
#include <ctype.h>
#include "cpplib.h"
@@ -59,42 +60,6 @@ static enum tree_code tag_to_expr[LTO_tree_last_tag];
/* The number of flags that are defined for each tree code. */
static int flags_length_for_code[NUM_TREE_CODES];
-struct data_in
-{
- /* That global decls and types. */
- struct lto_file_decl_data* file_data;
-
- /* The offsets to decode the local_decls. */
- int *local_decls_index;
-
- /* A table to reconstruct the local_decls. */
- int *local_decl_indexes;
-
-#ifdef LTO_STREAM_DEBUGGING
- /* The offsets to decode the local_decls debug info. */
- int *local_decls_index_d;
-#endif
-
- /* The local var_decls and the parm_decls. */
- tree *local_decls;
-
- /* All of the labels. */
- tree *labels;
-
- /* The string table. */
- const char * strings;
-
- /* The length of the string table. */
- unsigned int strings_len;
- /* Number of named labels. Used to find the index of unnamed labels
- since they share space with the named labels. */
- unsigned int num_named_labels;
- const char *current_file;
- int current_line;
- int current_col;
-};
-
-
/* This hash table is used to hash the file names in the
source_location field. Unlike other structures here, this is a
persistent structure whose data lives for the entire
@@ -149,11 +114,13 @@ input_string_internal (struct data_in *data_in, unsigned int loc,
unsigned int *rlen)
{
struct lto_input_block str_tab;
- unsigned int len = lto_input_uleb128 (&str_tab);
+ unsigned int len;
const char * result;
LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings,
loc, data_in->strings_len);
+
+ len = lto_input_uleb128 (&str_tab);
*rlen = len;
gcc_assert (str_tab.p + len <= data_in->strings_len);
@@ -293,6 +260,8 @@ process_tree_flags (tree expr, lto_flags_type flags)
{ expr->decl_common. flag_name = flags >> CLEAROUT; flags <<= 1; }
#define ADD_CLASS_EXPR_FLAG(flag_name) \
{ expr->base. flag_name = flags >> CLEAROUT; flags <<= 1; }
+#define ADD_CLASS_TYPE_FLAG(flag_name) \
+ { expr->type. flag_name = flags >> CLEAROUT; flags <<= 1; }
#define END_CLASS_CASE(class) break;
#define END_CLASS_SWITCH() \
default: \
@@ -306,12 +275,16 @@ process_tree_flags (tree expr, lto_flags_type flags)
#define START_EXPR_CASE(code) case code:
#define ADD_EXPR_FLAG(flag_name) \
{ expr->base. flag_name = (flags >> CLEAROUT); flags <<= 1; }
+#define ADD_TYPE_FLAG(flag_name) \
+ { expr->type. flag_name = (flags >> CLEAROUT); flags <<= 1; }
#define ADD_DECL_FLAG(flag_name) \
{ expr->decl_common. flag_name = flags >> CLEAROUT; flags <<= 1; }
#define ADD_VIS_FLAG(flag_name) \
{ expr->decl_with_vis. flag_name = (flags >> CLEAROUT); flags <<= 1; }
#define ADD_VIS_FLAG_SIZE(flag_name,size) \
{ expr->decl_with_vis. flag_name = (flags >> (BITS_PER_LTO_FLAGS_TYPE - size)); flags <<= size; }
+#define ADD_FUN_FLAG(flag_name) \
+ { expr->function_decl. flag_name = (flags >> CLEAROUT); flags <<= 1; }
#define END_EXPR_CASE(class) break;
#define END_EXPR_SWITCH() \
default: \
@@ -325,14 +298,17 @@ process_tree_flags (tree expr, lto_flags_type flags)
#undef START_CLASS_CASE
#undef ADD_CLASS_DECL_FLAG
#undef ADD_CLASS_EXPR_FLAG
+#undef ADD_CLASS_TYPE_FLAG
#undef END_CLASS_CASE
#undef END_CLASS_SWITCH
#undef START_EXPR_SWITCH
#undef START_EXPR_CASE
#undef ADD_EXPR_FLAG
+#undef ADD_TYPE_FLAG
#undef ADD_DECL_FLAG
#undef ADD_VIS_FLAG
#undef ADD_VIS_FLAG_SIZE
+#undef ADD_FUN_FLAG
#undef END_EXPR_CASE
#undef END_EXPR_SWITCH
}
@@ -1155,6 +1131,11 @@ input_local_var (struct lto_input_block *ib, struct data_in *data_in,
}
flags = input_tree_flags (ib, 0, true);
+ /* ### */
+ /* Bug fix for handling debug info previously omitted.
+ See comment in output_tree_flags, which failed to emit
+ the flags debug info in some cases. */
+ LTO_DEBUG_TREE_FLAGS (TREE_CODE (result), flags);
if (input_line_info (ib, data_in, flags))
set_line_info (data_in, result);
@@ -1437,6 +1418,11 @@ input_ssa_names (struct lto_input_block *ib, struct data_in *data_in, struct fun
ssa_name = make_ssa_name_fn (fn, name, build_empty_stmt ());
flags = input_tree_flags (ib, 0, true);
+ /* ### */
+ /* Bug fix for handling debug info previously omitted.
+ See comment in output_tree_flags, which failed to emit
+ the flags debug info in some cases. */
+ LTO_DEBUG_TREE_FLAGS (TREE_CODE (ssa_name), flags);
process_tree_flags (ssa_name, flags);
if (SSA_NAME_IS_DEFAULT_DEF (ssa_name))
set_default_def (SSA_NAME_VAR (ssa_name), ssa_name);
@@ -1604,8 +1590,9 @@ static bool initialized_local = false;
/* Static initialization for the lto reader. */
+/* ### Declared in lto-section-in.h. Should probably be moved elsewhere. */
-static void
+void
lto_static_init_local (void)
{
if (initialized_local)
@@ -1650,6 +1637,7 @@ lto_static_init_local (void)
#define START_CLASS_CASE(class) case class:
#define ADD_CLASS_DECL_FLAG(flag_name) flags_length_for_code[code]++;
#define ADD_CLASS_EXPR_FLAG(flag_name) flags_length_for_code[code]++;
+#define ADD_CLASS_TYPE_FLAG(flag_name) flags_length_for_code[code]++;
#define END_CLASS_CASE(class) break;
#define END_CLASS_SWITCH() \
default: \
@@ -1664,9 +1652,11 @@ lto_static_init_local (void)
{
#define START_EXPR_CASE(code) case code:
#define ADD_EXPR_FLAG(flag_name) flags_length_for_code[code]++;
+#define ADD_TYPE_FLAG(flag_name) flags_length_for_code[code]++;
#define ADD_DECL_FLAG(flag_name) flags_length_for_code[code]++;
#define ADD_VIS_FLAG(flag_name) flags_length_for_code[code]++;
#define ADD_VIS_FLAG_SIZE(flag_name,size) flags_length_for_code[code] += size;
+#define ADD_FUN_FLAG(flag_name) flags_length_for_code[code]++;
#define END_EXPR_CASE(class) break;
#define END_EXPR_SWITCH() \
default: \
@@ -1683,14 +1673,17 @@ lto_static_init_local (void)
#undef START_CLASS_CASE
#undef ADD_CLASS_DECL_FLAG
#undef ADD_CLASS_EXPR_FLAG
+#undef ADD_CLASS_TYPE_FLAG
#undef END_CLASS_CASE
#undef END_CLASS_SWITCH
#undef START_EXPR_SWITCH
#undef START_EXPR_CASE
#undef ADD_EXPR_FLAG
+#undef ADD_TYPE_FLAG
#undef ADD_DECL_FLAG
#undef ADD_VIS_FLAG
#undef ADD_VIS_FLAG_SIZE
+#undef ADD_FUN_FLAG
#undef END_EXPR_CASE
#undef END_EXPR_SWITCH
@@ -1908,3 +1901,1147 @@ lto_input_constructors_and_inits (struct lto_file_decl_data* file_data,
lto_read_body (file_data, NULL, data, LTO_section_static_initializer);
}
+/* ### Read types and globals. */
+
+tree input_tree (struct lto_input_block *, struct data_in *);
+tree input_type_tree (struct data_in *, struct lto_input_block *);
+
+static tree input_tree_operand (struct lto_input_block *,
+ struct data_in *,
+ struct function *, enum LTO_tags);
+
+/* Any potentially self-referential node must be entered into
+ the global vector before any fields are read from which it
+ might be reachable. */
+
+static unsigned
+global_vector_enter (struct data_in *data_in, tree node)
+{
+ unsigned index = VEC_length (tree, data_in->globals_index);
+
+ /* ### DEBUG */
+ /* fprintf (stderr, "ENTER %06u -> %p\n", index, node); */
+
+ VEC_safe_push (tree, heap, data_in->globals_index, node);
+
+ return index;
+}
+
+static void
+global_vector_fixup (struct data_in *data_in, unsigned index, tree node)
+{
+ /* ### DEBUG */
+ /* fprintf (stderr, "FIXUP %06u -> %p\n", index, node); */
+
+ VEC_replace (tree, data_in->globals_index, index, node);
+}
+
+static tree
+input_field_decl (struct lto_input_block *ib, struct data_in *data_in)
+{
+ tree decl = make_node (FIELD_DECL);
+
+ lto_flags_type flags = input_tree_flags (ib, FIELD_DECL, true);
+ if (input_line_info (ib, data_in, flags))
+ set_line_info (data_in, decl);
+ process_tree_flags (decl, flags);
+
+ global_vector_enter (data_in, decl);
+
+ /* omit locus, uid */
+ decl->decl_minimal.name = input_tree (ib, data_in);
+ decl->decl_minimal.context = input_tree (ib, data_in);
+
+ decl->common.type = input_tree (ib, data_in);
+
+ decl->decl_common.attributes = input_tree (ib, data_in);
+ decl->decl_common.abstract_origin = input_tree (ib, data_in);
+
+ decl->decl_common.mode = lto_input_uleb128 (ib);
+ decl->decl_common.align = lto_input_uleb128 (ib);
+ decl->decl_common.off_align = lto_input_uleb128 (ib);
+
+ decl->decl_common.size = input_tree (ib, data_in);
+ decl->decl_common.size_unit = input_tree (ib, data_in);
+
+ decl->field_decl.offset = input_tree (ib, data_in);
+ decl->field_decl.bit_field_type = input_tree (ib, data_in);
+ decl->field_decl.qualifier = input_tree (ib, data_in);
+ decl->field_decl.bit_offset = input_tree (ib, data_in);
+ decl->field_decl.fcontext = input_tree (ib, data_in);
+
+ decl->decl_common.initial = input_tree (ib, data_in);
+
+ /* lang_specific */
+
+ decl->common.chain = input_tree (ib, data_in);
+
+ return decl;
+}
+
+static tree
+input_function_decl (struct lto_input_block *ib, struct data_in *data_in)
+{
+ unsigned index;
+
+ tree decl = make_node (FUNCTION_DECL);
+
+ lto_flags_type flags = input_tree_flags (ib, FUNCTION_DECL, true);
+ if (input_line_info (ib, data_in, flags))
+ set_line_info (data_in, decl);
+ process_tree_flags (decl, flags);
+
+ index = global_vector_enter (data_in, decl);
+
+ /* omit locus, uid */
+ decl->decl_minimal.name = input_tree (ib, data_in);
+ decl->decl_minimal.context = input_tree (ib, data_in);
+
+ decl->decl_with_vis.assembler_name = input_tree (ib, data_in);
+ decl->decl_with_vis.section_name = input_tree (ib, data_in);
+
+ decl->common.type = input_tree (ib, data_in);
+
+ decl->decl_common.attributes = input_tree (ib, data_in);
+ decl->decl_common.abstract_origin = input_tree (ib, data_in);
+
+ decl->decl_common.mode = lto_input_uleb128 (ib);
+ decl->decl_common.align = lto_input_uleb128 (ib);
+ /* omit off_align */
+
+ decl->decl_common.size = input_tree (ib, data_in);
+ decl->decl_common.size_unit = input_tree (ib, data_in);
+
+ /* saved_tree -- this is a function body, so omit it here */
+ decl->decl_non_common.arguments = input_tree (ib, data_in);
+ decl->decl_non_common.result = input_tree (ib, data_in);
+ decl->decl_non_common.vindex = input_tree (ib, data_in);
+
+ /* lang_specific */
+ /* omit initial -- should be read with body */
+
+ /* struct function is filled in when body is read */
+
+ /* ### Adapted from DWARF reader. */
+ if (!TREE_PUBLIC (decl))
+ /* Need to ensure static entities between different files
+ don't clash unexpectedly. */
+ lang_hooks.set_decl_assembler_name (decl);
+
+ /* If the function has already been declared, merge the
+ declarations. */
+ {
+ tree merged = lto_symtab_merge_fn (decl);
+ /* If merge fails, use the original declaraction. */
+ if (merged != error_mark_node)
+ decl = merged;
+ }
+
+ global_vector_fixup (data_in, index, decl);
+
+ return decl;
+}
+
+static tree
+input_var_decl (struct lto_input_block *ib, struct data_in *data_in)
+{
+ unsigned index;
+
+ tree decl = make_node (VAR_DECL);
+
+ lto_flags_type flags = input_tree_flags (ib, VAR_DECL, true);
+ if (input_line_info (ib, data_in, flags))
+ set_line_info (data_in, decl);
+ process_tree_flags (decl, flags);
+
+ /* Even though we cannot actually generate a reference
+ to this node until we have done the lto_symtab_merge_var,
+ we must reserve the slot in the globals vector here,
+ because the writer allocates the indices before writing
+ out the type, etc. */
+ index = global_vector_enter (data_in, NULL);
+
+ /* omit locus, uid */
+ decl->decl_minimal.name = input_tree (ib, data_in);
+ decl->decl_minimal.context = input_tree (ib, data_in);
+
+ LTO_DEBUG_TOKEN ("var_decl_assembler_name");
+ decl->decl_with_vis.assembler_name = input_tree (ib, data_in);
+ decl->decl_with_vis.section_name = input_tree (ib, data_in);
+
+ decl->common.type = input_tree (ib, data_in);
+
+ decl->decl_common.attributes = input_tree (ib, data_in);
+ decl->decl_common.abstract_origin = input_tree (ib, data_in);
+
+ decl->decl_common.mode = lto_input_uleb128 (ib);
+ decl->decl_common.align = lto_input_uleb128 (ib);
+ /* omit off_align */
+
+ LTO_DEBUG_TOKEN ("var_decl_size");
+ decl->decl_common.size = input_tree (ib, data_in);
+ decl->decl_common.size_unit = input_tree (ib, data_in);
+
+ /* lang_specific */
+ /* omit rtl */
+
+ /* DECL_DEBUG_EXPR is stored in a table on the side,
+ not in the VAR_DECL node itself. */
+ LTO_DEBUG_TOKEN ("var_decl_debug_expr");
+ {
+ tree debug_expr = input_tree (ib, data_in);
+
+ if (debug_expr)
+ SET_DECL_DEBUG_EXPR (decl, debug_expr);
+ }
+
+ /* ### Adapted from DWARF reader. */
+ if (!(decl->decl_minimal.context
+ && TREE_CODE (decl->decl_minimal.context) == FUNCTION_DECL))
+ {
+ /* Variable has file scope, not local. */
+ if (!TREE_PUBLIC (decl))
+ {
+ /* Need to ensure static variables between different files
+ don't clash unexpectedly. */
+ lang_hooks.set_decl_assembler_name (decl);
+ rest_of_decl_compilation (decl,
+ /*top_level=*/1,
+ /*at_end=*/0);
+ }
+
+ /* The DWARF reader always sets DECL_STATIC for a global,
+ and lto_symtab_merge will assert if it is not set.
+ We should likely not set it, and fix lto_symtab_merge. */
+ TREE_STATIC (decl) = 1;
+
+ /* If this variable has already been declared, merge the
+ declarations. */
+ {
+ tree merged = lto_symtab_merge_var (decl);
+ /* If merge fails, use the original declaraction. */
+ if (merged != error_mark_node)
+ decl = merged;
+ }
+ }
+
+ global_vector_fixup (data_in, index, decl);
+
+ /* Read initial value expression last, after the global_vector_fixup. */
+ decl->decl_common.initial = input_tree (ib, data_in);
+
+ LTO_DEBUG_TOKEN ("var_decl_END");
+
+ return decl;
+}
+
+static tree
+input_parm_decl (struct lto_input_block *ib, struct data_in *data_in)
+{
+ tree decl = make_node (PARM_DECL);
+
+ lto_flags_type flags = input_tree_flags (ib, PARM_DECL, true);
+ if (input_line_info (ib, data_in, flags))
+ set_line_info (data_in, decl);
+ process_tree_flags (decl, flags);
+
+ global_vector_enter (data_in, decl);
+
+ /* omit locus, uid */
+ decl->decl_minimal.name = input_tree (ib, data_in);
+ decl->decl_minimal.context = input_tree (ib, data_in);
+
+ decl->common.type = input_tree (ib, data_in);
+
+ decl->decl_common.attributes = input_tree (ib, data_in);
+ decl->decl_common.abstract_origin = input_tree (ib, data_in);
+
+ decl->decl_common.mode = lto_input_uleb128 (ib);
+ decl->decl_common.align = lto_input_uleb128 (ib);
+ /* omit off_align */
+
+ decl->decl_common.size = input_tree (ib, data_in);
+ decl->decl_common.size_unit = input_tree (ib, data_in);
+
+ decl->decl_common.initial = input_tree (ib, data_in);
+
+ /* lang_specific */
+ /* omit rtl, incoming_rtl */
+
+ decl->common.chain = input_tree (ib, data_in);
+
+ return decl;
+}
+
+static tree
+input_result_decl (struct lto_input_block *ib, struct data_in *data_in)
+{
+ tree decl = make_node (RESULT_DECL);
+
+ lto_flags_type flags = input_tree_flags (ib, RESULT_DECL, true);
+ if (input_line_info (ib, data_in, flags))
+ set_line_info (data_in, decl);
+ process_tree_flags (decl, flags);
+
+ global_vector_enter (data_in, decl);
+
+ /* omit locus, uid */
+ decl->decl_minimal.name = input_tree (ib, data_in);
+ decl->decl_minimal.context = input_tree (ib, data_in);
+
+ decl->common.type = input_tree (ib, data_in);
+
+ decl->decl_common.attributes = input_tree (ib, data_in);
+ decl->decl_common.abstract_origin = input_tree (ib, data_in);
+
+ decl->decl_common.mode = lto_input_uleb128 (ib);
+ decl->decl_common.align = lto_input_uleb128 (ib);
+ /* omit off_align */
+
+ decl->decl_common.size = input_tree (ib, data_in);
+ decl->decl_common.size_unit = input_tree (ib, data_in);
+
+ /* lang_specific */
+ /* omit rtl */
+
+ decl->decl_common.initial = input_tree (ib, data_in);
+
+ /* omit chain */
+
+ return decl;
+}
+
+static tree
+input_type_decl (struct lto_input_block *ib, struct data_in *data_in)
+{
+ tree decl = make_node (TYPE_DECL);
+
+ lto_flags_type flags = input_tree_flags (ib, TYPE_DECL, true);
+ if (input_line_info (ib, data_in, flags))
+ set_line_info (data_in, decl);
+ process_tree_flags (decl, flags);
+
+ global_vector_enter (data_in, decl);
+
+ /* omit locus, uid */
+ /* ### Must go before type */
+ decl->decl_minimal.name = input_tree (ib, data_in);
+ decl->decl_minimal.context = input_tree (ib, data_in);
+
+ decl->decl_with_vis.assembler_name = input_tree (ib, data_in);
+ decl->decl_with_vis.section_name = input_tree (ib, data_in);
+
+ decl->common.type = input_tree (ib, data_in);
+
+ decl->decl_common.attributes = input_tree (ib, data_in);
+ decl->decl_common.abstract_origin = input_tree (ib, data_in);
+
+ /* omit mode */
+ decl->decl_common.align = lto_input_uleb128 (ib);
+
+ decl->decl_common.size = input_tree (ib, data_in);
+ decl->decl_common.size_unit = input_tree (ib, data_in);
+
+ /* lang_specific */
+ /* omit rtl */
+
+ decl->decl_common.initial = input_tree (ib, data_in);
+
+ decl->decl_non_common.saved_tree = input_tree (ib, data_in);
+ decl->decl_non_common.arguments = input_tree (ib, data_in);
+ decl->decl_non_common.result = input_tree (ib, data_in);
+ decl->decl_non_common.vindex = input_tree (ib, data_in);
+
+ return decl;
+}
+
+static tree
+input_namespace_decl (struct lto_input_block *ib, struct data_in *data_in)
+{
+ tree decl = make_node (NAMESPACE_DECL);
+
+ lto_flags_type flags = input_tree_flags (ib, NAMESPACE_DECL, true);
+ if (input_line_info (ib, data_in, flags))
+ set_line_info (data_in, decl);
+ process_tree_flags (decl, flags);
+
+ global_vector_enter (data_in, decl);
+
+ /* omit locus, uid */
+ decl->decl_minimal.name = input_tree (ib, data_in);
+ decl->decl_minimal.context = input_tree (ib, data_in);
+
+ decl->decl_with_vis.assembler_name = input_tree (ib, data_in);
+ decl->decl_with_vis.section_name = input_tree (ib, data_in);
+
+ /* omit type */
+
+ /* omit mode, align, size, size_unit */
+ decl->decl_common.attributes = input_tree (ib, data_in);
+ decl->decl_common.abstract_origin = input_tree (ib, data_in);
+
+ /* lang_specific */
+ /* omit rtl */
+
+ decl->decl_non_common.saved_tree = input_tree (ib, data_in);
+ /* omit arguments, result */
+ decl->decl_non_common.vindex = input_tree (ib, data_in);
+
+ return decl;
+}
+
+static tree
+input_translation_unit_decl (struct lto_input_block *ib, struct data_in *data_in)
+{
+ tree decl = make_node (TRANSLATION_UNIT_DECL);
+
+ lto_flags_type flags = input_tree_flags (ib, TRANSLATION_UNIT_DECL, true);
+ if (input_line_info (ib, data_in, flags))
+ set_line_info (data_in, decl);
+ process_tree_flags (decl, flags);
+
+ global_vector_enter (data_in, decl);
+
+ /* omit locus, uid */
+ decl->decl_minimal.name = input_tree (ib, data_in);
+ decl->decl_minimal.context = input_tree (ib, data_in);
+
+ decl->decl_with_vis.assembler_name = input_tree (ib, data_in);
+ decl->decl_with_vis.section_name = input_tree (ib, data_in);
+
+ decl->common.type = input_tree (ib, data_in);
+
+ /* omit attributes */
+ decl->decl_common.abstract_origin = input_tree (ib, data_in);
+
+ /* omit mode */
+ decl->decl_common.align = lto_input_uleb128 (ib);
+
+ /* omit size, size_unit, initial */
+ /* omit rtl */
+
+ return decl;
+}
+
+static tree
+input_binfo (struct lto_input_block *ib, struct data_in *data_in)
+{
+ size_t i;
+ tree binfo;
+ size_t num_base_accesses;
+ size_t num_base_binfos;
+ lto_flags_type flags;
+
+ flags = input_tree_flags (ib, TREE_BINFO, true);
+
+ num_base_accesses = lto_input_uleb128 (ib);
+ num_base_binfos = lto_input_uleb128 (ib);
+
+ binfo = make_tree_binfo (num_base_binfos);
+
+ /* no line info */
+ gcc_assert (!input_line_info (ib, data_in, flags));
+ process_tree_flags (binfo, flags);
+
+ global_vector_enter (data_in, binfo);
+
+ binfo->common.type = input_tree (ib, data_in);
+
+ binfo->binfo.offset = input_tree (ib, data_in);
+ binfo->binfo.vtable = input_tree (ib, data_in);
+ binfo->binfo.virtuals = input_tree (ib, data_in);
+ binfo->binfo.vptr_field = input_tree (ib, data_in);
+ binfo->binfo.inheritance = input_tree (ib, data_in);
+ binfo->binfo.vtt_subvtt = input_tree (ib, data_in);
+ binfo->binfo.vtt_vptr = input_tree (ib, data_in);
+
+ binfo->binfo.base_accesses = VEC_alloc (tree, gc, num_base_accesses);
+ LTO_DEBUG_TOKEN ("base_accesses");
+ for (i = 0; i < num_base_accesses; ++i)
+ VEC_quick_push (tree, binfo->binfo.base_accesses, input_tree (ib, data_in));
+
+ LTO_DEBUG_TOKEN ("base_binfos");
+ for (i = 0; i < num_base_binfos; ++i)
+ VEC_quick_push (tree, &binfo->binfo.base_binfos, input_tree (ib, data_in));
+
+ binfo->common.chain = input_tree (ib, data_in);
+
+ return binfo;
+}
+
+static tree
+input_type (struct lto_input_block *ib, struct data_in *data_in, enum tree_code code)
+{
+ tree type = make_node (code);
+
+ process_tree_flags (type, input_tree_flags (ib, code, true));
+ /* Clear this flag, since we didn't stream the values cache. */
+ TYPE_CACHED_VALUES_P (type) = 0;
+
+ global_vector_enter (data_in, type);
+
+ LTO_DEBUG_TOKEN ("type");
+ type->common.type = input_tree (ib, data_in);
+
+ LTO_DEBUG_TOKEN ("size");
+ type->type.size = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("size_unit");
+ type->type.size_unit = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("attributes");
+ type->type.attributes = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("uid");
+ type->type.uid = lto_input_uleb128 (ib);
+ LTO_DEBUG_TOKEN ("precision");
+ type->type.precision = lto_input_uleb128 (ib);
+ LTO_DEBUG_TOKEN ("mode");
+ type->type.mode = lto_input_uleb128 (ib);
+ LTO_DEBUG_TOKEN ("align");
+ type->type.align = lto_input_uleb128 (ib);
+ LTO_DEBUG_TOKEN ("pointer_to");
+ /* ### I think this is a cache that should not be streamed. */
+ type->type.pointer_to = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("reference_to");
+ type->type.reference_to = input_tree (ib, data_in);
+ /* ### Read symtab here, if required. */
+ LTO_DEBUG_TOKEN ("name");
+ type->type.name = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("minval");
+ type->type.minval = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("maxval");
+ type->type.maxval = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("next_variant");
+ type->type.next_variant = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("main_variant");
+ type->type.main_variant = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("binfo");
+ type->type.binfo = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("context");
+ type->type.context = input_tree (ib, data_in);
+ LTO_DEBUG_TOKEN ("canonical");
+ type->type.canonical = input_tree (ib, data_in);
+
+ /* Do components last */
+ LTO_DEBUG_TOKEN ("values");
+ {
+ tree values = input_tree (ib, data_in);
+ /* If using values cache, creation of integer
+ literals above may have allocated a new cache.
+ In this case, don't clobber it. */
+ if (!type->type.values)
+ type->type.values = values;
+ }
+
+ LTO_DEBUG_TOKEN ("chain");
+ type->common.chain = input_tree (ib, data_in); /* TYPE_STUB_DECL */
+
+ return type;
+}
+
+/* Read a node in the gimple tree from IB. The TAG has already been
+ read. */
+
+static tree
+input_tree_operand (struct lto_input_block *ib, struct data_in *data_in,
+ struct function *fn, enum LTO_tags tag)
+{
+ enum tree_code code;
+ tree type = NULL_TREE;
+ lto_flags_type flags;
+ tree result = NULL_TREE;
+ bool needs_line_set = false;
+
+ /* If tree reference, resolve to previously-read node. */
+ if (tag == LTO_tree_pickle_reference)
+ {
+ tree result;
+ unsigned int index = lto_input_uleb128 (ib);
+ gcc_assert (data_in->globals_index);
+#ifdef GLOBAL_STREAMER_TRACE
+ fprintf (stderr, "index 0x%x length 0x%x\n", index, VEC_length (tree, data_in->globals_index));
+#endif
+ gcc_assert (index < VEC_length (tree, data_in->globals_index));
+ result = VEC_index (tree, data_in->globals_index, index);
+ gcc_assert (result);
+#ifdef GLOBAL_STREAMER_TRACE
+ fprintf (stderr, "0x%x -> REF %p\n", index, result);
+#endif
+ LTO_DEBUG_UNDENT();
+ return result;
+ }
+
+ code = tag_to_expr[tag];
+
+ gcc_assert (code);
+
+ if (TREE_CODE_CLASS (code) != tcc_type && TREE_CODE_CLASS (code) != tcc_declaration)
+ {
+ if (TEST_BIT (lto_types_needed_for, code))
+ type = input_type_tree (data_in, ib);
+
+ flags = input_tree_flags (ib, code, false);
+ }
+ else
+ /* Inhibit the usual flag processing. Handlers for types
+ and declarations will deal with flags and TREE_TYPE themselves. */
+ flags = 0;
+
+
+ /* ### Handlers for declarations currently handle line info themselves. */
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+ || IS_GIMPLE_STMT_CODE_CLASS(TREE_CODE_CLASS (code)))
+ needs_line_set = input_line_info (ib, data_in, flags);
+
+ switch (code)
+ {
+ case COMPLEX_CST:
+ {
+ tree elt_type = input_type_tree (data_in, ib);
+
+ result = build0 (code, type);
+ if (tag == LTO_complex_cst1)
+ {
+ TREE_REALPART (result) = input_real (ib, data_in, elt_type);
+ TREE_IMAGPART (result) = input_real (ib, data_in, elt_type);
+ }
+ else
+ {
+ TREE_REALPART (result) = lto_input_integer (ib, elt_type);
+ TREE_IMAGPART (result) = lto_input_integer (ib, elt_type);
+ }
+ }
+ break;
+
+ case INTEGER_CST:
+ result = lto_input_integer (ib, type);
+ break;
+
+ case REAL_CST:
+ result = input_real (ib, data_in, type);
+ break;
+
+ case STRING_CST:
+ result = input_string (data_in, lto_input_uleb128 (ib));
+ TREE_TYPE (result) = type;
+ break;
+
+ case IDENTIFIER_NODE:
+ {
+ unsigned int len;
+ const char * ptr = input_string_internal (data_in, lto_input_uleb128 (ib), &len);
+ result = get_identifier_with_length (ptr, len);
+ }
+ break;
+
+ case VECTOR_CST:
+ {
+ tree chain = NULL_TREE;
+ int len = lto_input_uleb128 (ib);
+ tree elt_type = input_type_tree (data_in, ib);
+
+ if (len && tag == LTO_vector_cst1)
+ {
+ int i;
+ tree last
+ = build_tree_list (NULL_TREE, input_real (ib, data_in, elt_type));
+ chain = last;
+ for (i = 1; i < len; i++)
+ {
+ tree t
+ = build_tree_list (NULL_TREE, input_real (ib, data_in, elt_type));
+ TREE_CHAIN (last) = t;
+ last = t;
+ }
+ }
+ else
+ {
+ int i;
+ tree last = build_tree_list (NULL_TREE, lto_input_integer (ib, elt_type));
+ chain = last;
+ for (i = 1; i < len; i++)
+ {
+ tree t
+ = build_tree_list (NULL_TREE, lto_input_integer (ib, elt_type));
+ TREE_CHAIN (last) = t;
+ last = t;
+ }
+ }
+ result = build_vector (type, chain);
+ }
+ break;
+
+ case CASE_LABEL_EXPR:
+ /* ### We shouldn't see these here. */
+ gcc_unreachable ();
+
+ case CONSTRUCTOR:
+ {
+ VEC(constructor_elt,gc) *vec = NULL;
+ unsigned int len = lto_input_uleb128 (ib);
+
+ if (len)
+ {
+ unsigned int i = 0;
+ vec = VEC_alloc (constructor_elt, gc, len);
+ for (i = 0; i < len; i++)
+ {
+ tree purpose = NULL_TREE;
+ tree value;
+ constructor_elt *elt;
+ enum LTO_tags ctag = input_record_start (ib);
+
+ if (ctag)
+ purpose = input_tree_operand (ib, data_in, fn, ctag);
+
+ value = input_tree_operand (ib, data_in, fn, input_record_start (ib));
+ elt = VEC_quick_push (constructor_elt, vec, NULL);
+ elt->index = purpose;
+ elt->value = value;
+ }
+ }
+ result = build_constructor (type, vec);
+ }
+ break;
+
+ case SSA_NAME:
+ /* ### */
+ /* I'm not sure these are meaningful at file scope.
+ In any case, we cannot handle them in the same
+ manner as within a function body. */
+ gcc_unreachable ();
+
+ case CONST_DECL:
+ /* Just ignore these, Mark will make them disappear. */
+ break;
+
+ case FIELD_DECL:
+ result = input_field_decl (ib, data_in);
+ break;
+
+ case FUNCTION_DECL:
+ result = input_function_decl (ib, data_in);
+ break;
+
+ case VAR_DECL:
+ if (tag == LTO_var_decl1)
+ {
+ /* Static or external variable. */
+ result = input_var_decl (ib, data_in);
+ }
+ else
+ /* There should be no references to locals in this context. */
+ gcc_unreachable ();
+ break;
+
+ case PARM_DECL:
+ /* These should be dummy parameters in extern declarations, etc. */
+ result = input_parm_decl (ib, data_in);
+ break;
+
+ case RESULT_DECL:
+ /* Note that when we reach this point, were are declaring a result
+ decl, not referencing one. In some sense, the actual result
+ variable is a local, and should be declared in the function body,
+ but these are apparently treated similarly to parameters, for
+ which dummy instances are created for extern declarations, etc.
+ Actual references should occur only within a function body. */
+ result = input_result_decl (ib, data_in);
+ break;
+
+ case TYPE_DECL:
+ result = input_type_decl (ib, data_in);
+ break;
+
+ case NAMESPACE_DECL:
+ result = input_namespace_decl (ib, data_in);
+ break;
+
+ case TRANSLATION_UNIT_DECL:
+ result = input_translation_unit_decl (ib, data_in);
+ break;
+
+ case LABEL_DECL:
+ case LABEL_EXPR:
+ gcc_unreachable ();
+ break;
+
+ case COND_EXPR:
+ if (tag == LTO_cond_expr0)
+ {
+ tree op0;
+ tree op1;
+ tree op2;
+ op0 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ op1 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ op2 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ result = build3 (code, type, op0, op1, op2);
+ }
+ else
+ {
+ tree op0;
+ op0 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ result = build3 (code, type, op0, NULL, NULL);
+ }
+ break;
+
+ case COMPONENT_REF:
+ {
+ tree op0;
+ tree op1;
+ op0 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ op1 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+
+ /* Ignore 3 because it can be recomputed. */
+ result = build3 (code, type, op0, op1, NULL_TREE);
+ }
+ break;
+
+ case CALL_EXPR:
+ {
+ unsigned int i;
+ unsigned int count = lto_input_uleb128 (ib);
+ tree op1;
+ tree op2 = NULL_TREE;
+
+ /* The call chain. */
+ if (tag == LTO_call_expr1)
+ op2 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+
+ /* The callee. */
+ op1 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+
+ result = build_vl_exp (code, count);
+ CALL_EXPR_FN (result) = op1;
+ CALL_EXPR_STATIC_CHAIN (result) = op2;
+ for (i = 3; i < count; i++)
+ TREE_OPERAND (result, i)
+ = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ TREE_TYPE (result) = type;
+ }
+ break;
+
+ case BIT_FIELD_REF:
+ {
+ tree op0;
+ tree op1;
+ tree op2;
+ if (tag == LTO_bit_field_ref1)
+ {
+ op1 = build_int_cst_wide (sizetype, lto_input_uleb128 (ib), 0);
+ op2 = build_int_cst_wide (bitsizetype, lto_input_uleb128 (ib), 0);
+ op0 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ }
+ else
+ {
+ op0 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ op1 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ op2 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ }
+ result = build3 (code, type, op0, op1, op2);
+ }
+ break;
+
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ /* Ignore operands 2 and 3 for ARRAY_REF and ARRAY_RANGE REF
+ because they can be recomputed. */
+ {
+ tree op0 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ tree op1 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ result = build4 (code, type, op0, op1, NULL_TREE, NULL_TREE);
+ }
+ break;
+
+ case ASM_EXPR:
+ {
+ tree str = input_string (data_in, lto_input_uleb128 (ib));
+ tree ins = NULL_TREE;
+ tree outs = NULL_TREE;
+ tree clobbers = NULL_TREE;
+ tree tl;
+
+ tag = input_record_start (ib);
+ if (tag)
+ ins = input_tree_operand (ib, data_in, fn, tag);
+ tag = input_record_start (ib);
+ if (tag)
+ outs = input_tree_operand (ib, data_in, fn, tag);
+ tag = input_record_start (ib);
+ if (tag)
+ clobbers = input_tree_operand (ib, data_in, fn, tag);
+
+ result = build4 (code, void_type_node, str, outs, ins, clobbers);
+
+ for (tl = ASM_OUTPUTS (result); tl; tl = TREE_CHAIN (tl))
+ if (TREE_CODE (TREE_VALUE (tl)) == SSA_NAME)
+ SSA_NAME_DEF_STMT (TREE_VALUE (tl)) = result;
+ }
+ break;
+
+ case RESX_EXPR:
+ result = build1 (code, void_type_node, lto_input_integer (ib, NULL_TREE));
+ break;
+
+ case RETURN_EXPR:
+ /* ### We shouldn't see these here. */
+ gcc_unreachable ();
+
+ case RANGE_EXPR:
+ {
+ tree op0 = lto_input_integer (ib, input_type_tree (data_in, ib));
+ tree op1 = lto_input_integer (ib, input_type_tree (data_in, ib));
+ result = build2 (RANGE_EXPR, sizetype, op0, op1);
+ }
+ break;
+
+ case GIMPLE_MODIFY_STMT:
+ {
+ tree op0 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ tree op1 = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+
+ result = build_gimple_modify_stmt (op0, op1);
+ if (TREE_CODE (op0) == SSA_NAME)
+ SSA_NAME_DEF_STMT (op0) = result;
+ }
+ break;
+
+ case SWITCH_EXPR:
+ /* ### We shouldn't see these here. */
+ gcc_unreachable ();
+
+ case TREE_LIST:
+ {
+ unsigned int count = lto_input_uleb128 (ib);
+ tree next = NULL;
+
+ result = NULL_TREE;
+ while (count--)
+ {
+ tree value;
+ tree purpose;
+ tree elt;
+ enum LTO_tags tag = input_record_start (ib);
+
+ if (tag)
+ value = input_tree_operand (ib, data_in, fn, tag);
+ else
+ value = NULL_TREE;
+ tag = input_record_start (ib);
+ if (tag)
+ purpose = input_tree_operand (ib, data_in, fn, tag);
+ else
+ purpose = NULL_TREE;
+
+ elt = build_tree_list (purpose, value);
+ if (result)
+ TREE_CHAIN (next) = elt;
+ else
+ /* Save the first one. */
+ result = elt;
+ next = elt;
+ }
+ }
+ break;
+
+ case TREE_VEC:
+ {
+ unsigned int i;
+ unsigned int len = lto_input_uleb128 (ib);
+ tree result = make_tree_vec (len);
+
+ for (i = 0; i < len; ++i)
+ TREE_VEC_ELT (result, i) = input_tree (ib, data_in);
+ }
+ break;
+
+ case ERROR_MARK:
+ /* The canonical error node is preloaded,
+ so we should never see another one here. */
+ gcc_unreachable ();
+
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case FIXED_POINT_TYPE:
+ case COMPLEX_TYPE:
+ case BOOLEAN_TYPE:
+ case OFFSET_TYPE:
+ case ENUMERAL_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case VECTOR_TYPE:
+ case ARRAY_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ result = input_type (ib, data_in, code);
+ break;
+
+ case LANG_TYPE:
+ gcc_unreachable ();
+
+ case TREE_BINFO:
+ result = input_binfo (ib, data_in);
+ break;
+
+ /* This is the default case. All of the cases that can be done
+ completely mechanically are done here. */
+#define SET_NAME(a,b)
+#define TREE_SINGLE_MECHANICAL_TRUE
+#define MAP_EXPR_TAG(expr,tag) case expr:
+#include "lto-tree-tags.def"
+#undef MAP_EXPR_TAG
+#undef TREE_SINGLE_MECHANICAL_TRUE
+#undef SET_NAME
+ {
+ tree ops[7];
+ int len = TREE_CODE_LENGTH (code);
+ int i;
+ for (i = 0; i<len; i++)
+ ops[i] = input_tree_operand (ib, data_in, fn,
+ input_record_start (ib));
+ switch (len)
+ {
+ case 0:
+ result = build0 (code, type);
+ break;
+ case 1:
+ result = build1 (code, type, ops[0]);
+ break;
+ case 2:
+ result = build2 (code, type, ops[0], ops[1]);
+ break;
+ case 3:
+ result = build3 (code, type, ops[0], ops[1], ops[2]);
+ break;
+ case 4:
+ result = build4 (code, type, ops[0], ops[1], ops[2], ops[3]);
+ break;
+ case 5:
+ result = build5 (code, type, ops[0], ops[1], ops[2], ops[3],
+ ops[4]);
+ break;
+ /* No 'case 6'. */
+ case 7:
+ result = build7 (code, type, ops[0], ops[1], ops[2], ops[3],
+ ops[4], ops[5], ops[6]);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ break;
+ /* This is the error case, these are type codes that will either
+ never happen or that we have not gotten around to dealing
+ with are here. */
+ case BIND_EXPR:
+ case BLOCK:
+ case CATCH_EXPR:
+ case EH_FILTER_EXPR:
+ case NAME_MEMORY_TAG:
+ case OMP_CONTINUE:
+ case OMP_CRITICAL:
+ case OMP_FOR:
+ case OMP_MASTER:
+ case OMP_ORDERED:
+ case OMP_PARALLEL:
+ case OMP_RETURN:
+ case OMP_SECTIONS:
+ case OMP_SINGLE:
+ case SYMBOL_MEMORY_TAG:
+ case TARGET_MEM_REF:
+ case TRY_CATCH_EXPR:
+ case TRY_FINALLY_EXPR:
+ default:
+ /* We cannot have forms that are not explicity handled. So when
+ this is triggered, there is some form that is not being
+ output. */
+ gcc_unreachable ();
+ }
+
+ LTO_DEBUG_UNDENT();
+ if (flags)
+ process_tree_flags (result, flags);
+
+ if (needs_line_set)
+ set_line_info (data_in, result);
+
+ /* It is not enought to just put the flags back as we serialized
+ them. There are side effects to the buildN functions which play
+ with the flags to the point that we just have to call this here
+ to get it right. */
+ if (code == ADDR_EXPR)
+ {
+ tree x;
+
+ /* Following tree-cfg.c:verify_expr: skip any references and
+ ensure that any variable used as a prefix is marked
+ addressable. */
+ for (x = TREE_OPERAND (result, 0);
+ handled_component_p (x);
+ x = TREE_OPERAND (x, 0))
+ ;
+
+ if (TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == PARM_DECL)
+ TREE_ADDRESSABLE (x) = 1;
+ else if (TREE_CODE (x) == FUNCTION_DECL)
+ cgraph_mark_needed_node (cgraph_node (x));
+
+ recompute_tree_invariant_for_addr_expr (result);
+ }
+
+#ifdef GLOBAL_STREAMER_DEBUG
+ {
+ unsigned int next_index = VEC_length (tree, data_in->globals_index);
+ fprintf (stderr, "0x%x -> NEW %p : ", next_index-1, result);
+ print_generic_expr (stderr, result, 0);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ return result;
+}
+
+/* Input a generic tree, allowing for NULL_TREE. */
+tree
+input_tree (struct lto_input_block *ib, struct data_in *data_in)
+{
+ enum LTO_tags tag = input_record_start (ib);
+
+ if (tag)
+ return input_tree_operand (ib, data_in, NULL, tag);
+ else
+ return NULL_TREE;
+}
+
+/* ### Note reversed argument order. */
+tree
+input_type_tree ( struct data_in *data_in, struct lto_input_block *ib)
+{
+ enum LTO_tags tag;
+ tree type;
+
+ LTO_DEBUG_TOKEN ("type");
+ tag = input_record_start (ib);
+ type = input_tree_operand (ib, data_in, NULL, tag);
+ gcc_assert (type && TYPE_P (type));
+ return type;
+}
diff --git a/gcc/lto-function-out.c b/gcc/lto-function-out.c
index 49b0c6b8ff5..55a155cccbe 100644
--- a/gcc/lto-function-out.c
+++ b/gcc/lto-function-out.c
@@ -52,6 +52,7 @@ Boston, MA 02110-1301, USA. */
#include "output.h"
#include "lto-tags.h"
#include "lto-section-out.h"
+#include "lto-tree-out.h"
#include <ctype.h>
@@ -132,85 +133,6 @@ eq_string_slot_node (const void *p1, const void *p2)
else return 0;
}
-/* The fields written to a function or extern variable header. */
-
-struct output_block
-{
- enum lto_section_type section_type;
- struct lto_out_decl_state *decl_state;
-
- /* The stream that the main tree codes are written to. */
- struct lto_output_stream *main_stream;
- /* The stream that contains the indexes for the local name table. */
- struct lto_output_stream *local_decl_index_stream;
- /* The stream that contains the local name table. */
- struct lto_output_stream *local_decl_stream;
- /* The stream that contains the names for the named_labels. */
- struct lto_output_stream *named_label_stream;
- /* The stream that contains the string table. */
- struct lto_output_stream *string_stream;
- /* The stream that contains the ssa_names table. */
- struct lto_output_stream *ssa_names_stream;
- /* The stream that contains the cfg. */
- struct lto_output_stream *cfg_stream;
-
-#ifdef LTO_STREAM_DEBUGGING
- /* The stream that contains the local decls index debugging information. */
- struct lto_output_stream *debug_decl_index_stream;
- /* The stream that contains the local decls debugging information. */
- struct lto_output_stream *debug_decl_stream;
- /* The stream that contains the labels debugging information. */
- struct lto_output_stream *debug_label_stream;
- /* The stream that contains the ssa_names debugging information. */
- struct lto_output_stream *debug_ssa_names_stream;
- /* The stream that contains the cfg debugging information. */
- struct lto_output_stream *debug_cfg_stream;
- /* The stream that contains the gimple debugging information. */
- struct lto_output_stream *debug_main_stream;
-#endif
-
- /* The hash table that contains the set of labels we have seen so
- far and the indexes assigned to them. */
- htab_t label_hash_table;
- int next_named_label_index;
- int next_unnamed_label_index;
- VEC(tree,heap) *named_labels;
-
- /* The hash table that contains the set of local parm and var decls
- we have seen so far and the indexes assigned to them. */
- htab_t local_decl_hash_table;
- unsigned int next_local_decl_index;
- /* The local_decls_index and the local_decls_index_d are the indexes
- in the local var stream and the local var debugging stream where
- a particular local var is located. This allows the local vars to
- be read in random order. */
- VEC(int,heap) *local_decls_index;
- /* Index in local_decls so that list can be reconstructed
- properly. */
- VEC(int,heap) *unexpanded_local_decls_index;
-#ifdef LTO_STREAM_DEBUGGING
- VEC(int,heap) *local_decls_index_d;
-#endif
- VEC(tree,heap) *local_decls;
-
- /* The hash table that contains the set of strings we have seen so
- far and the indexes assigned to them. */
- htab_t string_hash_table;
- unsigned int next_string_index;
-
-
- /* The current cgraph_node that we are currently serializing. Null
- if we are serializing something else. */
- struct cgraph_node *cgraph_node;
-
- /* These are the last file and line that were seen in the stream.
- If the current node differs from these, it needs to insert
- something into the stream and fix these up. */
- const char *current_file;
- int current_line;
- int current_col;
-};
-
/* The output stream that contains the abbrev table for all of the
functions in this compilation unit. */
@@ -228,9 +150,10 @@ clear_line_info (struct output_block *ob)
/* Create the output block and return it. SECTION_TYPE is LTO_section_function_body or
-lto_static_initializer. */
+ lto_static_initializer. */
+/* ### Now declared in lto-section-out.h. Move definition to lto-section-out.c ? */
-static struct output_block *
+struct output_block *
create_output_block (enum lto_section_type section_type)
{
struct output_block *ob = xcalloc (1, sizeof (struct output_block));
@@ -274,8 +197,9 @@ create_output_block (enum lto_section_type section_type)
/* Destroy the output block OB. */
+/* ### Now declared in lto-section-out.h. Move definition to lto-section-out.c ? */
-static void
+void
destroy_output_block (struct output_block * ob)
{
enum lto_section_type section_type = ob->section_type;
@@ -466,6 +390,8 @@ output_tree_flags (struct output_block *ob,
{ flags <<= 1; if (expr->decl_common. flag_name ) flags |= 1; }
#define ADD_CLASS_EXPR_FLAG(flag_name) \
{ flags <<= 1; if (expr->base. flag_name ) flags |= 1; }
+#define ADD_CLASS_TYPE_FLAG(flag_name) \
+ { flags <<= 1; if (expr->type. flag_name ) flags |= 1; }
#define END_CLASS_CASE(class) break;
#define END_CLASS_SWITCH() \
default: \
@@ -479,12 +405,16 @@ output_tree_flags (struct output_block *ob,
#define START_EXPR_CASE(code) case code:
#define ADD_EXPR_FLAG(flag_name) \
{ flags <<= 1; if (expr->base. flag_name ) flags |= 1; }
+#define ADD_TYPE_FLAG(flag_name) \
+ { flags <<= 1; if (expr->type. flag_name ) flags |= 1; }
#define ADD_DECL_FLAG(flag_name) \
{ flags <<= 1; if (expr->decl_common. flag_name ) flags |= 1; }
#define ADD_VIS_FLAG(flag_name) \
{ flags <<= 1; if (expr->decl_with_vis. flag_name ) flags |= 1; }
#define ADD_VIS_FLAG_SIZE(flag_name,size) \
{ flags <<= size; if (expr->decl_with_vis. flag_name ) flags |= expr->decl_with_vis. flag_name; }
+#define ADD_FUN_FLAG(flag_name) \
+ { flags <<= 1; if (expr->function_decl. flag_name ) flags |= 1; }
#define END_EXPR_CASE(class) break;
#define END_EXPR_SWITCH() \
default: \
@@ -498,14 +428,17 @@ output_tree_flags (struct output_block *ob,
#undef START_CLASS_CASE
#undef ADD_CLASS_DECL_FLAG
#undef ADD_CLASS_EXPR_FLAG
+#undef ADD_CLASS_TYPE_FLAG
#undef END_CLASS_CASE
#undef END_CLASS_SWITCH
#undef START_EXPR_SWITCH
#undef START_EXPR_CASE
#undef ADD_EXPR_FLAG
+#undef ADD_TYPE_FLAG
#undef ADD_DECL_FLAG
#undef ADD_VIS_FLAG
#undef ADD_VIS_FLAG_SIZE
+#undef ADD_FUN_FLAG
#undef END_EXPR_CASE
#undef END_EXPR_SWITCH
@@ -572,7 +505,16 @@ output_tree_flags (struct output_block *ob,
LTO_DEBUG_TOKEN ("flags");
output_widest_uint_uleb128 (ob, flags);
- LTO_DEBUG_TREE_FLAGS (code, flags);
+ /* ### */
+ /* Note that when we force flags with code == 0,
+ we cause the debugging info to be omitted.
+ I tried to fix this like so:
+ LTO_DEBUG_TREE_FLAGS (TREE_CODE (expr), flags);
+ This breaks input_local_var, however, which
+ expects the debug info to be missing.
+ Do the fix anyway, and fix input_local_var. */
+ /* LTO_DEBUG_TREE_FLAGS (code, flags); */
+ LTO_DEBUG_TREE_FLAGS (TREE_CODE (expr), flags);
if (file_to_write)
{
@@ -629,11 +571,13 @@ output_type_ref (struct output_block *ob, tree node)
static unsigned int
output_local_decl_ref (struct output_block *ob, tree name, bool write)
{
+ bool new;
unsigned int index;
- bool new = lto_output_decl_index (write ? ob->main_stream : NULL,
- ob->local_decl_hash_table,
- &ob->next_local_decl_index,
- name, &index);
+
+ new = lto_output_decl_index (write ? ob->main_stream : NULL,
+ ob->local_decl_hash_table,
+ &ob->next_local_decl_index,
+ name, &index);
/* Push the new local var or param onto a vector for later
processing. */
if (new)
@@ -1879,11 +1823,17 @@ lto_static_init (void)
RESET_BIT (lto_flags_needed_for, SSA_NAME);
RESET_BIT (lto_flags_needed_for, VAR_DECL);
RESET_BIT (lto_flags_needed_for, TREE_LIST);
+ RESET_BIT (lto_flags_needed_for, TREE_VEC);
RESET_BIT (lto_flags_needed_for, TYPE_DECL);
+ RESET_BIT (lto_flags_needed_for, TRANSLATION_UNIT_DECL);
RESET_BIT (lto_flags_needed_for, NAMESPACE_DECL);
lto_types_needed_for = sbitmap_alloc (NUM_TREE_CODES);
+ /* ### */
+ /* Global declarations and types will handle the
+ type field by other means, so lto_types_needed_for
+ should not be set for them. */
#if REDUNDANT_TYPE_SYSTEM
/* These forms never need types. */
sbitmap_ones (lto_types_needed_for);
@@ -1902,8 +1852,28 @@ lto_static_init (void)
RESET_BIT (lto_types_needed_for, SSA_NAME);
RESET_BIT (lto_types_needed_for, VAR_DECL);
RESET_BIT (lto_types_needed_for, TREE_LIST);
+ RESET_BIT (lto_types_needed_for, TREE_VEC);
RESET_BIT (lto_types_needed_for, TYPE_DECL);
RESET_BIT (lto_types_needed_for, NAMESPACE_DECL);
+ RESET_BIT (lto_types_needed_for, TRANSLATION_UNIT_DECL);
+ /* ### types -- should move into alphabetical order */
+ RESET_BIT (lto_types_needed_for, VOID_TYPE);
+ RESET_BIT (lto_types_needed_for, INTEGER_TYPE);
+ RESET_BIT (lto_types_needed_for, REAL_TYPE);
+ RESET_BIT (lto_types_needed_for, FIXED_POINT_TYPE);
+ RESET_BIT (lto_types_needed_for, COMPLEX_TYPE);
+ RESET_BIT (lto_types_needed_for, BOOLEAN_TYPE);
+ RESET_BIT (lto_types_needed_for, OFFSET_TYPE);
+ RESET_BIT (lto_types_needed_for, ENUMERAL_TYPE);
+ RESET_BIT (lto_types_needed_for, POINTER_TYPE);
+ RESET_BIT (lto_types_needed_for, REFERENCE_TYPE);
+ RESET_BIT (lto_types_needed_for, VECTOR_TYPE);
+ RESET_BIT (lto_types_needed_for, ARRAY_TYPE);
+ RESET_BIT (lto_types_needed_for, RECORD_TYPE);
+ RESET_BIT (lto_types_needed_for, UNION_TYPE);
+ RESET_BIT (lto_types_needed_for, QUAL_UNION_TYPE);
+ RESET_BIT (lto_types_needed_for, FUNCTION_TYPE);
+ RESET_BIT (lto_types_needed_for, METHOD_TYPE);
#else
/* These forms will need types, even when the type system is fixed. */
SET_BIT (lto_types_needed_for, COMPLEX_CST);
@@ -2186,6 +2156,8 @@ lto_debug_tree_flags (struct lto_debug_context *context,
{ if (flags >> CLEAROUT) lto_debug_token (context, " " # flag_name ); flags <<= 1; }
#define ADD_CLASS_EXPR_FLAG(flag_name) \
{ if (flags >> CLEAROUT) lto_debug_token (context, " " # flag_name ); flags <<= 1; }
+#define ADD_CLASS_TYPE_FLAG(flag_name) \
+ { if (flags >> CLEAROUT) lto_debug_token (context, " " # flag_name ); flags <<= 1; }
#define END_CLASS_CASE(class) break;
#define END_CLASS_SWITCH() \
default: \
@@ -2199,12 +2171,16 @@ lto_debug_tree_flags (struct lto_debug_context *context,
#define START_EXPR_CASE(code) case code:
#define ADD_EXPR_FLAG(flag_name) \
{ if (flags >> CLEAROUT) lto_debug_token (context, " " # flag_name ); flags <<= 1; }
+#define ADD_TYPE_FLAG(flag_name) \
+ { if (flags >> CLEAROUT) lto_debug_token (context, " " # flag_name ); flags <<= 1; }
#define ADD_DECL_FLAG(flag_name) \
{ if (flags >> CLEAROUT) lto_debug_token (context, " " # flag_name ); flags <<= 1; }
#define ADD_VIS_FLAG(flag_name) \
{ if (flags >> CLEAROUT) lto_debug_token (context, " " # flag_name ); flags <<= 1; }
#define ADD_VIS_FLAG_SIZE(flag_name,size) \
{ if (flags >> (BITS_PER_LTO_FLAGS_TYPE - size)) lto_debug_token (context, " " # flag_name ); flags <<= size; }
+#define ADD_FUN_FLAG(flag_name) \
+ { if (flags >> CLEAROUT) lto_debug_token (context, " " # flag_name ); flags <<= 1; }
#define END_EXPR_CASE(class) break;
#define END_EXPR_SWITCH() \
default: \
@@ -2218,14 +2194,964 @@ lto_debug_tree_flags (struct lto_debug_context *context,
#undef START_CLASS_CASE
#undef ADD_CLASS_DECL_FLAG
#undef ADD_CLASS_EXPR_FLAG
+#undef ADD_CLASS_TYPE_FLAG
#undef END_CLASS_CASE
#undef END_CLASS_SWITCH
#undef START_EXPR_SWITCH
#undef START_EXPR_CASE
#undef ADD_EXPR_FLAG
+#undef ADD_TYPE_FLAG
#undef ADD_DECL_FLAG
#undef ADD_VIS_FLAG
+#undef ADD_FUN_FLAG
#undef END_EXPR_CASE
#undef END_EXPR_SWITCH
}
#endif
+
+
+/* ### Serialization of global types and declarations. */
+
+void output_tree (struct output_block *, tree);
+void output_type_tree (struct output_block *, tree);
+
+/* Output the start of a record with TAG and possibly flags for EXPR,
+ and the TYPE for VALUE to OB. */
+
+/* ### Use output_type_tree instead of output_type_ref. */
+
+static void
+output_global_record_start (struct output_block *ob, tree expr,
+ tree value, unsigned int tag)
+{
+ lto_output_1_stream (ob->main_stream, tag);
+ LTO_DEBUG_INDENT (tag);
+ if (expr)
+ {
+ enum tree_code code = TREE_CODE (expr);
+ if (value
+ && TEST_BIT (lto_types_needed_for, code)
+ && TREE_TYPE (value))
+ output_type_tree (ob, TREE_TYPE (value));
+ output_tree_flags (ob, code, expr, false);
+ }
+}
+
+static void
+output_field_decl (struct output_block *ob, tree decl)
+{
+ /* tag and flags */
+ output_global_record_start (ob, NULL, NULL, LTO_field_decl);
+ output_tree_flags (ob, 0, decl, true);
+
+ /* uid and locus are handled specially */
+ output_tree (ob, decl->decl_minimal.name);
+ output_tree (ob, decl->decl_minimal.context);
+
+ output_tree (ob, decl->common.type);
+
+ output_tree (ob, decl->decl_common.attributes);
+ output_tree (ob, decl->decl_common.abstract_origin);
+
+ output_uleb128 (ob, decl->decl_common.mode);
+ output_uleb128 (ob, decl->decl_common.align);
+ output_uleb128 (ob, decl->decl_common.off_align);
+
+ output_tree (ob, decl->decl_common.size);
+ output_tree (ob, decl->decl_common.size_unit);
+
+ output_tree (ob, decl->field_decl.offset);
+ output_tree (ob, decl->field_decl.bit_field_type);
+ output_tree (ob, decl->field_decl.qualifier);
+ output_tree (ob, decl->field_decl.bit_offset);
+ output_tree (ob, decl->field_decl.fcontext);
+
+ /* lang_specific */
+
+ output_tree (ob, decl->decl_common.initial);
+
+ /* Write out current field before its siblings,
+ so follow the chain last. */
+ output_tree (ob, decl->common.chain);
+}
+
+static void
+output_function_decl (struct output_block *ob, tree decl)
+{
+ /* tag and flags */
+ output_global_record_start (ob, NULL, NULL, LTO_function_decl);
+ output_tree_flags (ob, 0, decl, true);
+
+ /* uid and locus are handled specially */
+ output_tree (ob, decl->decl_minimal.name);
+ output_tree (ob, decl->decl_minimal.context);
+
+ output_tree (ob, decl->decl_with_vis.assembler_name);
+ output_tree (ob, decl->decl_with_vis.section_name);
+
+ /* omit chain, which would result in writing all functions */
+ output_tree (ob, decl->common.type);
+
+ output_tree (ob, decl->decl_common.attributes);
+ output_tree (ob, decl->decl_common.abstract_origin);
+
+ output_uleb128 (ob, decl->decl_common.mode);
+ output_uleb128 (ob, decl->decl_common.align);
+ gcc_assert (decl->decl_common.off_align == 0);
+
+ output_tree (ob, decl->decl_common.size);
+ output_tree (ob, decl->decl_common.size_unit);
+
+ /* lang_specific */
+
+ /* omit rtl */
+
+ /* saved_tree -- this is a function body, so omit it here */
+ output_tree (ob, decl->decl_non_common.arguments);
+ output_tree (ob, decl->decl_non_common.result);
+ output_tree (ob, decl->decl_non_common.vindex);
+
+ /* omit initial -- should be written with body */
+}
+
+static void
+output_var_decl (struct output_block *ob, tree decl)
+{
+ /* tag and flags */
+ /* Assume static or external variable. */
+ output_global_record_start (ob, NULL, NULL, LTO_var_decl1);
+ output_tree_flags (ob, 0, decl, true);
+
+ /* uid and locus are handled specially */
+ output_tree (ob, decl->decl_minimal.name);
+ output_tree (ob, decl->decl_minimal.context);
+
+ LTO_DEBUG_TOKEN ("var_decl_assembler_name");
+ output_tree (ob, decl->decl_with_vis.assembler_name);
+ output_tree (ob, decl->decl_with_vis.section_name);
+
+ /* omit chain */
+ output_tree (ob, decl->common.type);
+
+ output_tree (ob, decl->decl_common.attributes);
+ output_tree (ob, decl->decl_common.abstract_origin);
+
+ output_uleb128 (ob, decl->decl_common.mode);
+ output_uleb128 (ob, decl->decl_common.align);
+ gcc_assert (decl->decl_common.off_align == 0);
+
+ LTO_DEBUG_TOKEN ("var_decl_size");
+ output_tree (ob, decl->decl_common.size);
+ output_tree (ob, decl->decl_common.size_unit);
+
+ /* lang_specific */
+
+ /* omit rtl */
+
+ /* DECL_DEBUG_EXPR is stored in a table on the side,
+ not in the VAR_DECL node itself. */
+ LTO_DEBUG_TOKEN ("var_decl_debug_expr");
+ output_tree (ob, DECL_DEBUG_EXPR (decl));
+
+ /* Write initial expression last. */
+ output_tree (ob, decl->decl_common.initial);
+
+ LTO_DEBUG_TOKEN ("var_decl_END");
+}
+
+static void
+output_parm_decl (struct output_block *ob, tree decl)
+{
+ /* tag and flags */
+ output_global_record_start (ob, NULL, NULL, LTO_parm_decl);
+ output_tree_flags (ob, 0, decl, true);
+
+ /* uid and locus are handled specially */
+ output_tree (ob, decl->decl_minimal.name);
+ output_tree (ob, decl->decl_minimal.context);
+
+ output_tree (ob, decl->common.type);
+
+ output_tree (ob, decl->decl_common.attributes);
+ output_tree (ob, decl->decl_common.abstract_origin);
+
+ output_uleb128 (ob, decl->decl_common.mode);
+ output_uleb128 (ob, decl->decl_common.align);
+ gcc_assert (decl->decl_common.off_align == 0);
+
+ output_tree (ob, decl->decl_common.size);
+ output_tree (ob, decl->decl_common.size_unit);
+
+ output_tree (ob, decl->decl_common.initial); /* ### redundant? */
+
+ /* lang_specific */
+ /* omit rtl, incoming_rtl */
+
+ output_tree (ob, decl->common.chain);
+}
+
+static void
+output_result_decl (struct output_block *ob, tree decl)
+{
+ /* tag and flags */
+ output_global_record_start (ob, NULL, NULL, LTO_result_decl);
+ output_tree_flags (ob, 0, decl, true);
+
+ /* uid and locus are handled specially */
+ output_tree (ob, decl->decl_minimal.name);
+ output_tree (ob, decl->decl_minimal.context);
+
+ output_tree (ob, decl->common.type);
+
+ output_tree (ob, decl->decl_common.attributes);
+ output_tree (ob, decl->decl_common.abstract_origin);
+
+ output_uleb128 (ob, decl->decl_common.mode);
+ output_uleb128 (ob, decl->decl_common.align);
+ gcc_assert (decl->decl_common.off_align == 0);
+
+ output_tree (ob, decl->decl_common.size);
+ output_tree (ob, decl->decl_common.size_unit);
+
+ /* lang_specific */
+ /* omit rtl */
+
+ output_tree (ob, decl->decl_common.initial); /* ### make sense for result? */
+
+ gcc_assert (!decl->common.chain);
+}
+
+static void
+output_type_decl (struct output_block *ob, tree decl)
+{
+ /* tag and flags */
+ output_global_record_start (ob, NULL, NULL, LTO_type_decl);
+ output_tree_flags (ob, 0, decl, true);
+
+ /* uid and locus are handled specially */
+ /* ### Must go before type. */
+ output_tree (ob, decl->decl_minimal.name);
+ output_tree (ob, decl->decl_minimal.context);
+
+ output_tree (ob, decl->decl_with_vis.assembler_name);
+ output_tree (ob, decl->decl_with_vis.section_name);
+
+ output_tree (ob, decl->common.type);
+
+ output_tree (ob, decl->decl_common.attributes);
+ output_tree (ob, decl->decl_common.abstract_origin);
+
+ gcc_assert (decl->decl_common.mode == 0);
+ output_uleb128 (ob, decl->decl_common.align);
+
+ output_tree (ob, decl->decl_common.size); /* ??? */
+ output_tree (ob, decl->decl_common.size_unit); /* ??? */
+
+ /* lang_specific */
+
+ gcc_assert (decl->decl_with_rtl.rtl == NULL);
+
+ output_tree (ob, decl->decl_common.initial); /* ??? */
+
+ output_tree (ob, decl->decl_non_common.saved_tree); /* ??? */
+ output_tree (ob, decl->decl_non_common.arguments); /* ??? */
+ output_tree (ob, decl->decl_non_common.result);
+ output_tree (ob, decl->decl_non_common.vindex); /* ??? */
+}
+
+static void
+output_namespace_decl (struct output_block *ob, tree decl)
+{
+ /* tag and flags */
+ output_global_record_start (ob, NULL, NULL, LTO_namespace_decl);
+ output_tree_flags (ob, 0, decl, true);
+
+ /* uid and locus are handled specially */
+ output_tree (ob, decl->decl_minimal.name);
+ output_tree (ob, decl->decl_minimal.context);
+
+ output_tree (ob, decl->decl_with_vis.assembler_name);
+ output_tree (ob, decl->decl_with_vis.section_name);
+
+ gcc_assert (decl->common.type == NULL_TREE);
+
+ output_tree (ob, decl->decl_common.attributes);
+ output_tree (ob, decl->decl_common.abstract_origin);
+
+ gcc_assert (decl->decl_common.mode == 0);
+ gcc_assert (decl->decl_common.align == 0);
+
+ gcc_assert (decl->decl_common.size == NULL_TREE);
+ gcc_assert (decl->decl_common.size_unit == NULL_TREE);
+
+ /* lang_specific */
+
+ gcc_assert (decl->decl_with_rtl.rtl == NULL);
+
+ output_tree (ob, decl->decl_non_common.saved_tree); /* ??? */
+ gcc_assert (decl->decl_non_common.arguments == NULL_TREE); /* ??? */
+ gcc_assert (decl->decl_non_common.result == NULL_TREE); /* ??? */
+ output_tree (ob, decl->decl_non_common.vindex);
+
+ /* omit chain */
+}
+
+static void
+output_translation_unit_decl (struct output_block *ob, tree decl)
+{
+ /* tag and flags */
+ output_global_record_start (ob, NULL, NULL, LTO_translation_unit_decl);
+ output_tree_flags (ob, 0, decl, true);
+
+ /* uid and locus are handled specially */
+ output_tree (ob, decl->decl_minimal.name);
+ output_tree (ob, decl->decl_minimal.context);
+
+ output_tree (ob, decl->decl_with_vis.assembler_name);
+ output_tree (ob, decl->decl_with_vis.section_name);
+
+ output_tree (ob, decl->common.type);
+
+ gcc_assert (decl->decl_common.attributes == NULL_TREE);
+ output_tree (ob, decl->decl_common.abstract_origin);
+
+ gcc_assert (decl->decl_common.mode == 0);
+ output_uleb128 (ob, decl->decl_common.align);
+
+ gcc_assert (decl->decl_common.size == NULL_TREE);
+ gcc_assert (decl->decl_common.size_unit == NULL_TREE);
+ /* ### omit initial for now -- I think it is covered elsewhere */
+
+ gcc_assert (decl->decl_with_rtl.rtl == NULL);
+
+ /* omit chain */
+}
+
+static void
+output_binfo (struct output_block *ob, tree binfo)
+{
+ size_t i;
+ size_t num_base_accesses = VEC_length (tree, binfo->binfo.base_accesses);
+ size_t num_base_binfos = VEC_length (tree, &binfo->binfo.base_binfos);
+
+ output_global_record_start (ob, NULL, NULL, LTO_tree_binfo);
+ output_tree_flags (ob, 0, binfo, false);
+
+ output_uleb128 (ob, num_base_accesses);
+ output_uleb128 (ob, num_base_binfos);
+
+ /* need flags */
+ output_tree (ob, binfo->common.type);
+
+ output_tree (ob, binfo->binfo.offset);
+ output_tree (ob, binfo->binfo.vtable);
+ output_tree (ob, binfo->binfo.virtuals);
+ output_tree (ob, binfo->binfo.vptr_field);
+ output_tree (ob, binfo->binfo.inheritance);
+ output_tree (ob, binfo->binfo.vtt_subvtt);
+ output_tree (ob, binfo->binfo.vtt_vptr);
+
+ LTO_DEBUG_TOKEN ("base_accesses");
+ for (i = 0; i < num_base_accesses; ++i)
+ output_tree (ob, VEC_index (tree, binfo->binfo.base_accesses, i));
+
+ LTO_DEBUG_TOKEN ("base_binfos");
+ for (i = 0; i < num_base_binfos; ++i)
+ output_tree (ob, VEC_index (tree, &binfo->binfo.base_binfos, i));
+
+ output_tree (ob, binfo->common.chain);
+}
+
+static void
+output_type (struct output_block *ob, tree type, enum LTO_tags tag)
+{
+ /* tag and flags */
+ output_global_record_start (ob, NULL, NULL, tag);
+ output_tree_flags (ob, 0, type, false);
+
+ LTO_DEBUG_TOKEN ("type");
+ output_tree (ob, type->common.type);
+ LTO_DEBUG_TOKEN ("size");
+ output_tree (ob, type->type.size);
+ LTO_DEBUG_TOKEN ("size_unit");
+ output_tree (ob, type->type.size_unit);
+ LTO_DEBUG_TOKEN ("attributes");
+ output_tree (ob, type->type.attributes);
+ LTO_DEBUG_TOKEN ("uid");
+ output_uleb128 (ob, type->type.uid);
+ LTO_DEBUG_TOKEN ("precision");
+ output_uleb128 (ob, type->type.precision);
+ LTO_DEBUG_TOKEN ("mode");
+ output_uleb128 (ob, type->type.mode);
+ LTO_DEBUG_TOKEN ("align");
+ output_uleb128 (ob, type->type.align);
+ LTO_DEBUG_TOKEN ("pointer_to");
+ output_tree (ob, type->type.pointer_to);
+ LTO_DEBUG_TOKEN ("reference_to");
+ output_tree (ob, type->type.reference_to);
+ /* ### Output symtab here. Do we need it? */
+ LTO_DEBUG_TOKEN ("name");
+ output_tree (ob, type->type.name); /* may be a TYPE_DECL */
+ LTO_DEBUG_TOKEN ("minval");
+ output_tree (ob, type->type.minval);
+ LTO_DEBUG_TOKEN ("maxval");
+ output_tree (ob, type->type.maxval);
+ LTO_DEBUG_TOKEN ("next_variant");
+ output_tree (ob, type->type.next_variant);
+ LTO_DEBUG_TOKEN ("main_variant");
+ output_tree (ob, type->type.main_variant);
+ LTO_DEBUG_TOKEN ("binfo");
+ output_tree (ob, type->type.binfo);
+ LTO_DEBUG_TOKEN ("context");
+ output_tree (ob, type->type.context);
+ LTO_DEBUG_TOKEN ("canonical");
+ output_tree (ob, type->type.canonical);
+
+ /* Slot 'values' may be the structures fields, so do them last,
+ after other slots of the structure type have been filled in. */
+ LTO_DEBUG_TOKEN ("values");
+ if (TYPE_CACHED_VALUES_P (type))
+ {
+ gcc_assert (tag != RECORD_TYPE
+ && tag != UNION_TYPE
+ && tag != ARRAY_TYPE);
+ /* Don't stream the values cache. We must clear flag
+ TYPE_CACHED_VALUES_P on input. We don't do it here
+ because we don't want to clobber the tree as we write
+ it, and there is no infrastructure for modifying
+ flags as we serialize them. */
+ output_zero (ob);
+ }
+ else
+ output_tree (ob, type->type.values); /* should be a TREE_VEC */
+
+ LTO_DEBUG_TOKEN ("chain");
+ output_tree (ob, type->common.chain); /* overloaded as TYPE_STUB_DECL */
+}
+
+/* ### Use output_tree_operand */
+/* Output constructor CTOR to OB. */
+
+static void
+output_global_constructor (struct output_block *ob, tree ctor)
+{
+ tree value;
+ tree purpose;
+ unsigned HOST_WIDE_INT idx;
+
+ output_global_record_start (ob, ctor, ctor, LTO_constructor);
+ output_uleb128 (ob, VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
+
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
+ {
+ if (purpose)
+ output_tree (ob, purpose);
+ else
+ output_zero (ob);
+
+ if (TREE_CODE (value) == CONSTRUCTOR)
+ {
+ output_global_constructor (ob, value);
+ LTO_DEBUG_UNDENT ();
+ }
+ else
+ output_tree (ob, value);
+ }
+}
+
+void
+output_tree (struct output_block *ob, tree expr)
+{
+ enum tree_code code;
+ enum tree_code_class class;
+ unsigned int tag;
+
+ if (expr == NULL_TREE)
+ {
+ output_zero (ob);
+ return;
+ }
+
+#ifdef GLOBAL_STREAMER_TRACE
+ fprintf (stderr, "%p : ", expr);
+ print_generic_expr (stderr, expr, 0);
+ fprintf (stderr, "\n");
+#endif
+
+ if (TYPE_P (expr) || DECL_P (expr) || TREE_CODE (expr) == TREE_BINFO)
+ {
+ void **slot;
+ struct lto_decl_slot d_slot;
+ unsigned int global_index;
+ struct lto_decl_slot *new_slot;
+
+ /* If we've already pickled this node, emit a reference.
+ Otherwise, assign an index for the node we are about to emit. */
+
+ d_slot.t = expr;
+ slot = htab_find_slot (ob->main_hash_table, &d_slot, INSERT);
+ if (*slot != NULL)
+ {
+ struct lto_decl_slot *old_slot = (struct lto_decl_slot *)*slot;
+#ifdef GLOBAL_STREAMER_TRACE
+ fprintf (stderr, "%p -> OLD %d\n", expr, old_slot->slot_num);
+#endif
+ output_global_record_start (ob, NULL, NULL, LTO_tree_pickle_reference);
+ output_uleb128 (ob, old_slot->slot_num);
+ LTO_DEBUG_UNDENT ();
+ return;
+ }
+
+ global_index = ob->next_main_index++;
+ new_slot = xmalloc (sizeof (struct lto_decl_slot));
+ new_slot->t = expr;
+ new_slot->slot_num = global_index;
+ *slot = new_slot;
+
+#ifdef GLOBAL_STREAMER_TRACE
+ fprintf (stderr, "%p -> NEW %d\n", expr, new_slot->slot_num);
+#endif
+ }
+
+ code = TREE_CODE (expr);
+ class = TREE_CODE_CLASS (code);
+ tag = expr_to_tag [code];
+
+ switch (code)
+ {
+ case COMPLEX_CST:
+ if (TREE_CODE (TREE_REALPART (expr)) == REAL_CST)
+ {
+ output_global_record_start (ob, expr, expr, LTO_complex_cst1);
+ output_type_tree (ob, TREE_TYPE (TREE_REALPART (expr)));
+ output_real (ob, TREE_REALPART (expr));
+ output_real (ob, TREE_IMAGPART (expr));
+ }
+ else
+ {
+ output_global_record_start (ob, expr, expr, LTO_complex_cst0);
+ output_type_tree (ob, TREE_TYPE (TREE_REALPART (expr)));
+ output_integer (ob, TREE_REALPART (expr));
+ output_integer (ob, TREE_IMAGPART (expr));
+ }
+ break;
+
+ case INTEGER_CST:
+ output_global_record_start (ob, expr, expr, tag);
+ output_integer (ob, expr);
+ break;
+
+ case REAL_CST:
+ output_global_record_start (ob, expr, expr, tag);
+ output_real (ob, expr);
+ break;
+
+ case STRING_CST:
+ {
+ /* Most STRING_CSTs have a type when they get here. The ones
+ in the string operands of asms do not. Put something there
+ so that all STRING_CSTs can be handled uniformly. */
+ if (!TREE_TYPE (expr))
+ TREE_TYPE (expr) = void_type_node;
+
+ output_global_record_start (ob, expr, expr, LTO_string_cst);
+ output_string (ob, ob->main_stream,
+ TREE_STRING_POINTER (expr),
+ TREE_STRING_LENGTH (expr));
+ }
+ break;
+
+ case IDENTIFIER_NODE:
+ {
+ output_global_record_start (ob, expr, expr, LTO_identifier_node);
+ output_string (ob, ob->main_stream,
+ IDENTIFIER_POINTER (expr),
+ IDENTIFIER_LENGTH (expr));
+ }
+ break;
+
+
+ case VECTOR_CST:
+ {
+ tree t = TREE_VECTOR_CST_ELTS (expr);
+ int len = 1;
+
+ while ((t = TREE_CHAIN (t)) != NULL)
+ len++;
+ t = TREE_VECTOR_CST_ELTS (expr);
+ if (TREE_CODE (TREE_VALUE(t)) == REAL_CST)
+ {
+ output_global_record_start (ob, expr, expr, LTO_vector_cst1);
+ output_uleb128 (ob, len);
+ output_type_tree (ob, TREE_TYPE (TREE_VALUE (t)));
+ output_real (ob, TREE_VALUE (t));
+ while ((t = TREE_CHAIN (t)) != NULL)
+ output_real (ob, TREE_VALUE (t));
+ }
+ else
+ {
+ output_global_record_start (ob, expr, expr, LTO_vector_cst0);
+ output_uleb128 (ob, len);
+ output_type_tree (ob, TREE_TYPE (TREE_VALUE (t)));
+ output_integer (ob, TREE_VALUE (t));
+ while ((t = TREE_CHAIN (t)) != NULL)
+ output_integer (ob, TREE_VALUE (t));
+ }
+ }
+ break;
+
+ case CASE_LABEL_EXPR:
+ /* ### We should not be seeing case labels here. */
+ gcc_unreachable ();
+
+ case CONSTRUCTOR:
+ output_global_constructor (ob, expr);
+ break;
+
+ case SSA_NAME:
+ /* ### I'm not sure SSA_NAME nodes make sense here. */
+ gcc_unreachable ();
+ /*
+ output_global_record_start (ob, expr, expr, LTO_ssa_name);
+ output_uleb128 (ob, SSA_NAME_VERSION (expr));
+ */
+ break;
+
+ case CONST_DECL:
+ /* Just ignore these, Mark will make them disappear. */
+ break;
+
+ case FIELD_DECL:
+ output_field_decl (ob, expr);
+ break;
+
+ case FUNCTION_DECL:
+ output_function_decl (ob, expr);
+ break;
+
+ case VAR_DECL:
+ if (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
+ output_var_decl (ob, expr);
+ else
+ /* We should not be seeing local variables here. */
+ gcc_unreachable ();
+ break;
+
+ case PARM_DECL:
+ output_parm_decl (ob, expr);
+ break;
+
+ case RESULT_DECL:
+ output_result_decl (ob, expr);
+ break;
+
+ case TYPE_DECL:
+ output_type_decl (ob, expr);
+ break;
+
+ case NAMESPACE_DECL:
+ output_namespace_decl (ob, expr);
+ break;
+
+ case TRANSLATION_UNIT_DECL:
+ output_translation_unit_decl (ob, expr);
+ break;
+
+ case LABEL_DECL:
+ case LABEL_EXPR:
+ /* ### These should occur only within a function body. */
+ gcc_unreachable ();
+
+ case COND_EXPR:
+ if (TREE_OPERAND (expr, 1))
+ {
+ output_global_record_start (ob, expr, expr, LTO_cond_expr0);
+ output_tree (ob, TREE_OPERAND (expr, 0));
+ output_tree (ob, TREE_OPERAND (expr, 1));
+ output_tree (ob, TREE_OPERAND (expr, 2));
+ }
+ else
+ {
+ output_global_record_start (ob, expr, expr, LTO_cond_expr1);
+ output_tree (ob, TREE_OPERAND (expr, 0));
+ }
+ break;
+
+ case COMPONENT_REF:
+ output_global_record_start (ob, expr, expr, tag);
+ output_tree (ob, TREE_OPERAND (expr, 0));
+ output_tree (ob, TREE_OPERAND (expr, 1));
+ /* Ignore 3 because it can be recomputed. */
+ break;
+
+ case CALL_EXPR:
+ {
+ unsigned int count = TREE_INT_CST_LOW (TREE_OPERAND (expr, 0));
+ unsigned int i;
+
+ /* Operand 2 is the call chain. */
+ if (TREE_OPERAND (expr, 2))
+ {
+ output_global_record_start (ob, expr, expr, LTO_call_expr1);
+ output_uleb128 (ob, count);
+ output_tree (ob, TREE_OPERAND (expr, 2));
+ }
+ else
+ {
+ output_global_record_start (ob, expr, expr, LTO_call_expr0);
+ output_uleb128 (ob, count);
+ }
+ output_tree (ob, TREE_OPERAND (expr, 1));
+ for (i = 3; i < count; i++)
+ output_tree (ob, TREE_OPERAND (expr, i));
+ }
+ break;
+
+ case BIT_FIELD_REF:
+ {
+ tree op1 = TREE_OPERAND (expr, 1);
+ tree op2 = TREE_OPERAND (expr, 2);
+ if ((TREE_CODE (op1) == INTEGER_CST)
+ && (TREE_CODE (op2) == INTEGER_CST))
+ {
+ output_global_record_start (ob, expr, expr,
+ LTO_bit_field_ref1);
+ output_uleb128 (ob, TREE_INT_CST_LOW (op1));
+ output_uleb128 (ob, TREE_INT_CST_LOW (op2));
+ output_tree (ob, TREE_OPERAND (expr, 0));
+ }
+ else
+ {
+ output_global_record_start (ob, expr, expr,
+ LTO_bit_field_ref0);
+ output_tree (ob, TREE_OPERAND (expr, 0));
+ output_tree (ob, op1);
+ output_tree (ob, op2);
+ }
+ }
+ break;
+
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ /* Ignore operands 2 and 3 for ARRAY_REF and ARRAY_RANGE REF
+ because they can be recomputed. */
+ array_ref_low_bound (expr); /* ### DEBUG -- test for well-formedness */
+ output_global_record_start (ob, expr, expr, tag);
+ output_tree (ob, TREE_OPERAND (expr, 0));
+ output_tree (ob, TREE_OPERAND (expr, 1));
+ break;
+
+
+ case ASM_EXPR:
+ {
+ tree string_cst = ASM_STRING (expr);
+ output_global_record_start (ob, expr, NULL, LTO_asm_expr);
+ output_string (ob, ob->main_stream,
+ TREE_STRING_POINTER (string_cst),
+ TREE_STRING_LENGTH (string_cst));
+ if (ASM_INPUTS (expr))
+ output_tree (ob, ASM_INPUTS (expr));
+ else
+ output_zero (ob);
+
+ if (ASM_OUTPUTS (expr))
+ output_tree (ob, ASM_OUTPUTS (expr));
+ else
+ output_zero (ob);
+
+ if (ASM_CLOBBERS (expr))
+ output_tree (ob, ASM_CLOBBERS (expr));
+ else
+ output_zero (ob);
+ }
+ break;
+
+ case RANGE_EXPR:
+ {
+ output_global_record_start (ob, NULL, NULL, LTO_range_expr);
+ /* Need the types here to reconstruct the ranges. */
+ output_type_tree (ob, TREE_OPERAND (expr, 0));
+ output_integer (ob, TREE_OPERAND (expr, 0));
+ output_type_tree (ob, TREE_OPERAND (expr, 1));
+ output_integer (ob, TREE_OPERAND (expr, 1));
+ }
+ break;
+
+ case RESX_EXPR:
+ output_global_record_start (ob, expr, NULL, tag);
+ output_uleb128 (ob, TREE_INT_CST_LOW (TREE_OPERAND (expr, 0)));
+ break;
+
+ case RETURN_EXPR:
+ {
+ tree t = TREE_OPERAND (expr, 0);
+ if (t == NULL)
+ {
+ /* Form return. */
+ output_global_record_start (ob, expr, expr,
+ LTO_return_expr0);
+ }
+ else if (TREE_CODE (t) == MODIFY_EXPR)
+ {
+ /* Form return a = b; */
+ output_global_record_start (ob, expr, expr,
+ LTO_return_expr2);
+ output_tree (ob, TREE_OPERAND (t, 0));
+ output_tree (ob, TREE_OPERAND (t, 1));
+ }
+ else
+ {
+ /* Form return a; */
+ output_global_record_start (ob, expr, expr,
+ LTO_return_expr1);
+ /* If the type of the argument is a type that gets returned
+ in memory, then the gimplifier would have changed the
+ argument of the RETURN_EXPR to point at DECL_RESULT of
+ the current function. Communicate this fact to the
+ reader so we avoid reading in superfluous trees. */
+ if (t == DECL_RESULT (current_function_decl))
+ output_zero (ob);
+ else
+ output_tree (ob, t);
+ }
+ }
+ break;
+
+ case GIMPLE_MODIFY_STMT:
+ output_global_record_start (ob, expr, NULL, tag);
+ output_tree (ob, GIMPLE_STMT_OPERAND (expr, 0));
+ output_tree (ob, GIMPLE_STMT_OPERAND (expr, 1));
+ break;
+
+ case SWITCH_EXPR:
+ /* ### We shouldn't see these here. */
+ gcc_unreachable ();
+
+ case TREE_LIST:
+ {
+ tree tl;
+ int count = 0;
+
+ output_global_record_start (ob, expr, NULL, tag);
+ for (tl = expr; tl; tl = TREE_CHAIN (tl))
+ count++;
+
+ gcc_assert (count);
+ output_uleb128 (ob, count);
+ for (tl = expr; tl; tl = TREE_CHAIN (tl))
+ {
+ if (TREE_VALUE (tl) != NULL_TREE)
+ output_tree (ob, TREE_VALUE (tl));
+ else
+ output_zero (ob);
+
+ if (TREE_PURPOSE (tl))
+ output_tree (ob, TREE_PURPOSE (tl));
+ else
+ output_zero (ob);
+ }
+ }
+ break;
+
+ case TREE_VEC:
+ {
+ size_t i;
+ size_t len = TREE_VEC_LENGTH (expr);
+
+ output_global_record_start (ob, NULL, NULL, tag);
+ output_uleb128 (ob, len);
+ for (i = 0; i < len; ++i)
+ output_tree (ob, TREE_VEC_ELT (expr, i));
+ }
+ break;
+
+ case ERROR_MARK:
+ /* The canonical error node is preloaded,
+ so we should never see another one here. */
+ gcc_unreachable ();
+
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case FIXED_POINT_TYPE:
+ case COMPLEX_TYPE:
+ case BOOLEAN_TYPE:
+ case OFFSET_TYPE:
+ case ENUMERAL_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case VECTOR_TYPE:
+ case ARRAY_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ output_type (ob, expr, tag);
+ break;
+
+ case LANG_TYPE:
+ /* FIXME */
+ gcc_unreachable ();
+
+ case TREE_BINFO:
+ output_binfo (ob, expr);
+ break;
+
+ /* This is the default case. All of the cases that can be done
+ completely mechanically are done here. */
+ {
+ int i;
+#define SET_NAME(a,b)
+#define MAP_EXPR_TAG(expr, tag) case expr:
+#define TREE_SINGLE_MECHANICAL_TRUE
+
+#include "lto-tree-tags.def"
+#undef MAP_EXPR_TAG
+#undef TREE_SINGLE_MECHANICAL_TRUE
+#undef SET_NAME
+ output_global_record_start (ob, expr, expr, tag);
+ for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (expr)); i++)
+ output_tree (ob, TREE_OPERAND (expr, i));
+ break;
+ }
+
+ /* This is the error case, these are type codes that will either
+ never happen or that we have not gotten around to dealing
+ with are here. */
+ case BIND_EXPR:
+ case BLOCK:
+ case CATCH_EXPR:
+ case EH_FILTER_EXPR:
+ case NAME_MEMORY_TAG:
+ case OMP_CONTINUE:
+ case OMP_CRITICAL:
+ case OMP_FOR:
+ case OMP_MASTER:
+ case OMP_ORDERED:
+ case OMP_PARALLEL:
+ case OMP_RETURN:
+ case OMP_SECTIONS:
+ case OMP_SINGLE:
+ case SYMBOL_MEMORY_TAG:
+ case TARGET_MEM_REF:
+ case TRY_CATCH_EXPR:
+ case TRY_FINALLY_EXPR:
+ default:
+ /* We cannot have forms that are not explicity handled. So when
+ this is triggered, there is some form that is not being
+ output. */
+ gcc_unreachable ();
+ }
+
+ LTO_DEBUG_UNDENT ();
+}
+
+/* ### Replacement for output_type_ref when serializing globals. */
+void
+output_type_tree (struct output_block *ob, tree type)
+{
+ LTO_DEBUG_TOKEN ("type");
+ gcc_assert (type && TYPE_P (type));
+ output_tree (ob, type);
+}
diff --git a/gcc/lto-section-in.c b/gcc/lto-section-in.c
index 076fded6da2..a09879614fe 100644
--- a/gcc/lto-section-in.c
+++ b/gcc/lto-section-in.c
@@ -266,7 +266,7 @@ dump_debug_stream (struct lto_input_block *stream,
int chars = 0;
int hit_pos = -1;
fprintf (stderr,
- "stream failure: looking for a '%c'[0x%x] in the %s debug stream.\nHowever the data translated into a '%c'[0x%x]at position%d\n\n",
+ "stream failure: looking for a '%c'[0x%x] in the %s debug stream.\nHowever the data translated into a '%c'[0x%x]at position %d\n\n",
c, c, stream_name, b, b, stream->p);
while (i < stream->len)
diff --git a/gcc/lto-section-in.h b/gcc/lto-section-in.h
index 969b01e9db8..ebd17db44e8 100644
--- a/gcc/lto-section-in.h
+++ b/gcc/lto-section-in.h
@@ -74,29 +74,6 @@ struct lto_file_decl_data
htab_t section_hash_table;
};
-
-/* lto-function-in.c */
-
-/* FN is a FUNCTION_DECL. DATA is the LTO data written out during
- ordinary compilation, encoding the body of FN. FILE_DATA are the
- tables holding all of the global types and decls used by FN. Upon
- return, DECL_SAVED_TREE for FN contains the reconstituted body of
- FN and DECL_INITIAL contains the BLOCK tree for the function.
- However, it is not this function's responsibility to provide FN to
- the optimizers or code-generators; that will be done by the
- caller. */
-extern void
-lto_input_function_body (struct lto_file_decl_data* file_data,
- tree fn, const char *data);
-
-/* DATA is the LTO data written out during ordinary compilation,
- encoding the initializers for the static and external vars.
- FILE_DATA are the tables holding all of the global types and decls
- used in that file. */
-extern void
-lto_input_constructors_and_inits (struct lto_file_decl_data* file_data,
- const char *data);
-
/* DATA is the LTO data written out during ordinary compilation,
encoding the initializers for the static and external vars.
FILE_DATA are the tables holding all of the global types and decls
diff --git a/gcc/lto-section-out.c b/gcc/lto-section-out.c
index fd7c1c98c82..68d1c636d14 100644
--- a/gcc/lto-section-out.c
+++ b/gcc/lto-section-out.c
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
#include "output.h"
#include "lto-section.h"
#include "lto-section-out.h"
+#include "lto-tree-out.h"
#include <ctype.h>
@@ -100,6 +101,32 @@ lto_eq_type_slot_node (const void *p1, const void *p2)
}
+/* ### */
+/* Returns a hash code for P. */
+
+hashval_t
+lto_hash_global_slot_node (const void *p)
+{
+ const struct lto_decl_slot *ds = (const struct lto_decl_slot *) p;
+ return (hashval_t) TREE_HASH (ds->t);
+}
+
+
+/* ### */
+/* Returns nonzero if P1 and P2 are equal. */
+
+int
+lto_eq_global_slot_node (const void *p1, const void *p2)
+{
+ const struct lto_decl_slot *ds1 =
+ (const struct lto_decl_slot *) p1;
+ const struct lto_decl_slot *ds2 =
+ (const struct lto_decl_slot *) p2;
+
+ return ds1->t == ds2->t;
+}
+
+
/* Get a section name for a particular type or name. The NAME field
is only used if SECTION_TYPE is LTO_section_function_body or
lto_static_initializer. For all others it is ignored. The callee
@@ -382,7 +409,6 @@ lto_output_decl_index (struct lto_output_stream * obs, htab_t table,
}
}
-
/*****************************************************************************/
/* This part is used to store all of the global decls and types that are */
/* serialized out in this file so that a table for this file can be built */
@@ -414,46 +440,158 @@ lto_get_out_decl_state (void)
return out_state;
}
-/* Write the references for the objects in V to section SEC in the
- assembly file. Use REF_FN to compute the reference. */
+/* ### */
+/* Assign an index to a tree and enter it into the global streamer hash table. */
+
+static void
+preload_common_node (struct output_block *ob, tree t)
+{
+ void **slot;
+ struct lto_decl_slot d_slot;
+
+ d_slot.t = t;
+ slot = htab_find_slot (ob->main_hash_table, &d_slot, INSERT);
+ /* If well-known trees are not unique, we don't create duplicate entries. */
+ if (*slot == NULL)
+ {
+ struct lto_decl_slot *new_slot = xmalloc (sizeof (struct lto_decl_slot));
+ unsigned index = ob->next_main_index++;
+ new_slot->t = t;
+ new_slot->slot_num = index;
+ *slot = new_slot;
+#ifdef GLOBAL_STREAMER_TRACE
+ fprintf (stderr, "preloaded 0x%x: ", index);
+ print_generic_expr (stderr, t, 0);
+ fprintf (stderr, "\n");
+#endif
+ }
+ else
+ /* Skip the index, which will leave an unused slot in the
+ globals vector in the reader. Otherwise, the reader
+ initialization must perform a similar duplicate-removal
+ process to reconstruct a valid vector. NOTE: This isn't
+ difficult. Perhaps we should just do it. */
+ ob->next_main_index++;
+}
+
+/* ### */
+/* Preload the streamer hash table with pointers to well-known objects
+ so that they will not be streamed out, and will be replaced with the
+ corresponding objects when streamed back in. */
+
+static void
+preload_common_nodes (struct output_block *ob)
+{
+ unsigned i;
+
+ for (i = 0; i < TI_MAX; i++)
+ preload_common_node (ob, global_trees[i]);
+ for (i = 0; i < itk_none; i++)
+ preload_common_node (ob, integer_types[i]);
+}
+
+/* ### */
+/* Write each node in vector V to OB, as well as those reachable
+ from it and required for correct representation of its semantics.
+ Each node in V must be a global declaration or a type. A node
+ is written only once, even if it appears multiple times in the
+ vector. Certain transitively-reachable nodes, such as those
+ representing expressions, may be duplicated, but such nodes
+ must not appear in V itself. */
static void
-write_references (VEC(tree,heap) *v, section *sec,
- void (*ref_fn) (tree, lto_out_ref *))
+write_global_stream (struct output_block *ob, VEC(tree,heap) *v)
{
+ tree t;
int index;
+
+ for (index = 0; VEC_iterate(tree, v, index, t); index++)
+ {
+ void *slot;
+ struct lto_decl_slot d_slot;
+
+ d_slot.t = t;
+ slot = htab_find_slot (ob->main_hash_table, &d_slot, NO_INSERT);
+ if (slot == NULL)
+ output_tree (ob, t);
+ }
+}
+
+/* ### */
+/* Write a sequence of indices into the globals vector corresponding
+ to the trees in vector V. These are used by the reader to map the
+ indices used to refer to global entities within function bodies to
+ their referents. */
+
+static void
+write_global_references (struct output_block *ob, VEC(tree,heap) *v)
+{
tree t;
- lto_out_ref out_ref = {0, NULL, NULL};
+ int index;
for (index = 0; VEC_iterate(tree, v, index, t); index++)
{
- ref_fn (t, &out_ref);
- /* We always call switch_to_section as the act of creating a
- handle we can reference may have dumped some bits into the
- assembly. */
- switch_to_section (sec);
- dw2_asm_output_data (8, out_ref.section, " ");
- dw2_asm_output_delta (8, out_ref.label, out_ref.base_label, " ");
+ void **slot;
+ struct lto_decl_slot d_slot;
+ struct lto_decl_slot *old_slot;
+
+ d_slot.t = t;
+ slot = htab_find_slot (ob->main_hash_table, &d_slot, NO_INSERT);
+ gcc_assert (slot);
+ old_slot = (struct lto_decl_slot *)*slot;
+#if 0
+ fprintf (stderr, "*** %d: ", old_slot->slot_num);
+ print_generic_expr (stderr, t, 0);
+ fprintf (stderr, "\n");
+#endif
+ /* We should use uleb128 for the global vector index.
+ This will require writing the reference vectors as streams. */
+ dw2_asm_output_data (4, old_slot->slot_num, " ");
}
}
+/* ### */
/* This pass is run after all of the functions are serialized and all
of the ipa passes have written their serialized forms. This pass
- cases the vector of all of the global decls and types used from
+ causes the vector of all of the global decls and types used from
this file to be written in to a section that can then be read in to
recover these on other side. */
+
static unsigned int
produce_asm_for_decls (void)
{
- struct lto_decl_header header;
- section *section = lto_get_section (LTO_section_decls, NULL);
+ extern struct output_block *create_output_block (enum lto_section_type);
+ extern void destroy_output_block (struct output_block *);
+
struct lto_out_decl_state *out_state = lto_get_out_decl_state ();
- memset (&header, 0, sizeof (struct lto_decl_header));
+ struct lto_decl_header header;
+ section *decl_section = lto_get_section (LTO_section_decls, NULL);
+ struct output_block *ob = create_output_block (LTO_section_decls);
+
+ ob->global = true;
+ ob->main_hash_table = htab_create (37, lto_hash_global_slot_node, lto_eq_global_slot_node, free);
+ ob->next_main_index = 0;
- /* The entire header is stream computed here. */
- switch_to_section (section);
+ /* Assign reference indices for predefined trees. These need not be serialized. */
+ preload_common_nodes (ob);
+ memset (&header, 0, sizeof (struct lto_decl_header));
+
+ switch_to_section (decl_section);
+
+ /* Make string 0 be a NULL string. */
+ lto_output_1_stream (ob->string_stream, 0);
+
+ /* Write the global var decls. */
+ LTO_SET_DEBUGGING_STREAM (debug_main_stream, main_data);
+ write_global_stream (ob, out_state->field_decls);
+ write_global_stream (ob, out_state->fn_decls);
+ write_global_stream (ob, out_state->var_decls);
+ write_global_stream (ob, out_state->type_decls);
+ write_global_stream (ob, out_state->namespace_decls);
+ write_global_stream (ob, out_state->types);
+
header.lto_header.major_version = LTO_major_version;
header.lto_header.minor_version = LTO_minor_version;
header.lto_header.section_type = LTO_section_decls;
@@ -465,26 +603,32 @@ produce_asm_for_decls (void)
header.num_namespace_decls = VEC_length (tree, out_state->namespace_decls);
header.num_types = VEC_length (tree, out_state->types);
- assemble_string ((const char *)&header,
- sizeof (struct lto_decl_header));
-
- /* Write the global field references. */
- write_references (out_state->field_decls, section, lto_field_ref);
+ /* Currently not used. This field would allow us to preallocate
+ the globals vector, so that it need not be resized as it is extended. */
+ header.num_nodes = -1;
- /* Write the global function references. */
- write_references (out_state->fn_decls, section, lto_fn_ref);
+ header.main_size = ob->main_stream->total_size;
+ header.string_size = ob->string_stream->total_size;
+ header.debug_main_size = ob->debug_main_stream->total_size;
- /* Write the global var references. */
- write_references (out_state->var_decls, section, lto_var_ref);
+ assemble_string ((const char *)&header,
+ sizeof (struct lto_decl_header));
- /* Write the global type_decl references. */
- write_references (out_state->type_decls, section, lto_typedecl_ref);
+ /* We must write the types first. */
+ write_global_references (ob, out_state->types);
+ write_global_references (ob, out_state->field_decls);
+ write_global_references (ob, out_state->fn_decls);
+ write_global_references (ob, out_state->var_decls);
+ write_global_references (ob, out_state->type_decls);
+ write_global_references (ob, out_state->namespace_decls);
- /* Write the global namespace_decl references. */
- write_references (out_state->namespace_decls, section, lto_namespacedecl_ref);
+ lto_write_stream (ob->main_stream);
+ lto_write_stream (ob->string_stream);
+#ifdef LTO_STREAM_DEBUGGING
+ lto_write_stream (ob->debug_main_stream);
+#endif
- /* Write the global type references. */
- write_references (out_state->types, section, lto_type_ref);
+ destroy_output_block (ob);
htab_delete (out_state->field_decl_hash_table);
htab_delete (out_state->fn_decl_hash_table);
@@ -493,6 +637,9 @@ produce_asm_for_decls (void)
htab_delete (out_state->namespace_decl_hash_table);
htab_delete (out_state->type_hash_table);
+ /* ### */
+ htab_delete (ob->main_hash_table);
+
VEC_free (tree, heap, out_state->field_decls);
VEC_free (tree, heap, out_state->fn_decls);
VEC_free (tree, heap, out_state->var_decls);
@@ -505,7 +652,6 @@ produce_asm_for_decls (void)
return 0;
}
-
/* Gate function for all lto streaming passes. */
bool
gate_lto_out (void)
diff --git a/gcc/lto-section-out.h b/gcc/lto-section-out.h
index 001f2c93c83..9bb0b5a378e 100644
--- a/gcc/lto-section-out.h
+++ b/gcc/lto-section-out.h
@@ -119,6 +119,9 @@ hashval_t lto_hash_decl_slot_node (const void *);
int lto_eq_decl_slot_node (const void *, const void *);
hashval_t lto_hash_type_slot_node (const void *);
int lto_eq_type_slot_node (const void *, const void *);
+/* ### */
+hashval_t lto_hash_global_slot_node (const void *);
+int lto_eq_global_slot_node (const void *, const void *);
struct lto_out_decl_state *lto_get_out_decl_state (void);
void lto_write_stream (struct lto_output_stream *);
@@ -130,4 +133,5 @@ void lto_output_sleb128_stream (struct lto_output_stream *, HOST_WIDE_INT);
void lto_output_integer_stream (struct lto_output_stream *, tree);
bool lto_output_decl_index (struct lto_output_stream *, htab_t, unsigned int *, tree, unsigned int *);
bool gate_lto_out (void);
+
#endif /* GCC_LTO_SECTION_OUT_H */
diff --git a/gcc/lto-section.h b/gcc/lto-section.h
index d5ea6e40893..adfa0711c12 100644
--- a/gcc/lto-section.h
+++ b/gcc/lto-section.h
@@ -35,6 +35,11 @@ struct lto_decl_header
int32_t num_type_decls; /* Number of TYPE_DECLs. */
int32_t num_namespace_decls; /* Number of NAMESPACE_DECLs. */
int32_t num_types; /* Number of types. */
+
+ int32_t num_nodes; /* Number of nodes in globals stream. */
+ int32_t main_size; /* Size of region for expressions, decls, types, etc. */
+ int32_t string_size; /* Size of the string table. */
+ int32_t debug_main_size; /* Size of region for main stream debugging information. */
};
#endif /* GCC_LTO_SECTION_H */
diff --git a/gcc/lto-tags.h b/gcc/lto-tags.h
index d31efa109f8..417d6052a57 100644
--- a/gcc/lto-tags.h
+++ b/gcc/lto-tags.h
@@ -388,9 +388,10 @@ enum LTO_tags {
LTO_ssa_name,
LTO_string_cst,
-/* Cases are terminated a zero. */
+/* Cases are terminated with a zero. */
LTO_switch_expr,
LTO_tree_list,
+ LTO_tree_vec,
LTO_trunc_div_expr,
LTO_trunc_mod_expr,
LTO_truth_and_expr,
@@ -399,6 +400,7 @@ enum LTO_tags {
LTO_truth_xor_expr,
LTO_type_decl,
LTO_namespace_decl,
+ LTO_translation_unit_decl,
LTO_uneq_expr,
LTO_unge_expr,
LTO_ungt_expr,
@@ -428,7 +430,29 @@ enum LTO_tags {
LTO_asm_clobbers,
LTO_function,
+
+/* Type reference used in cgraph. */
LTO_type,
+
+/* Types */
+ LTO_void_type,
+ LTO_integer_type,
+ LTO_real_type,
+ LTO_fixed_point_type,
+ LTO_complex_type,
+ LTO_boolean_type,
+ LTO_offset_type,
+ LTO_enumeral_type,
+ LTO_pointer_type,
+ LTO_reference_type,
+ LTO_vector_type,
+ LTO_array_type,
+ LTO_record_type,
+ LTO_union_type,
+ LTO_qual_union_type,
+ LTO_function_type,
+ LTO_method_type,
+
LTO_eh_table,
/* Each of these requires 4 variants. 1 and 3 are have_inner and 2
@@ -454,6 +478,12 @@ enum LTO_tags {
LTO_eh_table_must_not_throw2,
LTO_eh_table_must_not_throw3,
+/* Base info, e.g., for C++ */
+ LTO_tree_binfo,
+
+/* Special for global streamer. Reference to previously-streamed node. */
+ LTO_tree_pickle_reference,
+
/* There are 16 variants of the following decl bodies depending on the
subtrees that may or may not be there in the decl_common part of
the tree.
@@ -465,6 +495,8 @@ enum LTO_tags {
These next two tags must have their last hex digit be 0. */
LTO_local_var_decl_body0 = 0x0C0,
LTO_parm_decl_body0 = 0x0D0,
+
+/* This is a special literal that must always appear last! */
LTO_tree_last_tag = 0x0E0
};
diff --git a/gcc/lto-tree-flags.def b/gcc/lto-tree-flags.def
index 93b9bde2043..437cbe7995f 100644
--- a/gcc/lto-tree-flags.def
+++ b/gcc/lto-tree-flags.def
@@ -114,13 +114,21 @@
START_CLASS_CASE (tcc_type)
ADD_CLASS_EXPR_FLAG (addressable_flag)
- ADD_CLASS_EXPR_FLAG (public_flag)
+ /* We do not emit public_flag, which is
+ overloaded here as TYPE_CACHED_VALUES_P.
+ We do not stream the values cache, but
+ instead reconstruct it as constants
+ are internalized. */
ADD_CLASS_EXPR_FLAG (volatile_flag)
ADD_CLASS_EXPR_FLAG (readonly_flag)
ADD_CLASS_EXPR_FLAG (constant_flag)
ADD_CLASS_EXPR_FLAG (unsigned_flag)
ADD_CLASS_EXPR_FLAG (nothrow_flag)
ADD_CLASS_EXPR_FLAG (saturating_flag)
+ ADD_CLASS_TYPE_FLAG (needs_constructing_flag)
+ ADD_CLASS_TYPE_FLAG (packed_flag)
+ ADD_CLASS_TYPE_FLAG (restrict_flag)
+ ADD_CLASS_TYPE_FLAG (user_align)
END_CLASS_CASE (tcc_type)
START_CLASS_CASE (tcc_unary)
@@ -164,6 +172,7 @@
END_EXPR_CASE (ARRAY_REF)
START_EXPR_CASE (ARRAY_TYPE)
+ ADD_TYPE_FLAG (string_flag)
END_EXPR_CASE (ARRAY_TYPE)
START_EXPR_CASE (ASM_EXPR)
@@ -292,6 +301,18 @@
START_EXPR_CASE (FIELD_DECL)
ADD_EXPR_FLAG (addressable_flag)
+ ADD_DECL_FLAG (nonlocal_flag) /* ??? */
+ ADD_DECL_FLAG (virtual_flag)
+ ADD_DECL_FLAG (ignored_flag)
+ ADD_DECL_FLAG (abstract_flag)
+ ADD_DECL_FLAG (artificial_flag)
+ ADD_DECL_FLAG (user_align)
+ ADD_DECL_FLAG (preserve_flag) /* ??? */
+ ADD_DECL_FLAG (debug_expr_is_from) /* ??? */
+ ADD_DECL_FLAG (decl_flag_1)
+ ADD_DECL_FLAG (decl_flag_2)
+ ADD_DECL_FLAG (decl_flag_3)
+ ADD_DECL_FLAG (no_tbaa_flag) /* ??? */
END_EXPR_CASE (FIELD_DECL)
START_EXPR_CASE (FILTER_EXPR)
@@ -321,6 +342,47 @@
END_EXPR_CASE (FLOOR_MOD_EXPR)
START_EXPR_CASE (FUNCTION_DECL)
+ ADD_EXPR_FLAG (addressable_flag)
+ ADD_EXPR_FLAG (static_flag)
+ ADD_EXPR_FLAG (public_flag)
+ ADD_EXPR_FLAG (asm_written_flag)
+ ADD_EXPR_FLAG (nothrow_flag)
+ ADD_DECL_FLAG (nonlocal_flag)
+ ADD_DECL_FLAG (virtual_flag)
+ ADD_DECL_FLAG (ignored_flag)
+ ADD_DECL_FLAG (abstract_flag)
+ ADD_DECL_FLAG (artificial_flag)
+ ADD_DECL_FLAG (user_align)
+ ADD_DECL_FLAG (preserve_flag)
+ ADD_DECL_FLAG (debug_expr_is_from) /* ??? */
+ ADD_DECL_FLAG (decl_flag_2)
+ ADD_DECL_FLAG (no_tbaa_flag) /* ??? */
+ ADD_VIS_FLAG (in_system_header_flag)
+ ADD_VIS_FLAG (weak_flag)
+ ADD_VIS_FLAG (comdat_flag)
+ ADD_VIS_FLAG_SIZE (visibility, 2);
+ ADD_VIS_FLAG (visibility_specified)
+ ADD_VIS_FLAG (one_only)
+ /* #### FIXME
+ The init priority itself appears to be
+ stored external to the tree. We appear
+ to be dropping it on the floor. */
+ ADD_VIS_FLAG (init_priority_p)
+ ADD_FUN_FLAG (static_ctor_flag)
+ ADD_FUN_FLAG (static_dtor_flag)
+ ADD_FUN_FLAG (uninlinable)
+ ADD_FUN_FLAG (possibly_inlined)
+ ADD_FUN_FLAG (novops_flag)
+ ADD_FUN_FLAG (returns_twice_flag)
+ ADD_FUN_FLAG (malloc_flag)
+ ADD_FUN_FLAG (operator_new_flag)
+ ADD_FUN_FLAG (pure_flag)
+ ADD_FUN_FLAG (declared_inline_flag)
+ ADD_FUN_FLAG (regdecl_flag)
+ ADD_FUN_FLAG (inline_flag)
+ ADD_FUN_FLAG (no_instrument_function_entry_exit)
+ ADD_FUN_FLAG (no_limit_stack)
+ ADD_FUN_FLAG(disregard_inline_limits)
END_EXPR_CASE (FUNCTION_DECL)
START_EXPR_CASE (FUNCTION_TYPE)
@@ -361,6 +423,8 @@
END_EXPR_CASE (INTEGER_CST)
START_EXPR_CASE (INTEGER_TYPE)
+ ADD_TYPE_FLAG (string_flag)
+ ADD_TYPE_FLAG (no_force_blk_flag)
END_EXPR_CASE (INTEGER_TYPE)
START_EXPR_CASE (LABEL_DECL)
@@ -421,6 +485,17 @@
END_EXPR_CASE (NAME_MEMORY_TAG)
START_EXPR_CASE (NAMESPACE_DECL)
+ ADD_EXPR_FLAG (public_flag)
+ ADD_DECL_FLAG (nonlocal_flag)
+ ADD_DECL_FLAG (ignored_flag)
+ ADD_DECL_FLAG (abstract_flag)
+ ADD_DECL_FLAG (artificial_flag)
+ ADD_DECL_FLAG (preserve_flag)
+ ADD_VIS_FLAG (in_system_header_flag)
+ ADD_VIS_FLAG (weak_flag) /* ??? */
+ ADD_VIS_FLAG (comdat_flag) /* ??? */
+ ADD_VIS_FLAG_SIZE (visibility, 2); /* ??? */
+ ADD_VIS_FLAG (visibility_specified) /* ??? */
END_EXPR_CASE (NAMESPACE_DECL)
START_EXPR_CASE (NE_EXPR)
@@ -546,6 +621,7 @@
START_EXPR_CASE (QUAL_UNION_TYPE)
ADD_EXPR_FLAG (asm_written_flag)
+ ADD_TYPE_FLAG (no_force_blk_flag)
END_EXPR_CASE (QUAL_UNION_TYPE)
START_EXPR_CASE (RANGE_EXPR)
@@ -570,6 +646,7 @@
START_EXPR_CASE (RECORD_TYPE)
ADD_EXPR_FLAG (asm_written_flag)
+ ADD_TYPE_FLAG (no_force_blk_flag)
END_EXPR_CASE (RECORD_TYPE)
START_EXPR_CASE (REDUC_MAX_EXPR)
@@ -586,7 +663,9 @@
END_EXPR_CASE (REFERENCE_TYPE)
START_EXPR_CASE (RESULT_DECL)
+ /* ### Missing flags when used as declaration, not expression. */
ADD_DECL_FLAG (gimple_reg_flag)
+
END_EXPR_CASE (RESULT_DECL)
START_EXPR_CASE (RESX_EXPR)
@@ -643,7 +722,19 @@
START_EXPR_CASE (TARGET_MEM_REF)
END_EXPR_CASE (TARGET_MEM_REF)
+ /* ### The necessity of most of these flags is questionable. */
START_EXPR_CASE (TRANSLATION_UNIT_DECL)
+ ADD_EXPR_FLAG (public_flag)
+ ADD_DECL_FLAG (nonlocal_flag)
+ ADD_DECL_FLAG (ignored_flag)
+ ADD_DECL_FLAG (abstract_flag)
+ ADD_DECL_FLAG (artificial_flag)
+ ADD_DECL_FLAG (preserve_flag)
+ ADD_VIS_FLAG (in_system_header_flag)
+ ADD_VIS_FLAG (weak_flag)
+ ADD_VIS_FLAG (comdat_flag)
+ ADD_VIS_FLAG_SIZE (visibility, 2);
+ ADD_VIS_FLAG (visibility_specified)
END_EXPR_CASE (TRANSLATION_UNIT_DECL)
START_EXPR_CASE (TREE_BINFO)
@@ -687,6 +778,15 @@
END_EXPR_CASE (TRY_FINALLY_EXPR)
START_EXPR_CASE (TYPE_DECL)
+ ADD_DECL_FLAG (nonlocal_flag) /* ??? */
+ ADD_DECL_FLAG (ignored_flag)
+ ADD_DECL_FLAG (abstract_flag)
+ ADD_DECL_FLAG (artificial_flag)
+ /* ### Do we need user_align, preserve_flag, debug_expr_is_from ??? */
+ ADD_DECL_FLAG (decl_flag_2)
+ ADD_DECL_FLAG (no_tbaa_flag) /* ??? */
+ ADD_VIS_FLAG (in_system_header_flag)
+ /* ### Do we need weak_flag, visibility_specified, visibility ??? */
END_EXPR_CASE (TYPE_DECL)
START_EXPR_CASE (UNEQ_EXPR)
@@ -700,6 +800,8 @@
START_EXPR_CASE (UNION_TYPE)
ADD_EXPR_FLAG (asm_written_flag)
+ ADD_TYPE_FLAG (no_force_blk_flag)
+ ADD_TYPE_FLAG (transparent_union_flag)
END_EXPR_CASE (UNION_TYPE)
START_EXPR_CASE (UNLE_EXPR)
@@ -730,6 +832,7 @@
ADD_DECL_FLAG (decl_flag_2)
ADD_DECL_FLAG (decl_flag_3)
ADD_DECL_FLAG (gimple_reg_flag)
+ /* ### no_tbaa_flag ??? */
ADD_VIS_FLAG (defer_output)
ADD_VIS_FLAG (hard_register)
ADD_VIS_FLAG (thread_local)
@@ -741,7 +844,9 @@
ADD_VIS_FLAG (weak_flag)
ADD_VIS_FLAG (seen_in_bind_expr)
ADD_VIS_FLAG (comdat_flag)
+ /* ### Do we need visibility_specified ??? */
ADD_VIS_FLAG_SIZE (visibility, 2)
+ /* ### We need to serialize the init priority itself. */
ADD_VIS_FLAG (init_priority_p)
ADD_VIS_FLAG_SIZE (tls_model, 3)
END_EXPR_CASE (VAR_DECL)
diff --git a/gcc/lto-tree-tags.def b/gcc/lto-tree-tags.def
index da3090108a2..e66179b1831 100644
--- a/gcc/lto-tree-tags.def
+++ b/gcc/lto-tree-tags.def
@@ -77,6 +77,7 @@
MAP_EXPR_TAG(INTEGER_CST, LTO_integer_cst)
MAP_EXPR_TAG(LABEL_DECL, LTO_label_decl)
MAP_EXPR_TAG(LABEL_EXPR, LTO_label_expr)
+ MAP_EXPR_TAG(NAMESPACE_DECL, LTO_namespace_decl)
MAP_EXPR_TAG(PARM_DECL, LTO_parm_decl)
MAP_EXPR_TAG(PHI_NODE, LTO_phi_node)
MAP_EXPR_TAG(RANGE_EXPR, LTO_range_expr)
@@ -86,9 +87,29 @@
MAP_EXPR_TAG(SSA_NAME, LTO_ssa_name)
MAP_EXPR_TAG(STRING_CST, LTO_string_cst)
MAP_EXPR_TAG(SWITCH_EXPR, LTO_switch_expr)
+ MAP_EXPR_TAG(TRANSLATION_UNIT_DECL, LTO_translation_unit_decl)
+ MAP_EXPR_TAG(TREE_BINFO, LTO_tree_binfo)
MAP_EXPR_TAG(TREE_LIST, LTO_tree_list)
+ MAP_EXPR_TAG(TREE_VEC, LTO_tree_vec)
MAP_EXPR_TAG(TYPE_DECL, LTO_type_decl)
- MAP_EXPR_TAG(NAMESPACE_DECL, LTO_namespace_decl)
+ /* ### types -- should move into alphabetical order */
+ MAP_EXPR_TAG(VOID_TYPE, LTO_void_type)
+ MAP_EXPR_TAG(INTEGER_TYPE, LTO_integer_type)
+ MAP_EXPR_TAG(REAL_TYPE, LTO_real_type)
+ MAP_EXPR_TAG(FIXED_POINT_TYPE, LTO_fixed_point_type)
+ MAP_EXPR_TAG(COMPLEX_TYPE, LTO_complex_type)
+ MAP_EXPR_TAG(BOOLEAN_TYPE, LTO_boolean_type)
+ MAP_EXPR_TAG(OFFSET_TYPE, LTO_offset_type)
+ MAP_EXPR_TAG(ENUMERAL_TYPE, LTO_enumeral_type)
+ MAP_EXPR_TAG(POINTER_TYPE, LTO_pointer_type)
+ MAP_EXPR_TAG(REFERENCE_TYPE, LTO_reference_type)
+ MAP_EXPR_TAG(VECTOR_TYPE, LTO_vector_type)
+ MAP_EXPR_TAG(ARRAY_TYPE, LTO_array_type)
+ MAP_EXPR_TAG(RECORD_TYPE, LTO_record_type)
+ MAP_EXPR_TAG(UNION_TYPE, LTO_union_type)
+ MAP_EXPR_TAG(QUAL_UNION_TYPE, LTO_qual_union_type)
+ MAP_EXPR_TAG(FUNCTION_TYPE, LTO_function_type)
+ MAP_EXPR_TAG(METHOD_TYPE, LTO_method_type)
#endif /* TREE_SINGLE_MECHANICAL_FALSE */
#ifdef TREE_SINGLE_MECHANICAL_TRUE
@@ -277,7 +298,10 @@
SET_NAME (LTO_ssa_name, "ssa_name")
SET_NAME (LTO_string_cst, "string_cst")
SET_NAME (LTO_switch_expr, "switch_expr")
+ SET_NAME (LTO_translation_unit_decl, "translation_unit_decl")
+ SET_NAME (LTO_tree_binfo, "tree_binfo")
SET_NAME (LTO_tree_list, "tree_list")
+ SET_NAME (LTO_tree_vec, "tree_vec")
SET_NAME (LTO_trunc_div_expr, "trunc_div_expr")
SET_NAME (LTO_trunc_mod_expr, "trunc_mod_expr")
SET_NAME (LTO_truth_and_expr, "truth_and_expr")
@@ -303,11 +327,33 @@
SET_NAME (LTO_widen_mult_expr, "widen_mult_expr")
SET_NAME (LTO_widen_sum_expr, "widen_sum_expr")
SET_NAME (LTO_with_size_expr, "with_size_expr")
- SET_NAME (LTO_asm_inputs, "asm_inputs")
- SET_NAME (LTO_asm_outputs, "asm_outputs")
- SET_NAME (LTO_asm_clobbers, "asm_clobbers")
+
+ /* ### Should put these in alphabetical order as above. */
+ SET_NAME (LTO_asm_inputs, "asm_inputs") /* ### used? */
+ SET_NAME (LTO_asm_outputs, "asm_outputs") /* ### used? */
+ SET_NAME (LTO_asm_clobbers, "asm_clobbers") /* ### used? */
SET_NAME (LTO_function, "function")
SET_NAME (LTO_type, "type")
+
+ /* ### Should put these in alphabetical order as above. */
+ SET_NAME (LTO_void_type, "void_type")
+ SET_NAME (LTO_integer_type, "integer_type")
+ SET_NAME (LTO_real_type, "real_type")
+ SET_NAME (LTO_fixed_point_type, "fixed_point_type")
+ SET_NAME (LTO_complex_type, "complex_type")
+ SET_NAME (LTO_boolean_type, "boolean_type")
+ SET_NAME (LTO_offset_type, "offset_type")
+ SET_NAME (LTO_enumeral_type, "enumeral_type")
+ SET_NAME (LTO_pointer_type, "pointer_type")
+ SET_NAME (LTO_reference_type, "reference_type")
+ SET_NAME (LTO_vector_type, "vector_type")
+ SET_NAME (LTO_array_type, "array_type")
+ SET_NAME (LTO_record_type, "record_type")
+ SET_NAME (LTO_union_type, "union_type")
+ SET_NAME (LTO_qual_union_type, "qual_union_type")
+ SET_NAME (LTO_function_type, "function_type")
+ SET_NAME (LTO_method_type, "method_type")
+
SET_NAME (LTO_eh_table, "eh_table")
SET_NAME (LTO_eh_table_cleanup0, "eh_table_cleanup0")
SET_NAME (LTO_eh_table_cleanup1, "eh_table_cleanup1")
@@ -329,6 +375,22 @@
SET_NAME (LTO_eh_table_must_not_throw1, "eh_table_must_not_throw1")
SET_NAME (LTO_eh_table_must_not_throw2, "eh_table_must_not_throw2")
SET_NAME (LTO_eh_table_must_not_throw3, "eh_table_must_not_throw3")
+
+ /* ### */
+ /* Special for the global streamer. */
+ SET_NAME (LTO_tree_pickle_reference, "tree_pickle_reference")
+
+ /* ### */
+ /* The globals and types streamer uses the same tags used by
+ the local streamer to represent references to represent the
+ actual declarations instead. This was consistent with reusing
+ existing code that maps tags to tree codes before further
+ case analysis. We may want to introduce new tags, however,
+ so that we can use the same system of tag variants used
+ in the function body streamer in order to compress the
+ stream data somewhat. At present, however, the tags below
+ are used only by the function body streamer. */
+
SET_NAME (LTO_local_var_decl_body0+0x0, "local_var_decl_body0")
SET_NAME (LTO_local_var_decl_body0+0x1, "local_var_decl_body1")
SET_NAME (LTO_local_var_decl_body0+0x2, "local_var_decl_body2")
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index 472747d82cb..35717e69429 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -1,3 +1,63 @@
+2008-05-28 Bill Maddox <maddox@google.com>
+
+ Replace the DWARF reader in the LTO front-end.
+
+ * lto.c: Include lto-tree-in.h, lto-tags.h.
+ (enum DWARF2_class, DW_cl_constant, struct DWARF2_form_data,
+ struct lto_context, lto_fd_init, lto_info_fd_init,
+ lto_abbrev_fd_init, lto_info_fd_close, lto_file_init,
+ lto_file_close, lto_file_corrupt_error, lto_abi_mismatch_error,
+ LTO_CHECK_INT_VAL, LTO_READ_TYPE, lto_read_uleb128, lto_read_sleb128,
+ lto_read_initial_length, lto_abbrev_read_attrs, lto_abbrev_read,
+ lto_abbrev_read_lookup, lto_read_section_offset,
+ lto_read_comp_unit_header, find_cu_for_offset, lto_get_file_name,
+ lto_resolve_reference,lto_read_form, attribute_value_as_int,
+ make_signed_host_wide_int, attribute_value_as_constant, lto_cache_hash,
+ lto_cache_eq, lto_cache_store_DIE, lto_cache_lookup_DIE,
+ lto_find_integral_type, lto_find_integral_type_1,
+ LTO_BEGIN_READ_ATTRS_UNCHECKED, LTO_BEGIN_READ_ATTRS, LTO_END_READ_ATTRS,
+ lto_unsupported_attr_error, lto_get_identifier, lto_read_referenced_type_DIE,
+ lto_read_compile_unit_DIE, lto_read_array_type_DIE,
+ lto_read_structure_union_class_type_DIE, lto_read_enumerator_DIE,
+ lto_read_enumeration_type_DIE, lto_read_only_for_child_DIEs,
+ lto_read_only_for_child_DIEs, lto_read_member_DIE, lto_read_abbrev,
+ lto_read_variable_formal_parameter_constant_DIE, lto_get_body):
+ Removed.
+ (preload_common_nodes): New function.
+ (lto_read_decls): Convert for new global streamer.
+ (lto_materialze_file_data, lto_read_subroutine_type_subprogram_die,
+ lto_read_unspecified_parameters_DIE, lto_read_typedef_DIE,
+ lto_read_pointer_reference_type_DIE, lto_read_subrange_type_DIE,
+ lto_read_base_type_DIE, lto_read_const_volatile_restrict_type_DIE,
+ lto_read_namespace_DIE, lto_read_unspecified_type_DIE, lto_read_DIE,
+ lto_read_child_DIEs, lto_collect_child_DIEs): Removed.
+ (lto_info_read, lto_set_cu_context): Removed.
+ (lto_file_read): Convert for new global streamer.
+ (lto_resolve_type_ref, lto_read_DIE_at_ptr, lto_resolve_var_ref,
+ lto_resolve_fn_ref, lto_resolve_field_ref, lto_resolve_typedecl_ref,
+ lto_resolve_namespacedecl_ref): Removed.
+ (lto_file_init, lto_file_close): Moved to lto-elf.c.
+ * lto-tree.h (lto_symtab_merge_var, lto_symtab_mergee_fun): Declare here.
+ * lto-elf.c (lto_file_init, lto_file_close): Moved from lto.c.
+ (lto_elf_file_open): Removed code to read DWARF debug sections.
+ * lto.h (lto_context, DWARF2_attr, DWARF2_abbrev, DWARF2_CompUnit,
+ lto_die_ptr, lto_die_cache_entry, lto_fd, lto_info_fd, lto_abbrev_fd):
+ Removed.
+ (lto_file): Removed debug_info and debug_abbrev fields.
+ (lto_ref): Removed.
+ (lto_file_init, lto_file_close, lto_resolve_type_ref, lto_resolve_var_ref,
+ lto_resolve_fn_ref, lto_resolve_field_ref, lto_resolve_typedecl_ref,
+ lto_resolve_namespacedecl_ref, lto_get_file_name): Removed declarations.
+ (lto_symtab_merge_var, lto_symtab_merge_fn): Declarations moved to lto-tree.h.
+ * lto-symtab.c (lto_compatible_attributes_p): Lobotomize this, as it barfs
+ on "Hello, world!".
+ * lto-section-out.c: Include lto-tree-out.h.
+ (lto_hash_global_slot_node, lto_eq_global_slot_node, preload_common_nodes,
+ write_global_stream, write_global_references): New functions.
+ (produce_asm_for_decls): Convert for new global streamer.
+ * lto-section-out.h (lto_hash_global_slot_node, lto_eq_global_slot_node):
+ Declare.
+
2008-05-27 Kenneth Zadeck <zadeck@naturalbridge.com>
* lto.h (lto_read_decls): Made local.
diff --git a/gcc/lto/lto-elf.c b/gcc/lto/lto-elf.c
index 7f96d535d82..5793a44bee4 100644
--- a/gcc/lto/lto-elf.c
+++ b/gcc/lto/lto-elf.c
@@ -37,6 +37,29 @@ Boston, MA 02110-1301, USA. */
#include "libiberty.h"
#include "ggc.h"
+
+/* ### Moved lto_file_init and lto_file_close here from lto.c.
+ The lto_file vs. lto_elf_file distinction now appears superfluous. */
+
+/* Initialize FILE, an LTO file object for FILENAME. */
+static void
+lto_file_init (lto_file *file,
+ const lto_file_vtable *vtable,
+ const char *filename)
+{
+ file->vtable = vtable;
+ file->filename = filename;
+ /* ### We no longer use the debug_info and debug_abbrev fields. */
+}
+
+/* Close FILE. */
+static void
+lto_file_close (lto_file *file ATTRIBUTE_UNUSED)
+{
+ /* ### We no longer use the debug_info and debug_abbrev fields. */
+ ggc_free (file);
+}
+
/* An ELF input file. */
struct lto_elf_file
{
@@ -283,9 +306,7 @@ lto_elf_file_open (const char *filename)
lto_elf_file *elf_file;
size_t bits;
const char *elf_ident;
- Elf_Data *data;
lto_file *result;
- lto_fd *fd;
/* Set up. */
elf_file = GGC_NEW (lto_elf_file);
@@ -380,29 +401,6 @@ lto_elf_file_open (const char *filename)
goto fail;
}
- /* Find the .debug_info and .debug_abbrev sections. */
- data = lto_elf_find_section_data (elf_file, ".debug_info");
- if (!data)
- {
- error ("could not read %qs section: %s",
- ".debug_info", elf_errmsg (0));
- goto fail;
- }
- fd = (lto_fd *) &result->debug_info;
- fd->start = (const char *) data->d_buf;
- fd->end = fd->start + data->d_size;
-
- data = lto_elf_find_section_data (elf_file, ".debug_abbrev");
- if (!data)
- {
- error ("could not read %qs section: %s",
- ".debug_abbrev", elf_errmsg (0));
- goto fail;
- }
- fd = (lto_fd *) &result->debug_abbrev;
- fd->start = (const char *) data->d_buf;
- fd->end = fd->start + data->d_size;
-
return result;
fail:
diff --git a/gcc/lto/lto-symtab.c b/gcc/lto/lto-symtab.c
index f8a94460a35..02d67f9c719 100644
--- a/gcc/lto/lto-symtab.c
+++ b/gcc/lto/lto-symtab.c
@@ -227,9 +227,16 @@ lto_compatible_attributes_p (tree decl ATTRIBUTE_UNUSED,
tree attributes_1,
tree attributes_2)
{
+#if 0
/* ??? For now, assume two attribute sets are compatible only if they
are both empty. */
return !attributes_1 && !attributes_2;
+#else
+ /* ### */
+ /* For the moment, live dangerously, and assume the user knows what he's doing.
+ I don't think the linker would distinguish these cases. */
+ return true || (!attributes_1 && !attributes_2);
+#endif
}
diff --git a/gcc/lto/lto-tree.h b/gcc/lto/lto-tree.h
index 87bc8f80606..af0038dc0c9 100644
--- a/gcc/lto/lto-tree.h
+++ b/gcc/lto/lto-tree.h
@@ -70,4 +70,22 @@ union lang_tree_node GTY(
/* Vector to keep track of external variables we've seen so far. */
extern GTY(()) VEC(tree,gc) *lto_global_var_decls;
+
+/* lto-symtab.c */
+
+/* The NEW_VAR (a VAR_DECL) has just been read. If there is an
+ existing variable with the same name, merge the declaration for
+ NEW_VAR with the previous declaration and return the previous
+ declaration. In this case, NEW_VAR must no longer be used by the
+ caller. All other entities referenced from NEW_VAR (including, in
+ particular, its type) must already have been merged before this
+ function is called. If the merge fails (due to inconsistencies
+ between the declarations), an error message is issued, and
+ error_mark_node is returned. If there is no previous declaration,
+ NEW_VAR is returned. */
+extern tree lto_symtab_merge_var (tree new_var);
+
+/* Like lto_symtab_merge_var, but for functions. */
+extern tree lto_symtab_merge_fn (tree new_fn);
+
#endif /* GCC_LTO_TREE_H */
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 60bca2bcd48..fe6ebe56f3b 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -36,2393 +36,11 @@ Boston, MA 02110-1301, USA. */
#include "langhooks.h"
#include "lto-section.h"
#include "lto-section-in.h"
+#include "lto-tree-in.h"
+#include "lto-tags.h" /* For LTO_tree_tag_names. */
-/* References
- DWARF Debugging Information Format (Version 3)
- http://dwarf.freestandards.org/Dwarf3.pdf
-
- */
-
-/* Types */
-
-/* The classes of DWARF2 attribute data. */
-typedef enum DWARF2_class
-{
- DW_cl_error = 0x0,
- DW_cl_address = 0x1,
- DW_cl_block = 0x2,
- DW_cl_uconstant = 0x4,
- DW_cl_sconstant = 0x8,
- DW_cl_flag = 0x10,
- DW_cl_lineptr = 0x20,
- DW_cl_loclistptr = 0x40,
- DW_cl_macptr = 0x80,
- DW_cl_rangelistptr = 0x100,
- DW_cl_reference = 0x200,
- DW_cl_string = 0x400
-} DWARF2_class;
-
-/* Some places we want to specify that both unsigned and signed constant
- forms are allowed, so define a shorthand. */
-#define DW_cl_constant (DW_cl_uconstant | DW_cl_sconstant)
-
-/* The data corresponding to a single attribute form in a DIE. */
-typedef struct DWARF2_form_data
-{
- /* The class of data. */
- DWARF2_class cl;
- union {
- /* If CL is DW_cl_address, DW_cl_lineptr, DW_cl_loclistptr,
- DW_cl_macptr, or DW_cl_rangelistptr, there is no additional
- data. These forms are not of interest to us for link-time
- optimization. */
- /* Used when CL is DW_cl_uconstant. */
- uint64_t uconstant;
- /* Used when CL is DW_cl_sconstant. */
- int64_t sconstant;
- /* Used when CL is DW_cl_block. */
- struct DWARF2_form_data_block {
- /* The number of bytes in the block. */
- size_t length;
- /* The data in the block. */
- const void *data;
- } block;
- /* Used when CL is DW_cl_flag. */
- bool flag;
- /* Used when CL is DW_cl_string. The value is a NUL-terminated
- string. */
- const char *string;
- /* Used when CL is DW_cl_reference. The value is a pointer into
- the .debug_info section indicating the DIE referenced. */
- lto_die_ptr reference;
- } u;
-} DWARF2_form_data;
-
-/* Information passed from parent DIEs to child DIEs to give context
- about the current location in the scope tree.
-
- When adding to this structure, make sure to update the
- initialization code in lto_file_read. */
-struct lto_context
-{
- /* The start of the current compilation unit info. This is right
- *after* the header, at the beginning of the DIE entries, so if
- you want the start of the header, you need to subtract the
- header length. */
- const char *cu_start;
- /* The byte just past the end of the current compilation unit. */
- const char *cu_end;
- /* Pointer to the CompUnit structure currently being used. */
- const DWARF2_CompUnit *cu;
- /* The scope (a NAMESPACE_DECL, FUNCTION_DECL, RECORD_TYPE, etc.)
- containing the DIE about to be read. NULL_TREE if at the
- outermost level. */
- tree scope;
- /* Some things (like lower array bounds) have language-specific defaults,
- so keep track of the language here. */
- int language;
- /* Some DIEs (like enumerated types) need to pass down some information
- to their children as they are parsed. */
- tree parentdata;
-
- /* When determining the type of a function, a pointer to the
- location where the next parameter type should be stored. */
- tree *last_parm_type;
- /* When determining the type of a function, true if the function
- type has variable arguments. */
- bool varargs_p;
-
- /* True if we should skip all DIEs. */
- bool skip_all;
- /* True if only parameters should be processed (because we are
- trying to determine the type of a function). */
- bool skip_non_parameters;
- /* True if all parameters should be skipped (because they have
- already been processed). */
- bool skip_parameters;
-};
-
-/* Forward Declarations */
-
-static hashval_t
-lto_cache_hash (const void *data);
-
-static int
-lto_cache_eq (const void *data, const void *key);
-
-static tree
-lto_read_DIE (lto_info_fd *fd,
- lto_context *context,
- bool *more);
-
-static tree
-lto_read_DIE_at_ptr (lto_info_fd *fd,
- lto_context *context,
- lto_die_ptr ptr);
-
-static void
-lto_read_child_DIEs (lto_info_fd *fd,
- const DWARF2_abbrev *abbrev,
- lto_context *context);
-
-static VEC(tree,heap) *
-lto_collect_child_DIEs (lto_info_fd *fd,
- const DWARF2_abbrev *abbrev,
- lto_context *context);
-
-static void
-lto_set_cu_context (lto_context *context, lto_info_fd *fd,
- DWARF2_CompUnit *unit);
-/* Functions */
-
-/* Initialize FD, a newly allocated "file descriptor". NAME indicates
- the name of the section from which FD is reading. FILE is the
- file containing that section. */
-static void
-lto_fd_init (lto_fd *fd, const char *name, lto_file *file)
-{
- fd->name = name;
- fd->start = NULL;
- fd->end = NULL;
- fd->cur = NULL;
- fd->file = file;
- fd->dwarf64 = false;
-}
-
-/* Initialize FD, a newly allocated file descriptor for a DWARF2
- info section. NAME and FILE are as for lto_fd_init. */
-static void
-lto_info_fd_init (lto_info_fd *fd, const char *name, lto_file *file)
-{
- lto_fd_init ((lto_fd *) fd, name, file);
- fd->num_units = 0;
- fd->units = NULL;
- fd->die_cache = htab_create_ggc (37, lto_cache_hash, lto_cache_eq, NULL);
-}
-
-/* Initialize FD, a newly allocated file descriptor for a DWARF2
- abbreviation section. NAME and FILE are as for lto_fd_init. */
-static void
-lto_abbrev_fd_init (lto_abbrev_fd *fd, const char *name, lto_file *file)
-{
- lto_fd_init ((lto_fd *) fd, name, file);
- fd->num_abbrevs = 0;
- fd->abbrevs = NULL;
-}
-
-/* Close FD. */
-static void
-lto_info_fd_close (lto_info_fd *fd)
-{
- size_t i;
-
- htab_delete (fd->die_cache);
- for (i = 0; i < fd->num_units; ++i)
- XDELETE (fd->units[i]);
- XDELETEVEC (fd->units);
-}
-
-/* Close FD. */
-static void
-lto_abbrev_fd_close (lto_abbrev_fd *fd)
-{
- size_t i;
-
- for (i = 0; i < fd->num_abbrevs; ++i)
- XDELETE (fd->abbrevs[i]);
- XDELETEVEC (fd->abbrevs);
-}
-
-/* Initialize FILE, an LTO file object for FILENAME. */
-void
-lto_file_init (lto_file *file,
- const lto_file_vtable *vtable,
- const char *filename)
-{
- file->vtable = vtable;
- file->filename = filename;
- lto_info_fd_init (&file->debug_info, ".debug_info", file);
- lto_abbrev_fd_init (&file->debug_abbrev, ".debug_abbrev", file);
-}
-
-/* Close FILE. */
-void
-lto_file_close (lto_file *file)
-{
- lto_info_fd_close (&file->debug_info);
- lto_abbrev_fd_close (&file->debug_abbrev);
- ggc_free (file);
-}
-
-/* Issue an error indicating that the section from which FD is reading
- is corrupt, i.e., fails to conform to the DWARF specification. */
-static void ATTRIBUTE_NORETURN
-lto_file_corrupt_error (const lto_fd *fd)
-{
- fatal_error ("corrupt link-time optimization information in "
- "%qs section", fd->name);
-}
-
-/* Issue an error indicating that the ABI used to compile the object
- file does not match that currently in use by the LTO front end. */
-static void ATTRIBUTE_NORETURN
-lto_abi_mismatch_error (void)
-{
- fatal_error ("ABI for object file does not match current "
- "compilation options");
-}
-
-/* Define a function:
-
- static C_TYPE
- lto_check_C_TYPE_val (uint64_t val, const char *message);
-
- VAL is being used in a way that requires that it fit into a host
- C_TYPE. If the value fits, it is returned unchanged (but cast to
- C_TYPE). If it doesn't fit, the DWARF information is still valid,
- but we are unable to process it; in that case, a fatal error is
- issued, using the error MESSAGE. */
-#define LTO_CHECK_INT_VAL(C_TYPE) \
- static C_TYPE \
- lto_check_##C_TYPE##_val (uint64_t val, const char *message) \
- { \
- C_TYPE result; \
- \
- result = val; \
- if ((uint64_t) result != val) \
- fatal_error ("%s", message); \
- return result; \
- }
-
-/* Define functions to check conversions from DWARF constant values to
- C datatypes. */
-LTO_CHECK_INT_VAL(size_t);
-LTO_CHECK_INT_VAL(int);
-LTO_CHECK_INT_VAL(HOST_WIDE_INT);
-
-#undef LTO_CHECK_INT_VAL
-
-/* Define a function:
-
- static C_TYPE lto_read_DWARF_TYPE (lto_fd *fd);
-
- Here, DWARF_TYPE is a defined name (like "ubyte") from the DWARF
- specification. C_TYPE is the equivalent C_TYPE. This function is
- responsible for performing any byte-swapping required when reading
- the raw data from memory.
-
- ??? However, that byte-swapping is not actually performed as of
- yet. */
-#define LTO_READ_TYPE(DWARF_TYPE, C_TYPE) \
- static C_TYPE \
- lto_read_##DWARF_TYPE (lto_fd *fd) \
- { \
- C_TYPE result; \
- \
- if (fd->cur + sizeof (C_TYPE) > fd->end) \
- lto_file_corrupt_error (fd); \
- memcpy (&result, fd->cur, sizeof (C_TYPE)); \
- fd->cur += sizeof (C_TYPE); \
- \
- return result; \
- }
-
-/* Define functions to read the DWARF primitive types. */
-LTO_READ_TYPE (ubyte, uint8_t);
-LTO_READ_TYPE (uhalf, uint16_t);
-LTO_READ_TYPE (uword, uint32_t);
-/* DWARF3 does not specify "udword" by name, but does use 64-bit
- unsigned quantities in some places. */
-LTO_READ_TYPE (udword, uint64_t);
-
-#undef LTO_READ_TYPE
-
-/* Read an unsigned LEB128 value from FD. */
-static uint64_t
-lto_read_uleb128 (lto_fd *fd)
-{
- uint8_t byte;
- uint64_t result;
- bool more;
- unsigned shift;
-
- result = 0;
- shift = 0;
- do
- {
- byte = lto_read_ubyte (fd);
- more = byte & 0x80;
- result |= (byte & ~0x80) << shift;
- shift += 7;
- }
- while (more);
-
- return result;
-}
-
-/* Read an signed LEB128 value from FD. */
-static int64_t
-lto_read_sleb128 (lto_fd *fd)
-{
- uint8_t byte;
- uint64_t result;
- int64_t sresult;
- bool more;
- uint8_t sign;
- unsigned shift;
-
- result = 0;
- shift = 0;
- do
- {
- byte = lto_read_ubyte (fd);
- more = byte & 0x80;
- result |= (byte & ~0x80) << shift;
- shift += 7;
- sign = (byte & 0x40);
- }
- while (more);
-
- if (sign && shift < 64)
- sresult = (int64_t) result | ((int64_t)(-1) << shift);
- else
- sresult = (int64_t) result;
- return sresult;
-}
-
-/* Read an initial length field from FD. The length may be a 32-bit
- or 64-bit quantity, depending on whether 32-bit or 64-bit DWARF is
- in use, so the value returned is always a 64-bit value. Set
- FIELD_SIZE to the size (in bytes) of the initial length field. */
-static uint64_t
-lto_read_initial_length (lto_fd *fd, unsigned int *field_size)
-{
- /* The length of the debugging information section, as indicated in
- the DWARF information itself. We use a 64-bit value so that we
- can support 64-bit DWARF in future. */
- uint64_t length;
-
- /* Assume that this will be a 32-bit DWARF section. */
- fd->dwarf64 = false;
- length = lto_read_uword (fd);
- if (length == 0xffffffff)
- {
- *field_size = sizeof (uint32_t) + sizeof (uint64_t);
- /* 64-bit DWARF. */
- fd->dwarf64 = true;
- /* The "dwarf2.h" header used by GCC does not declare 64-bit
- DWARF objects, so we cannot actually use 64-bit DWARF. */
- fatal_error ("64-bit DWARF not supported by link-time optimization");
- }
- else if (length >= 0xffffff00)
- /* An extension to DWARF that we do not support. */
- fatal_error ("link-time optimization does not support DWARF extension "
- HOST_WIDEST_INT_PRINT_UNSIGNED, length);
- else
- *field_size = sizeof (uint32_t);
-
- return length;
-}
-
-/* Read the attributes for an abbreviation entry from ABBREV_FD. If
- ATTRS is non-NULL, fill it in with the attributes read; otherwise,
- the attributes are discarded. In either case, return the number of
- attributes read. */
-static size_t
-lto_abbrev_read_attrs (lto_abbrev_fd *abbrev_fd, DWARF2_attr *attrs)
-{
- size_t num_attrs;
- lto_fd *fd;
-
- num_attrs = 0;
- fd = (lto_fd *)abbrev_fd;
-
- /* Read all the attributes. */
- while (true)
- {
- uint64_t name;
- uint64_t form;
- name = lto_read_uleb128 (fd);
- form = lto_read_uleb128 (fd);
- if (!name && !form)
- break;
- /* If requested, fill in the attribute array. */
- if (attrs)
- {
- attrs->name = name;
- attrs->form = form;
- ++attrs;
- }
- ++num_attrs;
- }
-
- return num_attrs;
-}
-
-/* Read all the DWARF2 abbreviations from ABBREV_FD, placing them in
- ABBREV_FD->ABBREVS. */
-static void
-lto_abbrev_read (lto_abbrev_fd *abbrev_fd)
-{
- size_t num_abbrevs = 0;
- unsigned pass;
- lto_fd *fd;
-
- /* We should only read the abbreviations once. */
- gcc_assert (!abbrev_fd->abbrevs);
- fd = (lto_fd *)abbrev_fd;
- /* Make two passes over the data. On the first pass, count the
- number of abbreviations; on the second, read them in. */
- for (pass = 0; pass < 2; ++pass)
- {
- /* On the second pass, allocate the array of abbreviations. */
- if (pass == 1)
- {
- abbrev_fd->num_abbrevs = num_abbrevs;
- abbrev_fd->abbrevs = XCNEWVEC (DWARF2_abbrev *, num_abbrevs);
- }
- num_abbrevs = 0;
- /* Read the abbreviations, starting from the beginning of the
- abbreviations section. */
- fd->cur = fd->start;
- while (true)
- {
- uint64_t index;
- uint64_t tag;
- uint8_t children;
- size_t num_attrs;
- DWARF2_abbrev *abbrev;
- const char *cur;
-
- /* Read the abbreviation index. */
- index = lto_read_uleb128 (fd);
- if (!index)
- /* Index zero indicates the end of the abbreviation codes. */
- break;
- if (index > num_abbrevs)
- {
- lto_check_size_t_val (index,
- "too many DWARF2 abbreviation entries");
- num_abbrevs = (size_t) index;
- }
- /* The index is followed by the tag for the DIE. */
- tag = lto_read_uleb128 (fd);
- children = lto_read_ubyte (fd);
- if (children != DW_CHILDREN_yes && children != DW_CHILDREN_no)
- lto_file_corrupt_error (fd);
- /* Count the attributes so that we know how much space is
- required for ABBREV. Remember where we are, so that we can
- return to our present location to read the attributes, after
- ABBREV has been allocated. */
- cur = fd->cur;
- num_attrs = lto_abbrev_read_attrs (abbrev_fd, NULL);
- if (abbrev_fd->abbrevs)
- {
- /* Allocate the abbreviation entry. */
- abbrev = ((DWARF2_abbrev *)
- xmalloc (sizeof (DWARF2_abbrev)
- + (num_attrs - 1) * sizeof (DWARF2_attr)));
- abbrev->tag = tag;
- abbrev->has_children = (children == DW_CHILDREN_yes);
- abbrev->num_attrs = num_attrs;
- /* Read the attributes again. */
- fd->cur = cur;
- lto_abbrev_read_attrs (abbrev_fd, abbrev->attrs);
- abbrev_fd->abbrevs[index - 1] = abbrev;
- }
- }
- }
-}
-
-/* Return the abbreviation entry with index ABBREV. */
-static const DWARF2_abbrev *
-lto_abbrev_lookup (lto_abbrev_fd *abbrev_fd, uint64_t abbrev)
-{
- const DWARF2_abbrev *result;
-
- /* An abbreviation of zero indicates the end of a list of sibling
- DIEs. Therefore, callers should never call this function with
- ABBREV set to zero. */
- gcc_assert (abbrev != 0);
- /* If the abbreviation is missing, that is an error. */
- if (abbrev > abbrev_fd->num_abbrevs)
- lto_file_corrupt_error ((lto_fd *)abbrev_fd);
- result = abbrev_fd->abbrevs[abbrev - 1];
- if (!result)
- lto_file_corrupt_error ((lto_fd *)abbrev_fd);
- return result;
-}
-
-/* Read a section offset from FD. In 32-bit DWARF, this is a 32-bit
- value; in 64-bit DWARF, it is a 64-bit value. Therefore, the value
- returned is always a 64-bit value. */
-static uint64_t
-lto_read_section_offset (lto_fd *fd)
-{
- return fd->dwarf64 ? lto_read_udword (fd) : lto_read_uword (fd);
-}
-
-/* Read the compilation-unit header from FD, placing the resulting
- header in *CU. */
-static void
-lto_read_comp_unit_header (lto_info_fd *fd,
- DWARF2_CompUnit *cu)
-{
- unsigned int length_field_size;
- lto_fd *basefd = (lto_fd *)fd;
-
- /* The cu length is the length of the compilation unit, *not*
- including the length field. Since the length field can be 4 or
- 12 bytes, and *our* cu_length is specified to *include* the
- length field, we have to account for this. */
- cu->cu_length = lto_read_initial_length (basefd, &length_field_size);
- cu->cu_length += length_field_size;
- cu->cu_version = lto_read_uhalf (basefd);
- cu->cu_abbrev_offset = lto_read_section_offset (basefd);
- cu->cu_pointer_size = lto_read_ubyte (basefd);
- if (cu->cu_pointer_size * BITS_PER_UNIT != POINTER_SIZE)
- lto_abi_mismatch_error ();
-}
-
-/* Find the compilation unit in FD that contains the DWARF2 DIE
- at OFFSET from the beginning of .debug_info. */
-static DWARF2_CompUnit *
-find_cu_for_offset (const lto_info_fd *fd,
- uint64_t offset)
-{
- unsigned int len = fd->num_units;
- unsigned int half, middle;
- unsigned int first = 0;
-
- while (len > 0)
- {
- DWARF2_CompUnit *middle_elem;
-
- half = len >> 1;
- middle = first;
- middle += half;
- middle_elem = fd->units[middle];
- if (middle_elem->cu_start_offset < offset)
- {
- first = middle;
- ++first;
- len = len - half - 1;
- }
- else
- len = half;
- }
-
- /* The above calculation will give us the first place *after* the cu
- we want. So just subtract 1. */
-
- if (first <= 0 || first > fd->num_units)
- lto_file_corrupt_error (&fd->base);
-
- return fd->units[first - 1];
-}
-
-
-/* Get the file name associated with INFO_FD. */
-const char *
-lto_get_file_name (lto_info_fd *info_fd)
-{
- return info_fd->base.file->filename;
-}
-
-
-/* Resolve a reference to the DIE at offset OFFSET. Returns a pointer
- to the DIE, as mapped into memory. Sets *NEW_CONTEXT to CONTEXT,
- or to a newly allocated context corresponding to the DIE referred
- to by OFFSET. If *NEW_CONTEXT != CONTEXT upon return, the caller
- must free *NEW_CONTEXT when it is no longer needed. */
-static lto_die_ptr
-lto_resolve_reference (lto_info_fd *info_fd,
- uint64_t offset,
- const lto_context *context,
- lto_context **new_context)
-{
- DWARF2_CompUnit *cu;
- lto_die_ptr reference;
-
- /* Swap context if necessary. */
- cu = find_cu_for_offset (info_fd, offset);
- if (cu != context->cu)
- {
- *new_context = XCNEW (lto_context);
- **new_context = *context;
- lto_set_cu_context (*new_context, info_fd, cu);
- context = *new_context;
- }
- /* Resolve reference. */
- reference = (lto_die_ptr) ((context->cu_start
- + lto_check_size_t_val (offset,
- "offset too large")));
- if (reference >= (lto_die_ptr) context->cu_end)
- lto_file_corrupt_error ((lto_fd *)info_fd);
-
- return reference;
-}
-
-/* Read the value of the attribute ATTR from INFO_FD. CONTEXT is as for
- the DIE readers. Upon return, *OUT contains the data read,
- and FORM_CONTEXT is the context necessary to do something with the
- form. */
-static void
-lto_read_form (lto_info_fd *info_fd,
- const DWARF2_attr *attr,
- lto_context *context,
- lto_context **form_context,
- DWARF2_form_data *out)
-{
- lto_fd *fd = (lto_fd *)info_fd;
- /* The Nth element in this array specifies (as a bitmask) the
- permissible classes of data for the attribute with code N. See
- Figure 20 in DWARF 3 \S 7.5.4. */
- static const DWARF2_class attr_classes[DW_AT_recursive + 1] = {
- DW_cl_error,
- DW_cl_reference, /* sibling */
- DW_cl_block | DW_cl_loclistptr, /* location */
- DW_cl_string, /* name */
- DW_cl_error, /* padding */
- DW_cl_error, /* padding */
- DW_cl_error, /* padding */
- DW_cl_error, /* padding */
- DW_cl_error, /* padding */
- DW_cl_constant, /* ordering */
- DW_cl_error, /* subscr_data */
- DW_cl_block | DW_cl_constant | DW_cl_reference, /* byte_size */
- DW_cl_block | DW_cl_constant | DW_cl_reference, /* bit_offset */
- DW_cl_block | DW_cl_constant | DW_cl_reference, /* bit_size */
- DW_cl_error, /* padding */
- DW_cl_error, /* element_list */
- DW_cl_lineptr, /* stmt_list */
- DW_cl_address, /* low_pc */
- DW_cl_address, /* high_pc */
- DW_cl_constant, /* language */
- DW_cl_error, /* member */
- DW_cl_reference, /* discr */
- DW_cl_constant, /* discr_value */
- DW_cl_constant, /* visibility */
- DW_cl_reference, /* import */
- DW_cl_block | DW_cl_loclistptr, /* string_length */
- DW_cl_reference, /* common_reference */
- DW_cl_string, /* comp_dir */
- DW_cl_block | DW_cl_constant | DW_cl_string | DW_cl_address, /* const_value */
- DW_cl_reference, /* containing_type */
- DW_cl_reference, /* default_value */
- DW_cl_error, /* padding */
- DW_cl_constant, /* inline */
- DW_cl_flag, /* is_optional */
- DW_cl_block | DW_cl_constant | DW_cl_reference, /* lower_bound */
- DW_cl_error, /* padding */
- DW_cl_error, /* padding */
- DW_cl_string, /* producer */
- DW_cl_error, /* padding */
- DW_cl_flag, /* prototyped */
- DW_cl_error, /* padding */
- DW_cl_error, /* padding */
- DW_cl_block | DW_cl_loclistptr, /* return_addr */
- DW_cl_error, /* padding */
- DW_cl_constant | DW_cl_rangelistptr, /* start_scope */
- DW_cl_error, /* padding */
- DW_cl_constant, /* stride_size */
- DW_cl_block | DW_cl_constant | DW_cl_reference, /* upper_bound */
- DW_cl_error, /* padding */
- DW_cl_reference, /* abstract_origin */
- DW_cl_constant, /* accessibility */
- DW_cl_constant, /* address_class */
- DW_cl_flag, /* artificial */
- DW_cl_reference, /* base_types */
- DW_cl_constant, /* calling_convention */
- DW_cl_block | DW_cl_constant | DW_cl_reference, /* count */
- DW_cl_block | DW_cl_constant | DW_cl_loclistptr, /* data_member_location */
- DW_cl_constant, /* decl_column */
- DW_cl_constant, /* decl_file */
- DW_cl_constant, /* decl_line */
- DW_cl_flag, /* declaration */
- DW_cl_block, /* discr_list */
- DW_cl_constant, /* encoding */
- DW_cl_flag, /* external */
- DW_cl_block | DW_cl_loclistptr, /* frame_base */
- DW_cl_reference, /* friend */
- DW_cl_constant, /* identifier_case */
- DW_cl_macptr, /* macro_info */
- DW_cl_block, /* namelist_items */
- DW_cl_reference, /* priority */
- DW_cl_block | DW_cl_loclistptr, /* segment */
- DW_cl_reference, /* specification */
- DW_cl_block | DW_cl_loclistptr, /* static_link */
- DW_cl_reference, /* type */
- DW_cl_block | DW_cl_loclistptr, /* use_location */
- DW_cl_flag, /* variable_parameter */
- DW_cl_constant, /* virtuality */
- DW_cl_block | DW_cl_loclistptr, /* vtable_elem_location */
- DW_cl_block | DW_cl_constant | DW_cl_reference, /* allocated */
- DW_cl_block | DW_cl_constant | DW_cl_reference, /* associated */
- DW_cl_block, /* data_location */
- DW_cl_block | DW_cl_constant | DW_cl_reference, /* stride */
- DW_cl_address, /* entry_pc */
- DW_cl_flag, /* use_UTF8 */
- DW_cl_reference, /* extension */
- DW_cl_rangelistptr, /* ranges */
- DW_cl_address | DW_cl_flag | DW_cl_reference | DW_cl_string,/* trampoline */
- DW_cl_constant, /* call_column */
- DW_cl_constant, /* call_file */
- DW_cl_constant, /* call_line */
- DW_cl_string, /* description */
- DW_cl_constant, /* binary_scale */
- DW_cl_constant, /* decimal_scale */
- DW_cl_reference, /* small */
- DW_cl_constant, /* decimal_sign */
- DW_cl_constant, /* digit_count */
- DW_cl_string, /* picture_string */
- DW_cl_flag, /* mutable */
- DW_cl_flag, /* threads_scaled */
- DW_cl_flag, /* explicit */
- DW_cl_reference, /* object_pointer */
- DW_cl_constant, /* endianity */
- DW_cl_flag, /* elemental */
- DW_cl_flag, /* pure */
- DW_cl_flag /* recursive */
- };
-
- /* The name (DW_AT_...) of this attribute. */
- uint64_t name;
- /* The form (DW_FORM_...) of this attribute. */
- uint64_t form;
- /* The set of form classes permitted for this attribute. */
- DWARF2_class class_mask;
-
- name = attr->name;
- form = attr->form;
- /* Make sure this is an attribute we recognize. */
- if (attr->name == DW_AT_MIPS_linkage_name)
- class_mask = DW_cl_string;
- else if (attr->name == DW_AT_GNU_vector)
- class_mask = DW_cl_flag;
- else if (attr->name >= sizeof (attr_classes) / sizeof (attr_classes[0]))
- lto_file_corrupt_error (fd);
- else
- /* Determine the set of permitted attribute classes. */
- class_mask = attr_classes[attr->name];
-
- /* Initialize OUT. */
- out->cl = DW_cl_error;
- /* The data read depends on the form given for the attribute. */
- switch (form)
- {
- case DW_FORM_addr:
- /* Addresses are not useful without relocation info, so just skip
- over the appropriate number of bytes. */
- out->cl = DW_cl_address;
- fd->cur += context->cu->cu_pointer_size;
- if (fd->cur > context->cu_end)
- lto_file_corrupt_error (fd);
- break;
-
- case DW_FORM_string:
- out->cl = DW_cl_string;
- out->u.string = fd->cur;
- /* Skip over the string. */
- while (true)
- {
- if (!*fd->cur++)
- break;
- if (fd->cur > context->cu_end)
- lto_file_corrupt_error (fd);
- }
- break;
-
- case DW_FORM_strp:
- /* Temporary hack: we don't need the string data, but we do need
- it not to crash if it sees one. So just skip past the offset
- and return an empty string. */
- out->cl = DW_cl_string;
- fd->dwarf64 ? lto_read_uword (fd) : lto_read_udword (fd);
- out->u.string = "";
- break;
-
- case DW_FORM_data1:
- case DW_FORM_data2:
- case DW_FORM_data4:
- case DW_FORM_data8:
- case DW_FORM_sdata:
- case DW_FORM_udata:
- {
- uint64_t data = 0;
- int64_t sdata = 0;
- /* Read the actual data. */
- switch (form)
- {
- case DW_FORM_data1:
- data = lto_read_ubyte (fd);
- break;
- case DW_FORM_data2:
- data = lto_read_uhalf (fd);
- break;
- case DW_FORM_data4:
- data = lto_read_uword (fd);
- break;
- case DW_FORM_data8:
- data = lto_read_udword (fd);
- break;
- case DW_FORM_sdata:
- sdata = lto_read_sleb128 (fd);
- break;
- case DW_FORM_udata:
- data = lto_read_uleb128 (fd);
- break;
- default:
- gcc_unreachable ();
- break;
- }
- switch (name)
- {
- case DW_AT_location:
- case DW_AT_string_length:
- case DW_AT_return_addr:
- case DW_AT_data_member_location:
- case DW_AT_frame_base:
- case DW_AT_static_link:
- case DW_AT_use_location:
- case DW_AT_vtable_elem_location:
- out->cl = DW_cl_loclistptr;
- break;
-
- case DW_AT_stmt_list:
- out->cl = DW_cl_lineptr;
- break;
-
- case DW_AT_macro_info:
- out->cl = DW_cl_macptr;
- break;
-
- case DW_AT_ranges:
- out->cl = DW_cl_rangelistptr;
- break;
-
- default:
- /* These forms are constants only if they do not allow one
- of the loclistptr, lineptr, macptr, or rangelistptr
- classes. */
- gcc_assert (!(class_mask & (DW_cl_loclistptr
- | DW_cl_lineptr
- | DW_cl_macptr
- | DW_cl_rangelistptr)));
- if (form == DW_FORM_sdata)
- {
- out->cl = DW_cl_sconstant;
- out->u.sconstant = sdata;
- }
- else
- {
- out->cl = DW_cl_uconstant;
- out->u.uconstant = data;
- }
- }
- break;
- }
-
- case DW_FORM_flag:
- out->cl = DW_cl_flag;
- out->u.flag = (lto_read_ubyte (fd) != 0);
- break;
-
- case DW_FORM_ref_addr:
- {
- uint64_t offset;
-
- /* The standard says
- "In the 32-bit DWARF format, this offset is a 4-byte unsigned
- value; in the 64-bit DWARF format, it is an 8-byte unsigned
- value"
- FIXME: Dwarf2 is different than Dwarf3 here: Dwarf2 says offet is
- the native address size and not offset size.
- */
- if (!fd->dwarf64)
- offset = lto_read_uword (fd);
- else
- offset = lto_read_udword (fd);
-
- out->cl = DW_cl_reference;
- out->u.reference
- = lto_resolve_reference (info_fd,
- offset,
- context,
- form_context);
- }
- break;
-
- case DW_FORM_ref1:
- case DW_FORM_ref2:
- case DW_FORM_ref4:
- case DW_FORM_ref8:
- case DW_FORM_ref_udata:
- {
- uint64_t offset;
- /* Read the offset from the start of the compilation unit to
- the referenced DIE. */
- switch (form)
- {
- case DW_FORM_ref1:
- offset = lto_read_ubyte (fd);
- break;
- case DW_FORM_ref2:
- offset = lto_read_uhalf (fd);
- break;
- case DW_FORM_ref4:
- offset = lto_read_uword (fd);
- break;
- case DW_FORM_ref8:
- offset = lto_read_udword (fd);
- break;
- case DW_FORM_ref_udata:
- offset = lto_read_uleb128 (fd);
- break;
- default:
- gcc_unreachable ();
- break;
- }
- out->cl = DW_cl_reference;
- out->u.reference
- = (lto_die_ptr) ((context->cu_start
- + lto_check_size_t_val (offset,
- "offset too large")));
- if (out->u.reference >= (lto_die_ptr) context->cu_end)
- lto_file_corrupt_error (fd);
- }
- break;
-
- case DW_FORM_block:
- case DW_FORM_block1:
- case DW_FORM_block2:
- case DW_FORM_block4:
- {
- uint64_t length;
- switch (form)
- {
- case DW_FORM_block:
- length = lto_read_uleb128 (fd);
- break;
- case DW_FORM_block1:
- length = lto_read_ubyte (fd);
- break;
- case DW_FORM_block2:
- length = lto_read_uhalf (fd);
- break;
- case DW_FORM_block4:
- length = lto_read_uword (fd);
- break;
- default:
- gcc_unreachable ();
- break;
- }
- out->cl = DW_cl_block;
- out->u.block.length = lto_check_size_t_val (length,
- "block size too large");
- out->u.block.data = fd->cur;
- fd->cur += out->u.block.length;
- if (fd->cur > context->cu_end)
- lto_file_corrupt_error (fd);
- }
- break;
-
- default:
- /* We cannot handle unrecognized forms. We do not even know how
- many bytes we ought to read. */
- fatal_error ("unsupported DWARF form " HOST_WIDEST_INT_PRINT_UNSIGNED,
- form);
- break;
- }
- /* Make sure that we actually read something. */
- gcc_assert (out->cl != DW_cl_error);
- /* Check the data read is of a class appropriate for the attribute. */
- if (!(out->cl & class_mask))
- lto_file_corrupt_error (fd);
-}
-
-/* Convert the attribute data to an int. */
-static int
-attribute_value_as_int (DWARF2_form_data *attr_data)
-{
- switch (attr_data->cl)
- {
- case DW_cl_uconstant:
- return lto_check_int_val (attr_data->u.uconstant,
- "unsigned value cannot be converted to int");
- case DW_cl_sconstant:
- if (attr_data->u.sconstant <= INT_MAX
- && attr_data->u.sconstant >= INT_MIN)
- return (int)attr_data->u.sconstant;
- else
- fatal_error ("signed value cannot be converted to int");
- default:
- fatal_error ("cannot interpret attribute value as integer");
- }
-}
-
-/* A helper function: convert an unsigned HOST_WIDE_INT to a signed
- HOST_WIDE_INT. According to ISO C, the obvious conversion is undefined
- if the unsigned value is larger than the largest positive signed
- HOST_WIDE_INT. There are many other places in GCC that assume it works
- (and, more specifically, that a two's-complement representation is used
- for signed integers on the host machine), but to be pedantic here,
- we'll split out the conversion into its own function so that it could
- be reimplemented. */
-
-static HOST_WIDE_INT
-make_signed_host_wide_int (unsigned HOST_WIDE_INT u)
-{
- return (HOST_WIDE_INT) u;
-}
-
-/* Convert the attribute value to an integer constant of type TYPE. If
- TYPE is null, choose an appropriate signed/unsigned int type, depending
- on the form of the attribute data. This doesn't do any checking to make
- sure that the constant value can actually be represented in the indicated
- TYPE; we'll assume that the compiler is smart enough not to emit such
- DWARF constants in the first place. */
-static tree
-attribute_value_as_constant (DWARF2_form_data *attr_data, tree type)
-{
- switch (attr_data->cl)
- {
- case DW_cl_uconstant:
- {
- uint64_t u = attr_data->u.uconstant;
- if (!type)
- type = unsigned_type_node;
- if (sizeof (HOST_WIDE_INT) >= sizeof (uint64_t))
- return build_int_cstu (type, u);
- else
- {
- int size = sizeof (HOST_WIDE_INT);
- int nbits = size * CHAR_BIT;
- gcc_assert (size * 2 >= (int) sizeof (uint64_t));
- return build_int_cst_wide (type, (unsigned HOST_WIDE_INT)u,
- make_signed_host_wide_int (u >> nbits));
- }
- }
- case DW_cl_sconstant:
- {
- int64_t s = attr_data->u.sconstant;
- if (!type)
- type = integer_type_node;
- if (sizeof (HOST_WIDE_INT) >= (int) sizeof (uint64_t))
- return build_int_cst (type, s);
- else
- {
- int size = sizeof (HOST_WIDE_INT);
- int nbits = size * BITS_PER_UNIT;
- gcc_assert (size * 2 >= (int) sizeof (int64_t));
- return build_int_cst_wide (type, (unsigned HOST_WIDE_INT)s,
- make_signed_host_wide_int (s >> nbits));
- }
- }
- default:
- fatal_error ("cannot interpret attribute value as integer");
- }
-}
-
-/* DIE Cache
-
- Some DIEs (like those for types and declarations) may be referred
- to explicitly, rather than just included in the DWARF tree. So as
- to avoid having to repeatedly process the same subtrees, we cache
- the trees assocaited with DIEs. The DIE cache is implemented as a
- hash table, mapping in-memory DIE addresses to {TYPE,DECL}
- nodes. */
-
-static hashval_t
-lto_cache_hash (const void *data)
-{
- const lto_die_cache_entry *entry = data;
-
- return htab_hash_pointer (entry->die);
-}
-
-static int
-lto_cache_eq (const void *data, const void *key)
-{
- const lto_die_cache_entry *entry = data;
-
- return entry->die == key;
-}
-
-/* Record the fact that DIE refers to VAL. */
-static void
-lto_cache_store_DIE (lto_info_fd *fd,
- lto_die_ptr die,
- tree val)
-{
- void **slot;
- lto_die_cache_entry *entry;
-
- gcc_assert (TYPE_P (val) || DECL_P (val));
- /* Find a place to put the cached value. */
- slot = htab_find_slot_with_hash (fd->die_cache, die,
- htab_hash_pointer (die),
- INSERT);
- if (!*slot)
- {
- /* Store the value. */
- entry = ggc_alloc (sizeof (lto_die_cache_entry));
- entry->die = die;
- entry->val = val;
- entry->sibling = fd->base.cur;
- *slot = entry;
- }
- else
- {
- /* We should not change the value once created. */
- gcc_assert (((lto_die_cache_entry *) *slot)->val == val);
- }
-}
-
-/* If FD points to a DIE that has already been processed, return the
- cached value. If SKIP is true and the DIE has already been processed,
- adjust FD to skip over the DIE and its children and point to its next
- sibling. */
-static tree
-lto_cache_lookup_DIE (lto_info_fd *fd, lto_die_ptr die, bool skip)
-{
- lto_die_cache_entry *entry;
-
- entry = htab_find_with_hash (fd->die_cache, die,
- htab_hash_pointer (die));
- if (entry)
- {
- if (skip)
- fd->base.cur = entry->sibling;
- return entry->val;
- }
- else
- return NULL_TREE;
-}
-
-
-/* Some DIEs (notably those for DW_TAG_subrange_type and
- DW_TAG_enumeration_type) may include either or both of base type and
- byte size attributes; the byte size is supposed to modify the base
- type. Put them together and return the resulting type.
- Additionally enforce the restriction that the base type must be
- a complete integral type.
- If neither attribute is specified, then return integer_type as the default.
-*/
-
-#define lto_find_integral_type(base,byte,got) lto_find_integral_type_1 (base, byte, got, false)
-
-static tree
-lto_find_integral_type_1 (tree base_type, int byte_size, bool got_byte_size, bool unsignedp)
-{
- int nbits = byte_size * BITS_PER_UNIT;
-
- if (! base_type)
- {
- if (! got_byte_size)
- base_type = unsignedp ? unsigned_type_node : integer_type_node;
- else if (nbits == INT_TYPE_SIZE)
- base_type = unsignedp ? unsigned_type_node : integer_type_node;
- else if (nbits == CHAR_TYPE_SIZE)
- base_type = unsignedp ? unsigned_char_type_node : char_type_node;
- else if (nbits == SHORT_TYPE_SIZE)
- base_type = unsignedp ? short_unsigned_type_node : short_integer_type_node;
- else if (nbits == LONG_TYPE_SIZE)
- base_type = unsignedp ? long_unsigned_type_node : long_integer_type_node;
- else if (nbits == LONG_LONG_TYPE_SIZE)
- base_type = unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node;
- else
- lto_abi_mismatch_error ();
- }
- else if (! INTEGRAL_TYPE_P (base_type)
- || !TYPE_SIZE (base_type)
- || !host_integerp (TYPE_SIZE (base_type), 1))
- lto_abi_mismatch_error ();
- else if (!got_byte_size)
- return base_type;
- else if (nbits <= tree_low_cst (TYPE_SIZE (base_type), 1))
- base_type = lang_hooks.types.type_for_size (nbits, /*unsigned=*/true);
- else
- sorry ("size of base type (%d bits) smaller than specified size (%d bits)",
- (int) tree_low_cst (TYPE_SIZE (base_type), 1),
- nbits);
- return base_type;
-}
-
-/* DIE Readers
-
- There is a DIE reader function for each supported kind of DIE.
- DIEs of type DW_TAG_<tag> are read by lto_read_<tag>_DIE. If
- convenient, a single reader may handle several related types of
- DIEs. If a reader handles DW_TAG_<tag1>, DW_TAG_<tag2>, ...,
- DW_TAG_<tagn>, it should be named
- lto_read_<tag1>_<tag2>_..._<tagn>_DIE.
-
- Each DIE reader is responsible for reading a DIE and its children.
- In general, the form of each DIE reader is:
-
- static tree
- lto_read_tag_DIE (lto_info_fd *fd,
- lto_die_ptr die,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
- {
- gcc_assert (abbrev->tag == DW_TAG_<tag>);
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_attr1:
- ... handle this attribute ...
- ;
-
- case DW_AT_attr2:
- ... handle this attribute ...
- ;
- }
- LTO_END_READ_ATTRS ();
-
- lto_read_child_DIEs (fd, abbrev, context);
-
- return ...tree representing decoded DIE;
- }
-
- The set of attributes handled should include (at least) all the
- attributes actually emitted by GCC. Uninteresting attributes may
- simply be ignored, but they should be named. Attributes that you
- know are important, but for which support has not yet been
- implemented, should be handled by calling
- lto_unsupported_attr_error. As a special case, you do not need to
- handle DW_AT_sibling; this attribute is just a hint, and is ignored
- everywhere. LTO_{BEGIN,END}_READ_ATTRS add a default case
- that issues about errors for unhandled attributes to help to
- enforce these rules.
-
- These rules may seem in contrast to the normal rules for a DWARF
- consumer which suggest that consumers should just ignore entries they
- do not understand. However, in this situation, we can assume that the
- input files came from GCC itself (so we do not need to worry about
- extensions from other tools). Furthermore, we must be concerned
- that ignoring entries might result in silent wrong-code generation.
-
- The CONTEXT argument is passed down to child DIEs from parent DIEs.
-
- After writing a new DIE reader function, add function to the
- READERS array in lto_read_DIE.
-
- There is no need for a comment above each DIE reader as their
- functionality is described by this meta-comment. */
-
-/* Macro to create the beginning of a loop for reading attributes for
- a DIE. The variables FD, ABBREV, and CONTEXT must be defined by
- the caller.
-
- This macro should not be used by DIE readers directly; use
- LTO_BEGIN_READ_ATTRS instead. */
-#define LTO_BEGIN_READ_ATTRS_UNCHECKED() \
- do { \
- const DWARF2_attr *attr; \
- for (attr = abbrev->attrs; \
- attr != abbrev->attrs + abbrev->num_attrs; \
- ++attr) \
- { \
- lto_context *old_context = context; \
- lto_context *new_context = context; \
- DWARF2_form_data attr_data; \
- \
- lto_read_form (fd, attr, context, &new_context, \
- &attr_data); \
- if (context != new_context) \
- context = new_context; \
- switch (attr->name) \
- { \
- case DW_AT_sibling: \
- break;
-
-/* Like LTO_BEGIN_READ_ATTRS_UNCHECKED, except that unhandled
- attribute are treated as indicating a corrupt object file.
-
- NB: The lto_context may change depending on the form, so be careful
- when falling through to another attr name. */
-#define LTO_BEGIN_READ_ATTRS() \
- LTO_BEGIN_READ_ATTRS_UNCHECKED() \
- default: \
- fprintf (stderr, "Unhandled attribute in %s: %s\n", __FUNCTION__, dwarf_attr_name (attr->name)); \
- lto_file_corrupt_error ((lto_fd *)fd); \
- break;
-
-/* Macro to create the end of a loop for reading attributes from a
- DIE. */
-#define LTO_END_READ_ATTRS() \
- } \
- if (context != old_context) \
- { \
- XDELETE (context); \
- context = old_context; \
- } \
- } \
- } while (false)
-
-/* Print an error message indicating that an attribute (as indicated
- by ATTR) has been read from a DIE (as indicated by ABBREV) -- but
- that there is not yet code to handle this attribute. */
-static void
-lto_unsupported_attr_error (const DWARF2_abbrev *abbrev,
- const DWARF2_attr *attr)
-{
- sorry ("unsupported attribute " HOST_WIDEST_INT_PRINT_UNSIGNED " for tag "
- HOST_WIDEST_INT_PRINT_UNSIGNED, attr->name, abbrev->tag);
-}
-
-/* Return an IDENTIFIER_NODE for the string constant indicated by
- DATA. */
-static tree
-lto_get_identifier (const DWARF2_form_data *data)
-{
- gcc_assert (data->cl == DW_cl_string);
- /* The input string is presently in memory mapped in from the DWARF
- section. Because the input to get_identifier must already be in
- GC-able memory, we must copy the string data. */
- return get_identifier (ggc_strdup (data->u.string));
-}
-
-/* Read a type DIE (located at REFERENCE) from FD. CONTEXT is the
- current context within the compilation unit. Returns the _TYPE
- node corresponding to the DIE.
- FIXME: Skipping around in the DWARF tree is potentially buggy if
- there are references to types thare arbitrarily nested children of
- other DIEs, because this will attempt to read those children without
- the context parentdata that would otherwise be set up by their parents.
- Current uses of parentdata for parsing DW_TAG_ENUMERATOR and
- DW_TAG_MEMBER ought to be OK since those are not types. */
-static tree
-lto_read_referenced_type_DIE (lto_info_fd *fd,
- lto_context *context,
- lto_die_ptr reference)
-{
- tree type;
-
- /* Check that the reference is in range. We use an assert, rather
- than calling lto_file_corrupt_error, because REFERENCE should be
- checked for validity when it is read from the file. */
- gcc_assert (reference >= (lto_die_ptr) context->cu_start
- && reference < (lto_die_ptr) context->cu_end);
- type = lto_cache_lookup_DIE (fd, reference, false);
- if (!type)
- {
- const char *saved_cur = fd->base.cur;
- tree parentdata = context->parentdata;
-
- /* Move the file pointer to the referenced location. */
- fd->base.cur = (const char *) reference;
- /* Reset parent data in context. */
- context->parentdata = NULL_TREE;
- /* Read the DIE, which we insist must be a type. */
- type = lto_read_DIE (fd, context, NULL);
- /* Restore the file pointer and parentdata. */
- fd->base.cur = saved_cur;
- context->parentdata = parentdata;
- }
- /* The DIE read should have been a type. */
- if (!type || !TYPE_P (type))
- lto_file_corrupt_error ((lto_fd *)fd);
-
- return type;
-}
-
-static tree
-lto_read_compile_unit_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- gcc_assert (abbrev->tag == DW_TAG_compile_unit);
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_language:
- {
- int lang = attribute_value_as_int (&attr_data);
- switch (lang)
- {
- case DW_LANG_C:
- case DW_LANG_C89:
- case DW_LANG_C99:
- case DW_LANG_C_plus_plus:
- break;
-
- default:
- error ("unsupported language %d", lang);
- break;
- }
- context->language = lang;
- break;
- }
-
- case DW_AT_low_pc:
- case DW_AT_high_pc:
- case DW_AT_entry_pc:
- case DW_AT_ranges:
- case DW_AT_name:
- case DW_AT_stmt_list:
- case DW_AT_macro_info:
- case DW_AT_comp_dir:
- case DW_AT_producer:
- case DW_AT_use_UTF8:
- case DW_AT_segment:
- /* Ignore. */
- break;
-
- case DW_AT_identifier_case:
- case DW_AT_base_types:
- lto_unsupported_attr_error (abbrev, attr);
- break;
- }
- LTO_END_READ_ATTRS ();
-
- lto_read_child_DIEs (fd, abbrev, context);
- return NULL_TREE;
-}
-
-static tree
-lto_read_array_type_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree type = NULL_TREE;
- VEC(tree,heap) *dims;
- int ndims;
- int order = -1;
- int i, istart, iend;
- bool is_vector = false;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_decl_column:
- case DW_AT_decl_file:
- case DW_AT_decl_line:
- /* Ignore. */
- break;
-
- case DW_AT_GNU_vector:
- is_vector = true;
- break;
-
- case DW_AT_type:
- type = lto_read_referenced_type_DIE (fd,
- context,
- attr_data.u.reference);
- break;
-
- case DW_AT_ordering:
- switch (attribute_value_as_int (&attr_data))
- {
- case DW_ORD_col_major:
- /* Process dimensions left-to-right */
- order = 1;
- break;
- case DW_ORD_row_major:
- /* Process dimensions right-to-left */
- order = -1;
- break;
- default:
- lto_file_corrupt_error ((lto_fd *)fd);
- }
- break;
-
- case DW_AT_byte_size:
- case DW_AT_stride:
- lto_unsupported_attr_error (abbrev, attr);
- break;
-
- }
- LTO_END_READ_ATTRS ();
-
- {
- tree type = lto_cache_lookup_DIE (fd, die, false);
-
- if (type) return type;
- }
-
- /* The DW_AT_type attribute is required. */
- if (!type)
- lto_file_corrupt_error ((lto_fd *)fd);
-
- /* Array dimensions are given as children of the DW_TAG_array_type DIE,
- and are tagged with either DW_TAG_subrange_type or
- DW_TAG_enumeration_type. */
- dims = lto_collect_child_DIEs (fd, abbrev, context);
- ndims = VEC_length (tree, dims);
-
- if (is_vector)
- {
- /* We should have a lone child DIE describing how many packed
- elements this vector type has. The DW_AT_type attribute
- describes the type of the vector elements. */
- tree range;
- tree upper_bound;
- HOST_WIDE_INT count;
-
- gcc_assert (ndims == 1);
-
- range = VEC_index (tree, dims, 0);
- upper_bound = TYPE_MAX_VALUE (range);
- count = TREE_INT_CST_LOW (upper_bound);
-
- /* RANGE describes the indices of the vector, so we need to add 1
- to find the number of elements. */
- type = build_vector_type (type, (int) count + 1);
- }
- else
- {
- /* Construct and cache the array type object for our caller. */
- if (ndims == 0)
- type = build_array_type (type, NULL_TREE);
- else
- {
- if (order == -1)
- {
- istart = ndims - 1;
- iend = -1;
- }
- else
- {
- gcc_assert (order == 1);
- istart = 0;
- iend = ndims;
- }
- for (i = istart; i != iend; i += order)
- {
- tree dim = VEC_index (tree, dims, i);
- if (!dim || ! INTEGRAL_TYPE_P (dim))
- lto_file_corrupt_error ((lto_fd *)fd);
- type = build_array_type (type, dim);
- }
- }
- }
- VEC_free (tree, heap, dims);
- return type;
-}
-
-
-static tree
-lto_read_structure_union_class_type_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree type = NULL_TREE;
- bool declaration = false;
- tree name = NULL_TREE;
- int size = 0;
- unsigned int align = 0;
- tree parentdata;
- VEC(tree,heap) *children;
- int i, n;
- tree *fields_tail;
- tree *methods_tail;
- record_layout_info rli;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_decl_column:
- case DW_AT_decl_file:
- case DW_AT_decl_line:
- /* Ignore. */
- break;
-
- case DW_AT_name:
- name = lto_get_identifier (&attr_data);
- break;
-
- case DW_AT_byte_size:
- if (attr_data.cl == DW_cl_uconstant || attr_data.cl == DW_cl_sconstant)
- size = attribute_value_as_int (&attr_data);
- else
- sorry ("can't handle dynamically-sized struct/union/class types");
- break;
-
- case DW_AT_declaration:
- declaration = attr_data.u.flag;
- break;
-
- case DW_AT_specification:
- type = lto_read_referenced_type_DIE (fd, context, attr_data.u.reference);
- if (TREE_CODE (type) != RECORD_TYPE
- && TREE_CODE (type) != UNION_TYPE
- && TREE_CODE (type) != QUAL_UNION_TYPE)
- lto_file_corrupt_error ((lto_fd *) fd);
- break;
-
- }
- LTO_END_READ_ATTRS ();
-
- /* Create the type, if this isn't a definition of a previously
- forward-declared type. */
- if (!type)
- {
- switch (abbrev->tag)
- {
- case DW_TAG_structure_type:
- case DW_TAG_class_type:
- type = make_node (RECORD_TYPE);
- break;
-
- case DW_TAG_union_type:
- type = make_node (UNION_TYPE);
- break;
-
- default:
- gcc_unreachable ();
- }
- switch (context->language)
- {
- case DW_LANG_C_plus_plus:
- /* In C++, the name slot gets a TYPE_DECL. */
- if (name)
- {
- tree decl = build_decl (TYPE_DECL, name, type);
- TYPE_NAME (type) = decl;
- TYPE_STUB_DECL (type) = decl;
- }
- else
- TYPE_STUB_DECL (type) = build_decl (TYPE_DECL, NULL_TREE, type);
- break;
-
- case DW_LANG_C:
- case DW_LANG_C89:
- case DW_LANG_C99:
- default:
- /* In C, the name slot gets the identifier which represents the
- only the struct/union tag name, not a type name. TYPE_STUB_DECL
- contains an anonymous decl to be used when emitting debug info. */
- if (name)
- TYPE_NAME (type) = name;
- TYPE_STUB_DECL (type) = build_decl (TYPE_DECL, NULL_TREE, type);
- break;
- }
- }
- if (size)
- {
- TYPE_SIZE (type) = bitsize_int (size * BITS_PER_UNIT);
- TYPE_SIZE_UNIT (type) = size_int (size);
-
- /* Since we already know the size, go ahead and set TYPE_MODE and
- TYPE_ALIGN on the type, so future uses of this type come out
- sane. There are special rules for RECORD_TYPE as regards
- TYPE_MODE, so just do this for UNION_TYPE. */
- if (TREE_CODE (type) == UNION_TYPE)
- {
- compute_record_mode (type);
-
- TYPE_ALIGN (type) = GET_MODE_ALIGNMENT (TYPE_MODE (type));
- }
- }
-
- /* Store this entry so that cases like:
-
- struct foo {
- struct foo *next;
- ....
- }
-
- don't cause infinite recursion. */
- lto_cache_store_DIE (fd, die, type);
-
- /* Process the members. */
- parentdata = context->parentdata;
- context->parentdata = type;
- children = lto_collect_child_DIEs (fd, abbrev, context);
- context->parentdata = parentdata;
-
- n = VEC_length (tree, children);
- fields_tail = &TYPE_FIELDS (type);
- methods_tail = &TYPE_METHODS (type);
- rli = start_record_layout (type);
- for (i = 0; i < n; i++)
- {
- tree child = VEC_index (tree, children, i);
-
- if (!child)
- continue;
-
- switch (TREE_CODE (child))
- {
- case FIELD_DECL:
- /* Field declarations. */
- *fields_tail = child;
- fields_tail = &TREE_CHAIN (child);
- /* FIXME: This is kind of nasty. DWARF doesn't encode the overall
- alignment of the struct/union type, so we'll take a stab at
- recomputing it and hope it comes out the same as for the
- original type. A better solution would be to extend DWARF to
- add an additional attribute for the alignment of the record
- type. */
- if (DECL_ALIGN (child) > align)
- align = DECL_ALIGN (child);
- /* FIXME: mess with propagating mutable/volatile/etc attributes
- back to parent struct type. */
- if (TREE_READONLY (child) || TREE_THIS_VOLATILE (child))
- sorry ("Don't know what to do with readonly or volatile fields");
- break;
-
- case VAR_DECL:
- /* Static variables in a class. */
- *fields_tail = child;
- fields_tail = &TREE_CHAIN (child);
- break;
-
- case FUNCTION_DECL:
- /* Member functions of a class.
- FIXME: Extend the DW_TAG_subprogram reader to recognize
- additional attributes for member functions. */
- *methods_tail = child;
- methods_tail = &TREE_CHAIN (child);
- break;
-
- /* FIXME: Add support for DW_TAG_access_declaration,
- DW_TAG_inheritance, DW_TAG_friend, and DW_TAG_variant_part
- which can appear as children of a class/struct type. */
-
- default:
- if (TYPE_P (child))
- /* Types declared locally within the scope of a class. */
- {
- tree name = TYPE_NAME (child);
- if (name && (TREE_CODE (name) == TYPE_DECL))
- {
- *fields_tail = name;
- fields_tail = &TREE_CHAIN (name);
- }
- if (TREE_CODE (child) == ENUMERAL_TYPE)
- {
- /* Add enumerators to TYPE_FIELDS, too. */
- tree pair;
- for (pair = TYPE_VALUES (child); pair;
- pair = TREE_CHAIN (pair))
- {
- tree decl = build_decl (CONST_DECL, TREE_PURPOSE (pair),
- TREE_VALUE (pair));
- *fields_tail = decl;
- fields_tail = &TREE_CHAIN (decl);
- }
- }
- }
- }
-
- if (TREE_CODE_CLASS (TREE_CODE (child)) == tcc_declaration)
- place_field (rli, child);
- }
-
- /* We have all the information we need about this structure. */
- finish_record_layout (rli, false);
-
- VEC_free (tree, heap, children);
- free (rli);
-
- /* Finish debugging output for this type. */
- if (!declaration)
- rest_of_type_compilation (type, /*top_level=*/1);
- return type;
-}
-
-static tree
-lto_read_enumeration_type_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- VEC(tree,heap) *enumerators;
- int i, n;
- tree type;
- tree base = NULL_TREE;
- tree name = NULL_TREE;
- int byte_size = 0;
- bool got_byte_size = false;
- tree enumlist = NULL_TREE;
- tree parentdata;
- bool use_unsigned = true;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_decl_column:
- case DW_AT_decl_file:
- case DW_AT_decl_line:
- /* Ignore. */
- break;
-
- case DW_AT_name:
- name = lto_get_identifier (&attr_data);
- break;
-
- case DW_AT_type:
- base = lto_read_referenced_type_DIE (fd,
- context,
- attr_data.u.reference);
- break;
-
- case DW_AT_byte_size:
- byte_size = attribute_value_as_int (&attr_data);
- got_byte_size = true;
- break;
-
- case DW_AT_stride:
- lto_unsupported_attr_error (abbrev, attr);
- }
- LTO_END_READ_ATTRS ();
-
- /* Build the (empty) enumeration type. */
- type = make_node (ENUMERAL_TYPE);
- if (name)
- TYPE_NAME (type) = name;
-
- /* Process the enumerators. */
- parentdata = context->parentdata;
- context->parentdata = type;
- enumerators = lto_collect_child_DIEs (fd, abbrev, context);
- context->parentdata = parentdata;
-
- n = VEC_length (tree, enumerators);
- for (i = n-1; i >= 0; i--)
- {
- tree pair = VEC_index (tree, enumerators, i);
- /* Make sure the child was actually an enumerator, which parse as
- (name, value) pairs. */
- if (! pair
- || TREE_CODE (pair) != TREE_LIST
- || ! TREE_VALUE (pair)
- || TREE_CODE (TREE_VALUE (pair)) != INTEGER_CST
- || ! TREE_PURPOSE (pair)
- || TREE_CODE (TREE_PURPOSE (pair)) != IDENTIFIER_NODE)
- lto_abi_mismatch_error ();
- /* Determine whether to use an unsigned type as the base. */
- if (INT_CST_LT (TREE_VALUE (pair), integer_zero_node))
- use_unsigned = false;
- /* Link the enumerators together. */
- TREE_CHAIN (pair) = enumlist;
- enumlist = pair;
- }
-
- /* Reconcile base type and byte size attributes. */
- base = lto_find_integral_type_1 (base, byte_size, got_byte_size,
- use_unsigned);
-
- /* Fill in various bits from the base type. */
- TYPE_MIN_VALUE (type) = TYPE_MIN_VALUE (base);
- TYPE_MAX_VALUE (type) = TYPE_MAX_VALUE (base);
- TYPE_UNSIGNED (type) = TYPE_UNSIGNED (base);
- TYPE_SIZE (type) = 0;
- TYPE_PRECISION (type) = TYPE_PRECISION (base);
- layout_type (type);
-
- TYPE_VALUES (type) = enumlist;
- TYPE_STUB_DECL (type) = build_decl (TYPE_DECL, NULL_TREE, type);
-
- /* Finish debugging output for this type. */
- rest_of_type_compilation (type, /*top_level=*/1);
- return type;
-}
-
-static tree
-lto_read_enumerator_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree name = NULL_TREE;
- tree value = NULL_TREE;
- tree type = context->parentdata;
-
- /* Enumerators can only appear as children of an enumeral type DIE. The
- parent has already created the enum type node and stashed it in the
- context. */
- if (!type || TREE_CODE (type) != ENUMERAL_TYPE)
- lto_file_corrupt_error ((lto_fd *)fd);
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_decl_column:
- case DW_AT_decl_file:
- case DW_AT_decl_line:
- /* Ignore. */
- break;
-
- case DW_AT_name:
- name = lto_get_identifier (&attr_data);
- break;
-
- case DW_AT_const_value:
- value = attribute_value_as_constant (&attr_data, type);
- break;
- }
- LTO_END_READ_ATTRS ();
-
- lto_read_child_DIEs (fd, abbrev, context);
-
- /* Return a TREE_LIST with the name as TREE_PURPOSE and the value as
- TREE_VALUE. */
- return tree_cons (name, value, NULL_TREE);
-}
-
-static tree
-lto_read_variable_formal_parameter_constant_DIE (lto_info_fd *fd,
- lto_die_ptr die,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree name;
- tree asm_name;
- tree type;
- bool external;
- bool declaration;
- bool artificial = false;
- enum tree_code code;
- tree decl;
- tree specification = NULL_TREE;
- tree abstract_origin = NULL_TREE;
-
- gcc_assert (abbrev->tag == DW_TAG_variable
- || abbrev->tag == DW_TAG_formal_parameter
- || abbrev->tag == DW_TAG_constant);
-
- name = NULL_TREE;
- asm_name = NULL_TREE;
- type = NULL_TREE;
- external = false;
- declaration = false;
- code = ERROR_MARK;
- decl = NULL_TREE;
- specification = NULL_TREE;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_location:
- case DW_AT_segment:
- case DW_AT_default_value:
- case DW_AT_start_scope:
- case DW_AT_decl_column:
- case DW_AT_decl_file:
- case DW_AT_decl_line:
- case DW_AT_const_value:
- /* Ignore. */
- break;
-
- case DW_AT_abstract_origin:
- abstract_origin = lto_read_DIE_at_ptr (fd, context,
- attr_data.u.reference);
- break;
-
- case DW_AT_specification:
- if (abbrev->tag == DW_TAG_variable)
- specification = lto_read_DIE_at_ptr (fd, context,
- attr_data.u.reference);
- break;
-
- case DW_AT_name:
- name = lto_get_identifier (&attr_data);
- /* Assume that the assembler name is the same as the source name
- -- unless a DW_AT_MIPS_linkage_name attribute is
- available. */
- if (!asm_name)
- asm_name = name;
- break;
-
- case DW_AT_artificial:
- artificial = attr_data.u.flag;
- break;
-
- case DW_AT_external:
- external = attr_data.u.flag;
- break;
-
- case DW_AT_type:
- type = lto_read_referenced_type_DIE (fd,
- context,
- attr_data.u.reference);
- break;
-
- case DW_AT_declaration:
- declaration = attr_data.u.flag;
- break;
-
- case DW_AT_variable_parameter:
- case DW_AT_is_optional:
- lto_unsupported_attr_error (abbrev, attr);
- break;
-
- case DW_AT_MIPS_linkage_name:
- /* Set the DECL_ASSEMBLER_NAME so we don't have to remangle
- names in LTO. */
- asm_name = lto_get_identifier (&attr_data);
- break;
- }
- LTO_END_READ_ATTRS ();
-
- /* Build the declaration. */
- switch (abbrev->tag)
- {
- case DW_TAG_variable:
- code = VAR_DECL;
- break;
- case DW_TAG_formal_parameter:
- code = PARM_DECL;
- break;
- case DW_TAG_constant:
- /* GCC doesn't have a distinct tree representation for this, and never
- generates this DWARF tag. (CONST_DECL is only for enumerators.)
- Do something reasonable if we see one. */
- code = VAR_DECL;
- break;
- default:
- gcc_unreachable ();
- break;
- }
-
- if (code == VAR_DECL
- && context->scope
- && TREE_CODE (context->scope) == FUNCTION_DECL
- && !declaration)
- /* We are only interested in variables with static storage
- duration. */
- ;
- else
- {
- tree referenced = NULL_TREE;
-
- /* Check for a referenced declaration. */
- if (!name
- && !type
- && ((specification && TREE_CODE (specification) == code)
- || (abstract_origin && TREE_CODE (abstract_origin) == code)))
- {
- /* Make sure we have one or the other. */
- gcc_assert (!specification || !abstract_origin);
- referenced = specification ? specification : abstract_origin;
- }
-
- /* Copy bits from the referenced declaration. */
- if (referenced && !name)
- name = DECL_NAME (referenced);
- if (referenced && !type)
- type = TREE_TYPE (referenced);
-
- /* Build the tree node for this entity. */
- decl = build_decl (code, name, type);
- DECL_SOURCE_LOCATION (decl) = UNKNOWN_LOCATION;
- DECL_ARTIFICIAL (decl) = artificial;
-
- /* Parameter decls never have external linkage, never need merging,
- etc. */
- if (code == VAR_DECL)
- {
- if (referenced && !asm_name)
- asm_name = DECL_ASSEMBLER_NAME (referenced);
- SET_DECL_ASSEMBLER_NAME (decl, asm_name);
- TREE_PUBLIC (decl) = external;
- DECL_EXTERNAL (decl) = declaration;
- TREE_STATIC (decl) = 1;
- TREE_USED (decl) = 1;
- DECL_COMDAT (decl) = 1;
-
- if (TYPE_QUALS (type) & TYPE_QUAL_CONST)
- TREE_READONLY (decl) = 1;
- if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
- TREE_THIS_VOLATILE (decl) = 1;
-
- if (!TREE_PUBLIC (decl))
- {
- /* Need to ensure static variables between different files
- don't clash unexpectedly. */
- lang_hooks.set_decl_assembler_name (decl);
- rest_of_decl_compilation (decl,
- /*top_level=*/1,
- /*at_end=*/0);
- }
-
- /* If this variable has already been declared, merge the
- declarations. */
- decl = lto_symtab_merge_var (decl);
- if (decl != error_mark_node)
- /* Record this variable in the DIE cache so that it can be
- resolved from the bodies of functions. */
- lto_cache_store_DIE (fd, die, decl);
- }
- else if (code == PARM_DECL)
- {
- *context->last_parm_type = build_tree_list (NULL_TREE,
- TREE_TYPE (decl));
- context->last_parm_type
- = &TREE_CHAIN (*context->last_parm_type);
- }
- }
-
- lto_read_child_DIEs (fd, abbrev, context);
- return decl;
-}
-
-/* Used when we only care about reading the DIE's children. */
-
-static tree
-lto_read_only_for_child_DIEs (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- LTO_BEGIN_READ_ATTRS_UNCHECKED ()
- {
- }
- LTO_END_READ_ATTRS ();
-
- lto_read_child_DIEs (fd, abbrev, context);
-
- return NULL_TREE;
-}
-
-static tree
-lto_read_member_DIE (lto_info_fd *fd,
- lto_die_ptr die,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree name = NULL_TREE;
- tree type = NULL_TREE;
- tree byte_offset = NULL_TREE;
- tree bit_offset = NULL_TREE;
- tree bit_size = NULL_TREE;
- tree byte_size = NULL_TREE;
- bool bit_field_p = false;
- tree decl;
- int code;
- tree bitpos;
- unsigned int bitpos_align;
-
- /* The DWARF spec implies that data member entries can appear outside of a
- structure, union, or class, but doesn't say what that might mean. */
- code = context->parentdata ? TREE_CODE (context->parentdata) : ERROR_MARK;
- if (code != RECORD_TYPE
- && code != UNION_TYPE
- && code != QUAL_UNION_TYPE)
- sorry ("member declaration not inside structure, class, or union");
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_decl_column:
- case DW_AT_decl_file:
- case DW_AT_decl_line:
- /* Ignore. */
- break;
-
- case DW_AT_name:
- name = lto_get_identifier (&attr_data);
- break;
-
- case DW_AT_type:
- type = lto_read_referenced_type_DIE (fd,
- context,
- attr_data.u.reference);
- break;
-
- case DW_AT_data_member_location:
- /* This is a constant or location description giving the offset in
- bytes from the beginning of the data member. If it's a location
- description, it's an expression that would be evaluated as if the
- offset of the beginning of the structure has already been pushed
- on the stack. */
- if (attr_data.cl == DW_cl_uconstant || attr_data.cl == DW_cl_sconstant)
- byte_offset = attribute_value_as_constant (&attr_data, bitsizetype);
- else if (attr_data.cl != DW_cl_block)
- lto_file_corrupt_error ((lto_fd *) fd);
- else
- /* Instead of doing a general location evaluation, just look
- for the patterns generated by dwarf2out.c. */
- {
- lto_fd datafd;
- uint64_t operator;
-
- lto_fd_init (&datafd, "DW_AT_data_member_location data",
- ((lto_fd *)fd)->file);
- datafd.start = (const char *)attr_data.u.block.data;
- datafd.end = datafd.start + attr_data.u.block.length;
- datafd.cur = datafd.start;
- datafd.dwarf64 = ((lto_fd *)fd)->dwarf64;
-
- operator = lto_read_uleb128 (&datafd);
- if (operator == DW_OP_constu || operator == DW_OP_plus_uconst)
- {
- uint64_t operand = lto_read_uleb128 (&datafd);
- HOST_WIDE_INT opval =
- lto_check_HOST_WIDE_INT_val (operand, "offset too large");
- byte_offset = build_int_cst (bitsizetype, opval);
- if (datafd.cur != datafd.end)
- lto_unsupported_attr_error (abbrev, attr);
- }
- else
- lto_unsupported_attr_error (abbrev, attr);
- }
- break;
-
- case DW_AT_byte_size:
- byte_size = attribute_value_as_constant (&attr_data, bitsizetype);
- break;
-
- case DW_AT_bit_offset:
- bit_offset = attribute_value_as_constant (&attr_data, bitsizetype);
- bit_field_p = true;
- break;
-
- case DW_AT_bit_size:
- bit_size = attribute_value_as_constant (&attr_data, bitsizetype);
- bit_field_p = true;
- break;
-
- case DW_AT_accessibility:
- case DW_AT_mutable:
- lto_unsupported_attr_error (abbrev, attr);
- break;
-
- }
- LTO_END_READ_ATTRS ();
-
- /* Complain if we didn't get a type. */
- if (! type)
- lto_file_corrupt_error ((lto_fd *) fd);
-
- /* Complain if we got a non-zero offset or bit field attribute for a union,
- or a missing offset when we're not processing a union, or incomplete
- bit field information. */
- if (code == UNION_TYPE)
- {
- if (bit_field_p)
- lto_file_corrupt_error ((lto_fd *) fd);
- if (!byte_offset)
- byte_offset = bitsize_zero_node;
- else if (! integer_zerop (byte_offset))
- lto_file_corrupt_error ((lto_fd *) fd);
- }
- else
- {
- if (! byte_offset)
- lto_file_corrupt_error ((lto_fd *) fd);
- if (bit_field_p && ! (bit_size && bit_offset))
- lto_file_corrupt_error ((lto_fd *) fd);
- }
-
- /* Make sure we got a byte size if we need one, or that it's not
- incompatible with the specified type. */
- if (bit_field_p && ! byte_size)
- byte_size = fold_convert (bitsizetype, TYPE_SIZE_UNIT (type));
- else if (!bit_field_p && byte_size &&
- !tree_int_cst_equal (byte_size, TYPE_SIZE_UNIT (type)))
- sorry ("don't know what to do with DW_AT_byte_size for non-bitfields");
-
- /* Compute the bit position of the field relative to the beginning of
- its containing structure. */
- bitpos = size_binop (MULT_EXPR, byte_offset, bitsize_unit_node);
- if (bit_field_p)
- {
- /* DWARF's bit offset is the number of bits from the most significant
- bit of the anonymous containing object to the most significant
- bit of the bit field. So we need to reverse to count from the
- opposite end of the container in the little-endian case. */
- if (! BYTES_BIG_ENDIAN)
- {
- tree container_bit_size =
- size_binop (MULT_EXPR, byte_size, bitsize_unit_node);
- bit_offset = size_binop (MINUS_EXPR,
- size_binop (MINUS_EXPR,
- container_bit_size, bit_offset),
- bit_size);
- }
- bitpos = size_binop (PLUS_EXPR, bitpos, bit_offset);
- }
-
- /* Next we need to find the alignment of the bit position. This bit of
- code copied from the Ada front end. */
- if (host_integerp (bitpos, 1))
- bitpos_align = (tree_low_cst (bitpos, 1) & -
- tree_low_cst (bitpos, 1));
- else
- bitpos_align = BITS_PER_UNIT;
-
- /* Build the decl and fill in its attributes. For bit fields, create
- and layout the field with its declared type, then overwrite it with
- a type of the specified precision; this is the way the C front end
- does it, and doing it the same way ensures that all of the various
- types, sizes, and alignments are compatible with those generated by
- C. */
- decl = build_decl (FIELD_DECL, name, type);
- DECL_SOURCE_LOCATION (decl) = UNKNOWN_LOCATION;
- if (bit_field_p)
- {
- DECL_SIZE (decl) = bit_size;
- SET_DECL_OFFSET_ALIGN (decl, 1);
- DECL_BIT_FIELD (decl) = true;
- DECL_NONADDRESSABLE_P (decl) = true;
- DECL_BIT_FIELD_TYPE (decl) = type;
- DECL_MODE (decl) = TYPE_MODE (type);
- }
- else
- layout_decl (decl, bitpos_align);
- DECL_CONTEXT (decl) = context->parentdata;
-
- /* Record our new decl as having come from this die, so we can
- resolve references to it from lto data. */
- lto_cache_store_DIE (fd, die, decl);
-
- /* Now set the offset explicitly. This bit of code was stolen from the
- Ada front end. */
- SET_DECL_OFFSET_ALIGN (decl,
- (host_integerp (bitpos, 1)
- ? BIGGEST_ALIGNMENT : BITS_PER_UNIT));
- pos_from_bit (&DECL_FIELD_OFFSET (decl),
- &DECL_FIELD_BIT_OFFSET (decl),
- DECL_OFFSET_ALIGN (decl),
- bitpos);
-
- lto_read_child_DIEs (fd, abbrev, context);
- return decl;
-}
-
-static const DWARF2_abbrev *
-lto_read_abbrev (lto_info_fd *fd)
-{
- uint64_t index;
- const DWARF2_abbrev *abbrev;
-
- /* Read the abbreviation index. */
- index = lto_read_uleb128 ((lto_fd *)fd);
- /* Zero indicates a null entry. */
- if (!index)
- return NULL;
- /* Get the actual abbreviation entry. */
- abbrev = lto_abbrev_lookup (&fd->base.file->debug_abbrev, index);
-
- return abbrev;
-}
-
-
-/* Return a pointer to the data for DECL if possible, NULL otherwise.
- FIXME!!! This function will go away when we stop using dwarf for
- the globals and types. The big difference between this and
- lto_read_section_data is that this function interpretes uses calls
- to libelf that cause the data to be interpreted (copied and
- otherwise manipulated) in a manner that is not necessary for the
- stream protocols that are used for the rest of lto. */
-
-static const void *
-lto_get_body (lto_info_fd *fd,
- lto_context *context ATTRIBUTE_UNUSED,
- enum lto_section_type section_type,
- const char *name)
-{
- lto_file *file;
-
- file = fd->base.file;
- return file->vtable->map_section (file, section_type, name);
-}
-
-/* Read the constructors and initsof FD if possible. */
+/* Read the constructors and inits. */
static void
lto_materialize_constructors_and_inits (struct lto_file_decl_data * file_data)
@@ -2432,7 +50,7 @@ lto_materialize_constructors_and_inits (struct lto_file_decl_data * file_data)
free ((char *)data);
}
-/* Read the function body for DECL out of FD if possible. */
+/* Read the function body for the function associated with NODE if possible. */
static void
lto_materialize_function (struct cgraph_node *node)
@@ -2471,6 +89,7 @@ lto_materialize_function (struct cgraph_node *node)
}
}
else
+ /* ### Shouldn't we just check this and assert if not? */
DECL_EXTERNAL (decl) = 1;
/* Let the middle end know about the function. */
@@ -2481,7 +100,7 @@ lto_materialize_function (struct cgraph_node *node)
cgraph_mark_reachable_node (cgraph_node (decl));
}
-/* Read the function body for DECL out of FD if possible. */
+/* Read the cgraph for this file. */
static void
lto_materialize_cgraph (struct lto_file_decl_data * file_data)
@@ -2491,1175 +110,143 @@ lto_materialize_cgraph (struct lto_file_decl_data * file_data)
free ((char *)data);
}
+/* ### */
+/* Initialize the globals vector with pointers to well-known trees. */
+
+static void
+preload_common_nodes (struct data_in *data_in)
+{
+ unsigned i;
+
+ for (i = 0; i < TI_MAX; i++)
+ VEC_safe_push (tree, heap, data_in->globals_index, global_trees[i]);
+ for (i = 0; i < itk_none; i++)
+ VEC_safe_push (tree, heap, data_in->globals_index, integer_types[i]);
+}
+
+/* ### */
/* Load in the global vars and all of the types from the main symbol
table. */
-static struct lto_file_decl_data*
-lto_read_decls (lto_info_fd *fd,
- lto_context *context,
- const void *data)
+static void
+lto_read_decls (struct lto_file_decl_data *decl_data, const void *data)
{
struct lto_decl_header * header
- = (struct lto_decl_header *) data;
- struct lto_file_decl_data *data_in = xmalloc (sizeof (struct lto_file_decl_data));
+ = (struct lto_decl_header *) data;
- int32_t fields_offset = sizeof (struct lto_decl_header);
+ int32_t types_offset = sizeof (struct lto_decl_header);
+ int32_t fields_offset
+ = types_offset + (header->num_types * sizeof (uint32_t));
int32_t fns_offset
- = fields_offset + (header->num_field_decls * sizeof (lto_ref));
+ = fields_offset + (header->num_field_decls * sizeof (uint32_t));
int32_t vars_offset
- = fns_offset + (header->num_fn_decls * sizeof (lto_ref));
+ = fns_offset + (header->num_fn_decls * sizeof (uint32_t));
int32_t type_decls_offset
- = vars_offset + (header->num_var_decls * sizeof (lto_ref));
+ = vars_offset + (header->num_var_decls * sizeof (uint32_t));
int32_t namespace_decls_offset
- = type_decls_offset + (header->num_type_decls * sizeof (lto_ref));
- int32_t types_offset
- = namespace_decls_offset + (header->num_namespace_decls * sizeof (lto_ref));
+ = type_decls_offset + (header->num_type_decls * sizeof (uint32_t));
+
+ uint32_t *in_types = (uint32_t*)(data + types_offset);
+ uint32_t *in_field_decls = (uint32_t*)(data + fields_offset);
+ uint32_t *in_fn_decls = (uint32_t*)(data + fns_offset);
+ uint32_t *in_var_decls = (uint32_t*)(data + vars_offset);
+ uint32_t *in_type_decls = (uint32_t*)(data + type_decls_offset);
+ uint32_t *in_namespace_decls = (uint32_t*)(data + namespace_decls_offset);
+
+ int32_t main_offset
+ = namespace_decls_offset + (header->num_namespace_decls * sizeof (uint32_t));
+ int32_t string_offset = main_offset + header->main_size;
+#ifdef LTO_STREAM_DEBUGGING
+ int32_t debug_main_offset = string_offset + header->string_size;
+#endif
- lto_ref *in_field_decls = (lto_ref*)(data + fields_offset);
- lto_ref *in_fn_decls = (lto_ref*)(data + fns_offset);
- lto_ref *in_var_decls = (lto_ref*)(data + vars_offset);
- lto_ref *in_type_decls = (lto_ref*)(data + type_decls_offset);
- lto_ref *in_namespace_decls = (lto_ref*)(data + namespace_decls_offset);
- lto_ref *in_types = (lto_ref*)(data + types_offset);
+ struct lto_input_block ib_main;
+ struct lto_input_block debug_main;
+ struct data_in data_in;
int i;
- data_in->field_decls = xcalloc (header->num_field_decls, sizeof (tree*));
- data_in->fn_decls = xcalloc (header->num_fn_decls, sizeof (tree*));
- data_in->var_decls = xcalloc (header->num_var_decls, sizeof (tree*));
- data_in->type_decls = xcalloc (header->num_type_decls, sizeof (tree*));
- data_in->namespace_decls
- = xcalloc (header->num_namespace_decls, sizeof (tree*));
- data_in->types = xcalloc (header->num_types, sizeof (tree*));
-
- for (i=0; i<header->num_field_decls; i++)
- data_in->field_decls[i]
- = lto_resolve_field_ref (fd, context, &in_field_decls[i]);
- data_in->num_field_decls = header->num_field_decls;
-
- for (i=0; i<header->num_fn_decls; i++)
- data_in->fn_decls[i]
- = lto_resolve_fn_ref (fd, context, &in_fn_decls[i]);
- data_in->num_fn_decls = header->num_fn_decls;
-
- for (i=0; i<header->num_var_decls; i++)
- data_in->var_decls[i]
- = lto_resolve_var_ref (fd, context, &in_var_decls[i]);
- data_in->num_var_decls = header->num_var_decls;
-
- for (i=0; i<header->num_type_decls; i++)
- data_in->type_decls[i]
- = lto_resolve_typedecl_ref (fd, context, &in_type_decls[i]);
- data_in->num_type_decls = header->num_type_decls;
-
- for (i = 0; i < header->num_namespace_decls; i++)
- data_in->namespace_decls[i]
- = lto_resolve_namespacedecl_ref (fd, context, &in_namespace_decls[i]);
- data_in->num_namespace_decls = header->num_namespace_decls;
-
- for (i=0; i<header->num_types; i++)
- data_in->types[i] = lto_resolve_type_ref (fd, context, &in_types[i]);
- data_in->num_types = header->num_types;
-
- data_in->file_name = lto_get_file_name (fd);
-
- return data_in;
-}
-
-
-/* Read the indirection tables for the global decls and types. */
-
-static struct lto_file_decl_data *
-lto_materialize_file_data (lto_info_fd *fd,
- lto_context *context)
-{
- lto_file *file = fd->base.file;
- const void *body = lto_get_body (fd, context, LTO_section_decls, NULL);
- struct lto_file_decl_data * file_data = lto_read_decls (fd, context, body);
-
- file->vtable->unmap_section (file, NULL, body);
- return file_data;
-}
-
-static tree
-lto_read_subroutine_type_subprogram_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree ret_type;
- tree arg_types;
- tree type;
- tree name;
- tree asm_name = NULL_TREE;
- bool external;
- bool prototyped;
- bool declaration;
- tree result;
- tree saved_scope;
- int inlined = DW_INL_not_inlined;
- tree abstract_origin = NULL_TREE;
- int line;
- tree specification = NULL_TREE;
-
- gcc_assert (abbrev->tag == DW_TAG_subroutine_type
- || abbrev->tag == DW_TAG_subprogram);
-
- ret_type = NULL_TREE;
- prototyped = false;
- name = NULL_TREE;
- external = false;
- declaration = false;
- saved_scope = NULL_TREE;
-
- if (abbrev->tag == DW_TAG_subroutine_type)
- {
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_type:
- ret_type = lto_read_referenced_type_DIE (fd,
- context,
- attr_data.u.reference);
- break;
-
- case DW_AT_prototyped:
- prototyped = attr_data.u.flag;
- break;
- }
- LTO_END_READ_ATTRS ();
- }
- else
- {
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_decl_column:
- case DW_AT_decl_file:
- /* Ignore. */
- break;
-
- case DW_AT_low_pc:
- case DW_AT_high_pc:
- case DW_AT_ranges:
- case DW_AT_frame_base:
- case DW_AT_static_link:
- /* Ignore. */
- break;
-
- case DW_AT_specification:
- specification = lto_read_DIE_at_ptr (fd, context,
- attr_data.u.reference);
- gcc_assert (TREE_CODE (specification) == FUNCTION_DECL);
- break;
-
- case DW_AT_decl_line:
- line = attribute_value_as_int (&attr_data);
- break;
-
- case DW_AT_declaration:
- declaration = attr_data.u.flag;
- break;
-
- case DW_AT_abstract_origin:
- abstract_origin = lto_read_DIE_at_ptr (fd, context,
- attr_data.u.reference);
- gcc_assert (TREE_CODE (abstract_origin) == FUNCTION_DECL);
- break;
-
- case DW_AT_name:
- name = lto_get_identifier (&attr_data);
- /* Assume that the assembler name is the same as the source
- name -- unless a DW_AT_MIPS_linkage_name attribute is
- available. */
- if (!asm_name)
- asm_name = name;
- break;
-
- case DW_AT_external:
- external = attr_data.u.flag;
- break;
-
- case DW_AT_type:
- ret_type = lto_read_referenced_type_DIE (fd,
- context,
- attr_data.u.reference);
- break;
-
- case DW_AT_prototyped:
- prototyped = attr_data.u.flag;
- break;
-
- case DW_AT_inline:
- inlined = attribute_value_as_int (&attr_data);
- break;
-
- case DW_AT_MIPS_linkage_name:
- /* Set the DECL_ASSEMBLER_NAME so we don't have to remangle
- names in LTO. */
- asm_name = lto_get_identifier (&attr_data);
- break;
- }
- LTO_END_READ_ATTRS ();
- }
-
- if (abstract_origin || specification)
- {
- /* Ensure that we only have one of them. */
- gcc_assert (!abstract_origin || !specification);
- result = abstract_origin ? abstract_origin : specification;
-
- goto read_children;
- }
-
- /* The DWARF3 specification says that a return type is only
- specified for functions that return a value. Therefore,
- functions without an explicit return type return "void". */
- if (!ret_type)
- ret_type = void_type_node;
-
- /* We must merge the FUNCTION_DECL before descending into its body
- so that the DECL_CONTEXT for any static variables is set
- correctly. But, to merge the FUNCTION_DECL, we must determine
- its type. Therefore, we have to do two passes over the children
- of the FUNCTION_DECL: one to compute the type of the parameters
- and one to process the actual children. */
- arg_types = NULL_TREE;
- if (prototyped)
- {
- const char *saved_cur;
- saved_cur = fd->base.cur;
-
- context->skip_non_parameters = true;
- context->last_parm_type = &arg_types;
- context->varargs_p = false;
- lto_read_child_DIEs (fd, abbrev, context);
- context->skip_non_parameters = false;
- fd->base.cur = saved_cur;
-
- if (!context->varargs_p)
- *context->last_parm_type = void_list_node;
- }
-
- /* We might have constructed the necessary type already while reading
- attributes. */
- if (abbrev->tag == DW_TAG_subroutine_type)
- {
- tree result = lto_cache_lookup_DIE (fd, die, false);
-
- if (result) return result;
- }
-
- /* Build the function type. */
- type = build_function_type (ret_type, arg_types);
- if (abbrev->tag == DW_TAG_subroutine_type)
- result = type;
- else
- {
- if (!name)
- lto_file_corrupt_error ((lto_fd *)fd);
-
- if (external && declaration)
- {
- /* Check to see if this function is a builtin. */
- tree builtins = lang_hooks.decls.getdecls ();
-
- while (builtins)
- {
- tree candidate = builtins;
-
- /* Check to see if this builtin matches this function's
- DIE. Use the builtin decl if so. */
- if (name == DECL_NAME (candidate)
- || (DECL_ASSEMBLER_NAME_SET_P (candidate)
- && name == DECL_ASSEMBLER_NAME (candidate)))
- {
- result = candidate;
-
- goto read_children;
- }
-
- builtins = TREE_CHAIN (candidate);
- }
- }
-
- result = build_decl (FUNCTION_DECL, name, type);
- DECL_SOURCE_LOCATION (result) = UNKNOWN_LOCATION;
- TREE_PUBLIC (result) = external;
- if (inlined == DW_INL_declared_inlined
- || inlined == DW_INL_declared_not_inlined)
- DECL_DECLARED_INLINE_P (result) = 1;
-
- /* Set the DECL_ASSEMBLER_NAME for the function from the
- information in the DIE. */
- SET_DECL_ASSEMBLER_NAME (result, asm_name ? asm_name : name);
-
- DECL_RESULT (result)
- = build_decl (RESULT_DECL, NULL_TREE,
- TYPE_MAIN_VARIANT (ret_type));
- DECL_CONTEXT (DECL_RESULT (result)) = result;
- TREE_ADDRESSABLE (result) = 1;
-#if 0
- DECL_SOURCE_LOCATION (result) = { input_filename, line };
+ LTO_INIT_INPUT_BLOCK (ib_main, data + main_offset, 0, header->main_size);
+ LTO_INIT_INPUT_BLOCK (debug_main, data + debug_main_offset, 0, header->debug_main_size);
+
+ decl_data->field_decls = xcalloc (header->num_field_decls, sizeof (tree));
+ decl_data->fn_decls = xcalloc (header->num_fn_decls, sizeof (tree));
+ decl_data->var_decls = xcalloc (header->num_var_decls, sizeof (tree));
+ decl_data->type_decls = xcalloc (header->num_type_decls, sizeof (tree));
+ decl_data->namespace_decls = xcalloc (header->num_namespace_decls, sizeof (tree));
+ decl_data->types = xcalloc (header->num_types, sizeof (tree));
+
+ memset (&data_in, 0, sizeof (struct data_in));
+ data_in.file_data = decl_data;
+ data_in.strings = data + string_offset;
+ data_in.strings_len = header->string_size;
+ data_in.globals_index = NULL;
+ data_in.global = true; /* ### unused */
+
+ /* ### This doesn't belong here */
+ /* ### Need initialization not done in lto_static_init () */
+ lto_static_init_local ();
+
+#ifdef LTO_STREAM_DEBUGGING
+ lto_debug_context.out = lto_debug_in_fun;
+ lto_debug_context.indent = 0;
+ lto_debug_context.tag_names = LTO_tree_tag_names;
+ lto_debug_context.current_data = &debug_main;
#endif
- /* We need to have a reliable way to determine whether this
- function decl is associated with a definition so that the
- merging heuristics work properly. The best way to do that is
- to look for the function's body. */
- {
- const char *name = IDENTIFIER_POINTER (DECL_NAME (result));
- const void *body = lto_get_body (fd, context, LTO_section_function_body, name);
-
- if (body)
- {
- DECL_EXTERNAL (result) = 0;
- fd->base.file->vtable->unmap_section (fd->base.file, name, body);
- }
- else
- DECL_EXTERNAL (result) = 1;
- }
-
- if (!TREE_PUBLIC (result))
- /* Need to ensure static entities between different files
- don't clash unexpectedly. */
- lang_hooks.set_decl_assembler_name (result);
-
- /* If the function has already been declared, merge the
- declarations. */
- result = lto_symtab_merge_fn (result);
- if (result != error_mark_node)
- {
- /* Record this function in the DIE cache so that it can be
- resolved from the bodies of functions. */
- lto_cache_store_DIE (fd, die, result);
- }
- }
-
- /* Read the child DIEs, which are in the scope of RESULT. */
- read_children:
- if (TREE_CODE (result) == FUNCTION_DECL)
- {
- saved_scope = context->scope;
- context->scope = result;
- }
- context->skip_parameters = true;
- lto_read_child_DIEs (fd, abbrev, context);
- context->skip_parameters = false;
- if (TREE_CODE (result) == FUNCTION_DECL)
- context->scope = saved_scope;
-
- return result;
-}
-
-static tree
-lto_read_unspecified_parameters_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- gcc_assert (abbrev->tag == DW_TAG_unspecified_parameters);
- context->varargs_p = true;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- }
- LTO_END_READ_ATTRS ();
- lto_read_child_DIEs (fd, abbrev, context);
-
- return NULL_TREE;
-}
-
-static tree
-lto_read_typedef_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree base_type = NULL_TREE;
- tree name = NULL_TREE;
- tree decl;
- tree type;
+ /* Preload references to well-known trees. */
+ preload_common_nodes (&data_in);
- LTO_BEGIN_READ_ATTRS ()
+ /* Read the global declarations and types. */
+ /* ### We should be a bit more graceful regarding truncated files. */
+ while (ib_main.p < ib_main.len)
{
- case DW_AT_type:
- base_type = lto_read_referenced_type_DIE (fd,
- context,
- attr_data.u.reference);
- break;
-
- case DW_AT_name:
- name = lto_get_identifier (&attr_data);
- break;
-
- case DW_AT_decl_column:
- case DW_AT_decl_file:
- case DW_AT_decl_line:
- /* Ignore. */
- break;
-
+ input_tree (&ib_main, &data_in);
+ gcc_assert (ib_main.p <= ib_main.len);
}
- LTO_END_READ_ATTRS ();
-
- {
- tree type = lto_cache_lookup_DIE (fd, die, false);
-
- if (type) return type;
- }
- /* The DW_AT_name attribute is required. */
- if (!name)
- lto_file_corrupt_error ((lto_fd *)fd);
- /* The DW_AT_type attribute is supposed to be required, but since DWARF
- has no representation for the void type, dwarf2out.c omits the type
- attribute in that case. So, in order to allow GCC's output to be
- read in again, we have to interpret a missing base type attribute as
- the void type, too. */
- if (!base_type)
- base_type = void_type_node;
- /* Build the typedef. */
- type = build_variant_type_copy (base_type);
- decl = build_decl (TYPE_DECL, name, type);
- TYPE_NAME (type) = decl;
- DECL_ORIGINAL_TYPE (decl) = base_type;
+ /* Construct index vectors for use when reading function bodies. */
- /* Store this for future references in our children. */
- lto_cache_store_DIE (fd, die, type);
-
- lto_read_child_DIEs (fd, abbrev, context);
- return type;
-}
-
-
-static tree
-lto_read_pointer_reference_type_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree pointed_to = NULL_TREE;
- tree name = NULL_TREE;
- tree type;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_name:
- name = lto_get_identifier (&attr_data);
- break;
-
- case DW_AT_type:
- pointed_to = lto_read_referenced_type_DIE (fd,
- context,
- attr_data.u.reference);
- break;
-
- case DW_AT_byte_size:
- if (attribute_value_as_int (&attr_data) * BITS_PER_UNIT != POINTER_SIZE)
- lto_abi_mismatch_error ();
- break;
- }
- LTO_END_READ_ATTRS ();
-
- /* The DW_AT_type attribute is supposed to be required, but since DWARF
- has no representation for the void type, dwarf2out.c omits the type
- attribute in that case. So, in order to allow GCC's output to be
- read in again, we have to interpret a missing base type attribute as
- the void type, too. */
- if (!pointed_to)
- pointed_to = void_type_node;
- /* Build the pointer or reference type. */
- switch (abbrev->tag)
- {
- case DW_TAG_pointer_type:
- type = build_pointer_type (pointed_to);
- break;
- case DW_TAG_reference_type:
- type = build_reference_type (pointed_to);
- break;
- default:
- gcc_unreachable ();
- }
-
- /* If pointer/reference has a name, build a typedef. */
- if (name != NULL_TREE)
- {
- tree named_type = build_variant_type_copy (type);
- tree decl = build_decl (TYPE_DECL, name, named_type);
- TYPE_NAME (named_type) = decl;
- DECL_ORIGINAL_TYPE (decl) = type;
- type = named_type;
- }
-
- lto_read_child_DIEs (fd, abbrev, context);
- return type;
-}
-
-static tree
-lto_read_subrange_type_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree type;
- tree base = NULL_TREE;
- int byte_size = 0;
- bool got_byte_size = false;
- tree lower = NULL_TREE;
- tree upper = NULL_TREE;
- tree count = NULL_TREE;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_decl_column:
- case DW_AT_decl_file:
- case DW_AT_decl_line:
- /* Ignore. */
- break;
-
- case DW_AT_type:
- base = lto_read_referenced_type_DIE (fd,
- context,
- attr_data.u.reference);
- break;
-
- case DW_AT_byte_size:
- byte_size = attribute_value_as_int (&attr_data);
- got_byte_size = true;
- break;
-
- case DW_AT_lower_bound:
- lower = attribute_value_as_constant (&attr_data, NULL_TREE);
- break;
-
- case DW_AT_upper_bound:
- upper = attribute_value_as_constant (&attr_data, NULL_TREE);
- break;
-
- case DW_AT_count:
- count = attribute_value_as_constant (&attr_data, NULL_TREE);
- break;
-
- case DW_AT_threads_scaled:
- case DW_AT_stride:
- lto_unsupported_attr_error (abbrev, attr);
- }
- LTO_END_READ_ATTRS ();
-
- /* Reconcile base type and byte size attributes. */
- base = lto_find_integral_type (base, byte_size, got_byte_size);
-
- /* Lower bound can be omitted if there is a language-specific default. */
- if (!lower)
- {
- switch (context->language)
- {
- case DW_LANG_C89:
- case DW_LANG_C:
- case DW_LANG_C_plus_plus:
- case DW_LANG_C99:
- lower = integer_zero_node;
- break;
-
- case DW_LANG_Fortran77:
- case DW_LANG_Fortran90:
- case DW_LANG_Fortran95:
- lower = integer_one_node;
- break;
-
- default:
- /* No other default lower bound values are currently defined. */
- lto_file_corrupt_error ((lto_fd *)fd);
- }
- }
-
- /* At most one of count and upper bound can be specified. If we got count,
- use it to compute the upper bound. */
- if (count)
- {
- if (upper)
- lto_file_corrupt_error ((lto_fd *)fd);
- else if (host_integerp (count, 0) && host_integerp (lower, 0))
- upper = build_int_cst (TREE_TYPE (count),
- TREE_INT_CST_LOW (lower)
- + TREE_INT_CST_LOW (count) - 1);
- else
- sorry ("can't compute upper array bound");
- }
-
- /* Build the range type, and record it for our caller. */
- type = build_range_type (base, lower, upper);
-
- lto_read_child_DIEs (fd, abbrev, context);
- return type;
-}
-
-static tree
-lto_read_base_type_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree name;
- bool have_encoding;
- enum dwarf_type encoding;
- bool have_size;
- bool have_offset;
- bool have_bits;
- int size;
- tree type;
- int bits;
- int offset;
- int maxbits;
-
- name = NULL_TREE;
- have_encoding = false;
- encoding = DW_ATE_void;
- have_size = false;
- size = 0;
- have_bits = false;
- bits = 0;
- have_offset = false;
- offset = 0;
- type = NULL_TREE;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_name:
- name = lto_get_identifier (&attr_data);
- break;
-
- case DW_AT_encoding:
- have_encoding = true;
- encoding = attribute_value_as_int (&attr_data);
- break;
-
- case DW_AT_byte_size:
- have_size = true;
- size = attribute_value_as_int (&attr_data);
- break;
-
- case DW_AT_bit_size:
- have_bits = true;
- bits = attribute_value_as_int (&attr_data);
- break;
-
- case DW_AT_bit_offset:
- have_offset = true;
- offset = attribute_value_as_int (&attr_data);
- break;
- }
- LTO_END_READ_ATTRS ();
-
- if (!have_encoding || !have_size)
- lto_file_corrupt_error ((lto_fd *)fd);
-
- /* The DWARF spec implies that DW_AT_bit_size and DW_AT_bit_offset go
- together as a pair. We only support the case where integral types are
- aligned in the low order bits of its containing word, which is how
- dwarf2out.c encodes types with "weird" precisions. */
- maxbits = BITS_PER_UNIT * size;
- if (have_offset && have_bits)
- {
- if (bits > maxbits)
- lto_file_corrupt_error ((lto_fd *)fd);
- if (encoding != DW_ATE_unsigned && encoding != DW_ATE_signed)
- sorry ("bit size attribute only supported for signed/unsigned types");
- if (offset != maxbits - bits)
- sorry ("unaligned base type not supported");
- }
- else if (have_offset || have_bits)
- lto_file_corrupt_error ((lto_fd *)fd);
- else
- bits = maxbits;
-
- lto_read_child_DIEs (fd, abbrev, context);
-
- /* Build the type. */
- switch (encoding)
- {
- case DW_ATE_unsigned:
- case DW_ATE_signed:
- type = make_bitfield_integer_type (bits, encoding == DW_ATE_unsigned);
- break;
-
- case DW_ATE_unsigned_char:
- case DW_ATE_signed_char:
- type = make_bitfield_integer_type (bits, encoding == DW_ATE_unsigned_char);
- TYPE_STRING_FLAG (type) = 1;
- break;
-
- case DW_ATE_boolean:
- type = build_nonstandard_integer_type (bits, 1);
- TREE_SET_CODE (type, BOOLEAN_TYPE);
- TYPE_MAX_VALUE (type) = build_int_cst (type, 1);
- TYPE_PRECISION (type) = 1;
- break;
-
- case DW_ATE_float:
- type = make_node (REAL_TYPE);
- TYPE_PRECISION (type) = bits;
- layout_type (type);
- break;
-
- case DW_ATE_complex_float:
- {
- tree base = make_node (REAL_TYPE);
- TYPE_PRECISION (base) = bits / 2;
- layout_type (base);
- type = build_complex_type (base);
- }
- break;
-
- case DW_ATE_GNU_complex_signed:
- case DW_ATE_GNU_complex_unsigned:
- {
- bool unsigned_p = encoding == DW_ATE_GNU_complex_unsigned;
- tree base = make_bitfield_integer_type (bits / 2, unsigned_p);
- type = build_complex_type (base);
- }
- break;
-
- case DW_ATE_decimal_float:
- case DW_ATE_lo_user:
- default:
- sorry ("unsupported base type encoding - 0x%x", encoding);
- break;
- }
- /* If this is a new type, declare it.
- The DWARF spec seems to imply that the name attribute is required,
- but GCC generates base_type DIEs without names in some cases (e.g.,
- for the referenced type of the subrange type used as an array
- subscript). Accept that without complaining by just skipping making
- the declaration. */
- if (name && !TYPE_NAME (type))
- {
- tree decl;
- decl = build_decl (TYPE_DECL, name, type);
- TYPE_NAME (type) = decl;
- /* Let the middle end know about the type declaration. */
- rest_of_decl_compilation (decl,
- /*top_level=*/1,
- /*at_end=*/0);
- }
-
- return type;
-}
-
-static tree
-lto_read_const_volatile_restrict_type_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree base_type = NULL_TREE;
- tree type;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_type:
- base_type = lto_read_referenced_type_DIE (fd,
- context,
- attr_data.u.reference);
- break;
- case DW_AT_name:
- /* Ignore. FIXME: is this right? */
- break;
- }
- LTO_END_READ_ATTRS ();
-
- /* The DW_AT_type attribute is supposed to be required, but since DWARF
- has no representation for the void type, dwarf2out.c omits the type
- attribute in that case. So, in order to allow GCC's output to be
- read in again, we have to interpret a missing base type attribute as
- the void type, too. */
- if (!base_type)
- base_type = void_type_node;
- /* Build the modified type. */
- switch (abbrev->tag)
- {
- case DW_TAG_const_type:
- type = build_qualified_type (base_type, TYPE_QUAL_CONST);
- break;
- case DW_TAG_volatile_type:
- type = build_qualified_type (base_type, TYPE_QUAL_VOLATILE);
- break;
- case DW_TAG_restrict_type:
- type = build_qualified_type (base_type, TYPE_QUAL_RESTRICT);
- break;
- default:
- gcc_unreachable ();
- }
-
- lto_read_child_DIEs (fd, abbrev, context);
- return type;
-}
-
-/* Read a namespace DIE from FD. ABBREV is a DWARF2 abbreviation-table entry.
- CONTEXT provides information about the current state of the compilation
- unit. Returns a tree representing the NAMESPACE_DECL read. */
-
-static tree
-lto_read_namespace_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree name = NULL_TREE;
- tree namespace_decl;
- tree parentdata;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_name:
- name = lto_get_identifier (&attr_data);
- break;
-
- case DW_AT_decl_file:
- case DW_AT_decl_line:
- /* Ignore. */
- break;
- }
- LTO_END_READ_ATTRS ();
-
- gcc_assert (name);
- namespace_decl = build_decl (NAMESPACE_DECL, name, void_type_node);
- DECL_CONTEXT (namespace_decl) = context->parentdata;
-
- parentdata = context->parentdata;
- context->parentdata = namespace_decl;
- lto_read_child_DIEs (fd, abbrev, context);
- context->parentdata = parentdata;
-
- return namespace_decl;
-}
-
-static tree
-lto_read_unspecified_type_DIE (lto_info_fd *fd,
- lto_die_ptr die ATTRIBUTE_UNUSED,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- tree type = NULL_TREE;
-
- LTO_BEGIN_READ_ATTRS ()
- {
- case DW_AT_name:
- gcc_assert (attr_data.cl == DW_cl_string);
- if (strcmp (attr_data.u.string, "void") == 0)
- type = void_type_node;
- break;
- }
- LTO_END_READ_ATTRS ();
-
- if (!type)
- sorry ("unsupported use of DW_TAG_unspecified_type");
- lto_read_child_DIEs (fd, abbrev, context);
- return type;
-}
-
-/* Read the next DIE from FD. CONTEXT provides information about the
- current state of the compilation unit. Returns a (possibly null) TREE
- representing the DIE read. If more is non-NULL, *more is set to true
- iff there was a real DIE present; false if the DIE was a null entry
- indicating the end of a list of sibling DIEs. */
-static tree
-lto_read_DIE (lto_info_fd *fd, lto_context *context, bool *more)
-{
- typedef tree (*DIE_reader_fnptr)(lto_info_fd * fd,
- lto_die_ptr die,
- const DWARF2_abbrev *abbrev,
- lto_context *context);
- /* Reader functions for the tags defined by DWARF 3. */
- static const DIE_reader_fnptr readers[DW_TAG_shared_type + 1] =
- {
- NULL, /* padding */
- lto_read_array_type_DIE,
- lto_read_structure_union_class_type_DIE,
- NULL, /* entry_point */
- lto_read_enumeration_type_DIE,
- lto_read_variable_formal_parameter_constant_DIE,
- NULL, /* padding */
- NULL, /* padding */
- NULL, /* imported_declaration */
- NULL, /* padding */
- lto_read_only_for_child_DIEs, /* label */
- lto_read_only_for_child_DIEs, /* lexical_block */
- NULL, /* padding */
- lto_read_member_DIE,
- NULL, /* padding */
- lto_read_pointer_reference_type_DIE,
- lto_read_pointer_reference_type_DIE,
- lto_read_compile_unit_DIE,
- NULL, /* string_type */
- lto_read_structure_union_class_type_DIE,
- NULL, /* padding */
- lto_read_subroutine_type_subprogram_DIE,
- lto_read_typedef_DIE,
- lto_read_structure_union_class_type_DIE,
- lto_read_unspecified_parameters_DIE,
- NULL, /* variant */
- NULL, /* common_block */
- NULL, /* common_inclusion */
- NULL, /* inheritance */
- lto_read_only_for_child_DIEs, /* inlined_subroutine */
- NULL, /* module */
- NULL, /* ptr_to_member_type */
- NULL, /* set_type */
- lto_read_subrange_type_DIE,
- NULL, /* with_stmt */
- NULL, /* access_declaration */
- lto_read_base_type_DIE,
- NULL, /* catch_block */
- lto_read_const_volatile_restrict_type_DIE,
- lto_read_variable_formal_parameter_constant_DIE,
- lto_read_enumerator_DIE,
- NULL, /* file_type */
- NULL, /* friend */
- NULL, /* namelist */
- NULL, /* namelist_item */
- NULL, /* packed_type */
- lto_read_subroutine_type_subprogram_DIE,
- NULL, /* template_type_param */
- NULL, /* template_value_param */
- NULL, /* thrown_type */
- NULL, /* try_block */
- NULL, /* variant_part */
- lto_read_variable_formal_parameter_constant_DIE,
- lto_read_const_volatile_restrict_type_DIE,
- NULL, /* dwarf_procedure */
- lto_read_const_volatile_restrict_type_DIE,
- NULL, /* interface_type */
- lto_read_namespace_DIE,
- NULL, /* imported_module */
- lto_read_unspecified_type_DIE,
- NULL, /* partial_unit */
- NULL, /* imported_unit */
- NULL, /* padding */
- NULL, /* condition */
- NULL /* shared_type */
- };
-
- const DWARF2_abbrev *abbrev;
- DIE_reader_fnptr reader;
- lto_die_ptr die;
- tree val;
-
- /* Record the location of the current DIE -- before we change the
- file pointer. */
- die = (lto_die_ptr) ((lto_fd *)fd)->cur;
- /* Read the abbreviation entry so that we know what kind of DIE this
- is. */
- abbrev = lto_read_abbrev (fd);
- if (!abbrev)
- {
- if (more)
- *more = false;
- return NULL_TREE;
- }
- /* Check to see if this DIE has already been processed. If so, skip
- over it and its children. */
- val = lto_cache_lookup_DIE (fd, die, /*skip=*/true);
- if (!val)
- {
- bool saved_skip_all;
-
- saved_skip_all = context->skip_all;
- /* Determine the DIE reader function. */
- reader = NULL;
-
- if (context->skip_all)
- ;
- else if (context->skip_non_parameters
- && abbrev->tag != DW_TAG_formal_parameter
- && abbrev->tag != DW_TAG_unspecified_parameters)
- context->skip_all = true;
- else if (context->skip_parameters
- && (abbrev->tag == DW_TAG_formal_parameter
- || abbrev->tag == DW_TAG_unspecified_parameters))
- context->skip_all = true;
- else if (abbrev->tag < sizeof (readers) / sizeof (DIE_reader_fnptr))
- reader = readers[abbrev->tag];
-
- if (reader)
- {
- /* If we are reading some sort of formal parameter or
- unspecified parameter, then we need to unset
- context->skip_non_parameters to read the types for said
- parameter. */
- bool saved_skip_non_parameters = context->skip_non_parameters;
-
- context->skip_non_parameters = false;
-
- /* If there is a reader, use it. */
- val = reader (fd, die, abbrev, context);
- if (val)
- /* If this DIE refers to a type, cache the value so that future
- references to the type can be processed quickly. */
- {
- if (TYPE_P (val))
- {
- /* In the absence of a better solution, say that we alias
- everything FIXME. */
- TYPE_ALIAS_SET (val) = 0;
-
- lto_cache_store_DIE (fd, die, val);
- }
- /* If this DIE refers to a namespace, we must cache the value
- or future references will not properly set DECL_CONTEXT. */
- else if (TREE_CODE (val) == NAMESPACE_DECL)
- lto_cache_store_DIE (fd, die, val);
- }
- context->skip_non_parameters = saved_skip_non_parameters;
- }
- else
- {
- if (!context->skip_all)
- /* Assume that all other tags matter, as we are otherwise at
- risk of silently generating wrong code. If a tag can be
- safely ignored, it should be explicitly ignored above. */
- error ("DWARF tag " HOST_WIDEST_INT_PRINT_UNSIGNED " not "
- "supported by link-time optimization", abbrev->tag);
-
- /* Skip over this DIE, but attempt to read its children. */
- lto_read_only_for_child_DIEs (fd, die, abbrev, context);
- }
-
- context->skip_all = saved_skip_all;
- }
-
- if (more)
- *more = true;
- return val;
-}
-
-/* Read the children of a DIE from FD, passing CONTEXT to the DIE readers
- for the children. The attributes of the DIE have already been
- read. ABBREV indicates whether or not the DIE actually has
- children; if it does not, then this function returns without
- reading anything. Therefore, it is always safe to call this
- function from a DIE reader, after reading the DIE's attributes.
- This function simply discards the tree valued returned by lto_read_DIE
- for each child.
-*/
-static void
-lto_read_child_DIEs (lto_info_fd *fd,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- if (abbrev->has_children)
- {
- bool more;
- do
- lto_read_DIE (fd, context, &more);
- while (more);
- }
-}
-
-/* This function is similar to lto_read_child_DIEs but collects the tree
- values from reading each child into a heap-allocated VEC, which is
- returned.
-*/
-static VEC(tree,heap) *
-lto_collect_child_DIEs (lto_info_fd *fd,
- const DWARF2_abbrev *abbrev,
- lto_context *context)
-{
- VEC(tree,heap) *result = VEC_alloc (tree, heap, 32);
- if (abbrev->has_children)
- {
- bool more;
- do
- {
- tree val = lto_read_DIE (fd, context, &more);
- if (more)
- VEC_safe_push (tree, heap, result, val);
- }
- while (more);
- }
- return result;
-}
-
-
-/* Read all the DWARF2 compile units from INFO_FD, placing them in
- INFO_FD->UNITS. */
-static void
-lto_info_read (lto_info_fd *info_fd)
-{
- size_t num_units;
- lto_fd *fd;
- unsigned long offset;
- size_t current_unit;
-
- /* We should only read the compilation units once. */
- gcc_assert (!info_fd->units);
- fd = (lto_fd *)info_fd;
-
- /* Start reading from the beginning of the section. */
- fd->cur = fd->start;
-
- num_units = 0;
-
- /* Get the number of compilation units. */
- while (fd->cur < fd->end)
- {
- /* The compilation-unit header. */
- DWARF2_CompUnit cu;
- const char *before_header = fd->cur;
-
- /* Read the compilation unit header. */
- lto_read_comp_unit_header (info_fd, &cu);
+ for (i=0; i<header->num_types; i++)
+ decl_data->types[i]
+ = VEC_index (tree, data_in.globals_index, in_types[i]);
+ decl_data->num_types = header->num_types;
- fd->cur = before_header + cu.cu_length;
- num_units++;
- }
-
- info_fd->num_units = num_units;
- info_fd->units = XCNEWVEC (DWARF2_CompUnit *, num_units);
+ for (i=0; i<header->num_field_decls; i++)
+ decl_data->field_decls[i]
+ = VEC_index (tree, data_in.globals_index, in_field_decls[i]);
+ decl_data->num_field_decls = header->num_field_decls;
- /* Now read the actual compilation units. */
- fd->cur = fd->start;
- offset = 0;
- current_unit = 0;
+ for (i=0; i<header->num_fn_decls; i++)
+ decl_data->fn_decls[i]
+ = VEC_index (tree, data_in.globals_index, in_fn_decls[i]);
+ decl_data->num_fn_decls = header->num_fn_decls;
- /* Read the compilation units. */
- while (fd->cur < fd->end)
- {
- const char *before_header = fd->cur;
- unsigned long header_length;
- DWARF2_CompUnit *cu;
+ for (i=0; i<header->num_var_decls; i++)
+ decl_data->var_decls[i]
+ = VEC_index (tree, data_in.globals_index, in_var_decls[i]);
+ decl_data->num_var_decls = header->num_var_decls;
- cu = XCNEW (DWARF2_CompUnit);
- info_fd->units[current_unit] = cu;
+ for (i=0; i<header->num_type_decls; i++)
+ decl_data->type_decls[i]
+ = VEC_index (tree, data_in.globals_index, in_type_decls[i]);
+ decl_data->num_type_decls = header->num_type_decls;
- /* Read the compilation unit header. */
- lto_read_comp_unit_header (info_fd, cu);
-
- header_length = fd->cur - before_header;
- cu->cu_start_offset = offset + header_length;
- cu->cu_header_length = header_length;
+ for (i=0; i<header->num_namespace_decls; i++)
+ decl_data->namespace_decls[i]
+ = VEC_index (tree, data_in.globals_index, in_namespace_decls[i]);
+ decl_data->num_namespace_decls = header->num_namespace_decls;
- fd->cur = before_header + cu->cu_length;
- offset = fd->cur - fd->start;
- current_unit++;
- }
-}
+ /* The globals index vector is needed only while reading. */
-/* Setup compile unit fields in CONTEXT from FD and UNIT */
-static void
-lto_set_cu_context (lto_context *context, lto_info_fd *fd,
- DWARF2_CompUnit *unit)
-{
- context->cu_start =
- fd->base.start + unit->cu_start_offset - unit->cu_header_length;
- context->cu_end = context->cu_start + unit->cu_length;
- context->cu = unit;
+ VEC_free (tree, heap, data_in.globals_index);
}
-
/* Generate a TREE representation for all types and external decls
entities in FILE. If an entity in FILE has already been read (from
another object file), merge the two entities. Returns TRUE iff
FILE was successfully processed.
- Read all of the lto dwarf out of the file. Then read the cgraph
+ Read all of the globals out of the file. Then read the cgraph
and process the .o index into the cgraph nodes so that it can open
the .o file to load the functions and ipa information. */
@@ -3667,236 +254,26 @@ static bool
lto_file_read (lto_file *file)
{
struct lto_file_decl_data* file_data;
- size_t i;
- /* The descriptor for the .debug_info section. */
- lto_fd *fd;
- /* Read the abbreviation entries. */
- lto_abbrev_read (&file->debug_abbrev);
- /* Read the compilation units. */
- lto_info_read (&file->debug_info);
+ char *data;
- fd = &file->debug_info.base;
+ file_data = xmalloc (sizeof (struct lto_file_decl_data));
- for (i = 0; i < file->debug_info.num_units; i++)
- {
- /* The current compilation unit. */
- DWARF2_CompUnit *unit = file->debug_info.units[i];
- /* The context information for this compilation unit. */
- lto_context context;
- htab_t section_hash_table;
-
- /* Set up the context. */
- lto_set_cu_context (&context, &file->debug_info, unit);
- fd->cur = context.cu_start + unit->cu_header_length;
-
- /* Read DIEs. */
- while (fd->cur < context.cu_end)
- {
- tree last_parm_type = NULL_TREE;
-
- /* Reinitialize everything for a toplevel DIE. */
- context.scope = NULL_TREE;
- context.parentdata = NULL_TREE;
- /* Initialize this specially so reading a formal parameter DIE
- won't fall over. We shouldn't normally see such DIEs at
- the toplevel in the first place, but if the following
- scenario occurs:
-
- 1. Read a subprogram DIE for X;
- 2. Read a formal parameter DIE for X's parameter(s) as
- children of X;
- 3. Attempt to read X's DIE again, but we retrieve the cached
- version we read in step 1;
-
- Then we will attempt to read the formal parameter DIEs for
- X's parameter(s) as "toplevel" DIEs, as they haven't been
- skipped properly by step 3. It's harmless, but we need to
- be prepared for such a situation. */
- context.last_parm_type = &last_parm_type;
- context.varargs_p = false;
- context.skip_all = false;
- context.skip_non_parameters = false;
- context.skip_parameters = false;
-
- lto_read_DIE (&file->debug_info, &context, NULL);
- }
-
- section_hash_table = lto_elf_build_section_table (file);
- file_data = lto_materialize_file_data (&file->debug_info, &context);
- file_data->section_hash_table = section_hash_table;
-
- lto_materialize_constructors_and_inits (file_data);
-
- lto_materialize_cgraph (file_data);
- }
-
- return true;
-}
-
-tree
-lto_resolve_type_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref)
-{
- lto_die_ptr die;
- lto_context *new_context = context;
- tree type;
-
- /* At present, we only support a single DWARF section. */
- if (ref->section != 0)
- lto_abi_mismatch_error ();
- /* Map REF to a DIE. */
- die = lto_resolve_reference (info_fd, ref->offset, context, &new_context);
- /* Map DIE to a type. */
- type = lto_read_referenced_type_DIE (info_fd, context, die);
- if (!type || !TYPE_P (type))
- lto_file_corrupt_error ((lto_fd *)info_fd);
- /* Clean up. */
- if (new_context != context)
- XDELETE (new_context);
-
- return type;
-}
-
-static tree
-lto_read_DIE_at_ptr (lto_info_fd *info_fd,
- lto_context *context,
- lto_die_ptr ptr)
-{
- tree result = lto_cache_lookup_DIE (info_fd, ptr, /*skip=*/false);
- if (!result)
- {
- lto_fd *fd = (lto_fd *)info_fd;
- const char *saved_die = fd->cur;
-
- fd->cur = (const char *) ptr;
- result = lto_read_DIE (info_fd, context, NULL);
-
- fd->cur = saved_die;
- }
- return result;
-}
+ file_data->file_name = file->filename;
+ file_data->section_hash_table = lto_elf_build_section_table (file);
-tree
-lto_resolve_var_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref)
-{
- lto_die_ptr die;
- lto_context *new_context = context;
- tree var;
-
- /* At present, we only support a single DWARF section. */
- if (ref->section != 0)
- lto_abi_mismatch_error ();
- /* Map REF to a DIE. */
- die = lto_resolve_reference (info_fd, ref->offset, context, &new_context);
- /* Map DIE to a variable. */
- var = lto_read_DIE_at_ptr (info_fd, context, die);
- if (!var || TREE_CODE (var) != VAR_DECL)
- lto_file_corrupt_error ((lto_fd *)info_fd);
-
- /* Clean up. */
- if (new_context != context)
- XDELETE (new_context);
-
- return var;
-}
-
-tree
-lto_resolve_fn_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref)
-{
- lto_die_ptr die;
- lto_context *new_context = context;
- tree fn;
-
- /* At present, we only support a single DWARF section. */
- if (ref->section != 0)
- lto_abi_mismatch_error ();
- /* Map REF to a DIE. */
- die = lto_resolve_reference (info_fd, ref->offset, context, &new_context);
- /* Map DIE to a function. */
- fn = lto_read_DIE_at_ptr (info_fd, context, die);
- if (!fn || TREE_CODE (fn) != FUNCTION_DECL)
- lto_file_corrupt_error ((lto_fd *)info_fd);
-
- /* Clean up. */
- if (new_context != context)
- XDELETE (new_context);
-
- return fn;
-}
-
-tree
-lto_resolve_field_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref)
-{
- lto_die_ptr die;
- lto_context *new_context = context;
- tree field;
-
- /* At present, we only support a single DWARF section. */
- if (ref->section != 0)
- lto_abi_mismatch_error ();
- /* Map REF to a DIE. */
- die = lto_resolve_reference (info_fd, ref->offset, context, &new_context);
- /* Map DIE to a field. */
- field = lto_read_DIE_at_ptr (info_fd, context, die);
- if (!field || TREE_CODE (field) != FIELD_DECL)
- lto_file_corrupt_error ((lto_fd *)info_fd);
-
- /* Clean up. */
- if (new_context != context)
- XDELETE (new_context);
-
- return field;
-}
-
-/* Fetch the type specified and build a fake TYPE_DECL to represent it. */
+ data = lto_get_section_data (file_data, LTO_section_decls, NULL);
-tree
-lto_resolve_typedecl_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref)
-{
- tree type = lto_resolve_type_ref (info_fd, context, ref);
+ lto_read_decls (file_data, data);
- return build_decl (TYPE_DECL, NULL_TREE, type);
-}
+ free ((char *)data);
-/* Returns the NAMESPACE_DECL corresponding to the DIE located at REF from
- INFO_FD. CONTEXT is the current context within the compilation unit.
- Note: Skipping around in the DWARF tree is buggy for NAMESPACE_DECL's
- because the context parentdata needed to properly set DECL_CONTEXT
- is missing. Consequently, we generate an error if the result is not
- cached. */
-tree
-lto_resolve_namespacedecl_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref)
-{
- lto_die_ptr die;
- lto_context *new_context = context;
- tree decl;
+ lto_materialize_constructors_and_inits (file_data);
- /* At present, we only support a single DWARF section. */
- if (ref->section != 0)
- lto_abi_mismatch_error ();
- /* Map REF to a DIE. */
- die = lto_resolve_reference (info_fd, ref->offset, context, &new_context);
- /* Map DIE to a namespace decl. */
- decl = lto_cache_lookup_DIE (info_fd, die, /*skip=*/false);
- if (!decl || TREE_CODE (decl) != NAMESPACE_DECL)
- lto_file_corrupt_error ((lto_fd *)info_fd);
+ lto_materialize_cgraph (file_data);
- /* Clean up. */
- if (new_context != context)
- XDELETE (new_context);
+ /* ### We never free file_data. */
- return decl;
+ return true;
}
/* Needed so the garbage collector knows to root around in functions we
diff --git a/gcc/lto/lto.h b/gcc/lto/lto.h
index 3826651fde8..099315b34b3 100644
--- a/gcc/lto/lto.h
+++ b/gcc/lto/lto.h
@@ -32,117 +32,7 @@ Boston, MA 02110-1301, USA. */
#include "lto-section-in.h"
/* Forward Declarations */
-
struct lto_file_struct;
-typedef struct lto_context lto_context;
-
-/* Types */
-
-/* A DWARF2 attribute. */
-typedef struct DWARF2_attr_struct GTY(())
-{
- /* The name of the attribute, e.g., DW_AT_name. */
- uint64_t name;
- /* The form of the attribute, e.g., DW_FORM_data2. */
- uint64_t form;
-}
-DWARF2_attr;
-
-/* A DWARF2 abbreviation-table entry. */
-typedef struct DWARF2_abbrev_struct GTY(())
-{
- /* The tag for a DIE using this abbreviation, e.g.,
- DW_TAG_pointer_type. */
- uint64_t tag;
- /* True if the next DIE is a child of this one; false, if the next
- DIE is a sibling of this one. */
- bool has_children;
- /* The number of attributes in the ATTRIBUTES array. */
- size_t num_attrs;
- /* A dynamically-sized array of attributes. */
- DWARF2_attr GTY((length ("%h.num_attrs"))) attrs[1];
-}
-DWARF2_abbrev;
-
-/* A DWARF2 compilation unit. */
-typedef struct DWARF2_CompUnit_struct GTY(())
-{
- /* Offset from start of .debug_info for this CU. */
- uint64_t cu_start_offset;
- /* Length of the CU header. */
- uint64_t cu_header_length;
- /* Length of CU *including* the length field. */
- uint64_t cu_length;
- /* DWARF version number of this CU. */
- unsigned short cu_version;
- /* Offset of abbrevs for this CU from the start of debug_abbrev. */
- uint64_t cu_abbrev_offset;
- /* Pointer size of this CU. */
- unsigned char cu_pointer_size;
-}
-DWARF2_CompUnit;
-
-/* A pointer to a DWARF2 DIE, as mapped into memory.
-
- The "lto_die" type is intentionally never defined. This typedef
- exists purely for type safety. */
-typedef struct lto_die *lto_die_ptr;
-
-/* A cache entry for mapping DIEs to trees. */
-typedef struct lto_die_cache_entry GTY(())
-{
- /* The DIE address. */
- lto_die_ptr GTY((skip)) die;
- /* The tree corresponding to this DIE. */
- tree val;
- /* The address of the next sibling after the DIE. */
- const char *sibling;
-} lto_die_cache_entry;
-
-/* A file descriptor for reading from a particular DWARF section. */
-typedef struct lto_fd_struct GTY(())
-{
- /* The name of this section. */
- const char *name;
- /* The first byte of the section. */
- const char *start;
- /* The byte just past the end of the section. */
- const char *end;
- /* The next available byte. */
- const char *cur;
- /* The lto_file with which this section is associated. */
- struct lto_file_struct * GTY((skip)) file;
- /* True if using 64-bit DWARF. */
- bool dwarf64;
-}
-lto_fd;
-
-/* A file descriptor for reading from a DWARF information section. */
-typedef struct lto_info_fd_struct GTY(())
-{
- /* The base object. */
- lto_fd base;
- /* The number of compilation units in this section. */
- size_t num_units;
- /* The compilation units themselves. */
- DWARF2_CompUnit ** GTY((length ("%h.num_units"), skip)) units;
- /* A map from DIEs to trees. The keys are offsets into the DWARF
- information section; the values are trees. */
- htab_t GTY((param_is (lto_die_cache_entry))) die_cache;
-}
-lto_info_fd;
-
-/* A file descriptor for reading from a DWARF abbreviation section. */
-typedef struct lto_abbrev_fd_struct GTY(())
-{
- /* The base object. */
- lto_fd base;
- /* The number of abbreviations in this section. */
- size_t num_abbrevs;
- /* The abbreviations themselves. */
- DWARF2_abbrev ** GTY((length ("%h.num_abbrevs"), skip)) abbrevs;
-}
-lto_abbrev_fd;
/* The virtual function table for an lto_file. */
typedef struct lto_file_vtable_struct GTY(())
@@ -166,21 +56,14 @@ typedef struct lto_file_struct GTY(())
const lto_file_vtable * GTY((skip)) vtable;
/* The name of the file. */
const char *filename;
- /* The contents of the .debug_info section. */
- lto_info_fd debug_info;
- /* The contents of the .debug_abbrev section. */
- lto_abbrev_fd debug_abbrev;
+
+ /* ### */
+ /* The debug_info and debug_abbrev fields are no longer used.
+ As a result, the lto_file vs. lto_elf_file distinction is
+ no longer useful, and should be eliminated. */
}
lto_file;
-/* A reference to a global entity (type, variable, or function). */
-typedef struct lto_ref
-{
- /* The DWARF compilation unit containing the entity. */
- uint64_t section;
- /* The offset of the DIE corresponding to the entity. */
- uint64_t offset;
-} lto_ref;
/* lto.c */
@@ -189,48 +72,6 @@ typedef struct lto_ref
to the middle end. */
extern void lto_main (int debug_p);
-/* Initialize the newly allocated FILE, which corresponds to
- FILENAME. VTABLE is the virtual table for FILE. */
-extern void lto_file_init (lto_file *file,
- const lto_file_vtable *vtable,
- const char *filename);
-
-/* Free resources associated with FILE. FILE itself will be
- deallocated by this function. */
-extern void lto_file_close (lto_file *file);
-
-/* Return the TYPE referred to by REF. */
-extern tree lto_resolve_type_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref);
-
-/* Return the VAR_DECL referred to by REF. */
-extern tree lto_resolve_var_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref);
-
-/* Return the FUNCTION_DECL referred to by REF. */
-extern tree lto_resolve_fn_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref);
-
-/* Return the FIELD_DECL referred to by REF. */
-extern tree lto_resolve_field_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref);
-
-/* Return the TYPE_DECL referred to by REF. */
-extern tree lto_resolve_typedecl_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref);
-
-/* Return the NAMESPACE_DECL referred to by REF. */
-extern tree lto_resolve_namespacedecl_ref (lto_info_fd *info_fd,
- lto_context *context,
- const lto_ref *ref);
-
-/* Get the file name associated with INFO_FD. */
-extern const char *lto_get_file_name (lto_info_fd *info_fd);
/* lto-elf.c */
@@ -243,21 +84,4 @@ extern void lto_elf_file_close (lto_file *file);
/* Build and index of all lto sections in an elf file. */
extern htab_t lto_elf_build_section_table (lto_file *file);
-/* lto-symtab.c */
-
-/* The NEW_VAR (a VAR_DECL) has just been read. If there is an
- existing variable with the same name, merge the declaration for
- NEW_VAR with the previous declaration and return the previous
- declaration. In this case, NEW_VAR must no longer be used by the
- caller. All other entities referenced from NEW_VAR (including, in
- particular, its type) must already have been merged before this
- function is called. If the merge fails (due to inconsistencies
- between the declarations), an error message is issued, and
- error_mark_node is returned. If there is no previous declaration,
- NEW_VAR is returned. */
-extern tree lto_symtab_merge_var (tree new_var);
-
-/* Like lto_symtab_merge_var, but for functions. */
-extern tree lto_symtab_merge_fn (tree new_fn);
-
#endif /* LTO_H */