};
-/* Returns a hash code for P. */
+/* Returns a hash code for P.
+ Shamelessly stollen from libiberty. */
static hashval_t
hash_string_slot_node (const void *p)
{
const struct string_slot *ds = (const struct string_slot *) p;
- return (hashval_t) htab_hash_string (ds->s);
+ hashval_t r = ds->len;
+ int i;
+
+ for (i = 0; i < ds->len; i++)
+ r = r * 67 + (unsigned)ds->s[i] - 113;
+ return r;
}
const struct string_slot *ds2 = (const struct string_slot *) p2;
if (ds1->len == ds2->len)
- {
- int i;
- for (i = 0; i < ds1->len; i++)
- if (ds1->s[i] != ds2->s[i])
- return 0;
- return 1;
- }
+ return memcmp (ds1->s, ds2->s, ds1->len) == 0;
return 0;
}
-/* Free the string slot pointed-to by P. */
-
-static void
-string_slot_free (void *p)
-{
- struct string_slot *slot = (struct string_slot *) p;
- free (CONST_CAST (void *, (const void *) slot->s));
- free (slot);
-}
-
-
/* Clear the line info stored in DATA_IN. */
static void
clear_line_info (ob);
ob->string_hash_table = htab_create (37, hash_string_slot_node,
- eq_string_slot_node, string_slot_free);
+ eq_string_slot_node, NULL);
+ gcc_obstack_init (&ob->obstack);
return ob;
}
free (ob->cfg_stream);
lto_streamer_cache_delete (ob->writer_cache);
+ obstack_free (&ob->obstack, NULL);
free (ob);
}
+/* Return index used to reference STRING of LEN characters in the string table
+ in OB. The string might or might not include a trailing '\0'.
+ Then put the index onto the INDEX_STREAM.
+ When PERSISTENT is set, the string S is supposed to not change during
+ duration of the OB and thus OB can keep pointer into it. */
-/* Output STRING of LEN characters to the string
- table in OB. The string might or might not include a trailing '\0'.
- Then put the index onto the INDEX_STREAM. */
-
-void
-lto_output_string_with_length (struct output_block *ob,
- struct lto_output_stream *index_stream,
- const char *s,
- unsigned int len)
+static unsigned
+lto_string_index (struct output_block *ob,
+ const char *s,
+ unsigned int len,
+ bool persistent)
{
struct string_slot **slot;
struct string_slot s_slot;
- char *string = (char *) xmalloc (len + 1);
- memcpy (string, s, len);
- string[len] = '\0';
- s_slot.s = string;
+ s_slot.s = s;
s_slot.len = len;
s_slot.slot_num = 0;
- /* Indicate that this is not a NULL string. */
- lto_output_uleb128_stream (index_stream, 0);
-
slot = (struct string_slot **) htab_find_slot (ob->string_hash_table,
&s_slot, INSERT);
if (*slot == NULL)
struct lto_output_stream *string_stream = ob->string_stream;
unsigned int start = string_stream->total_size;
struct string_slot *new_slot
- = (struct string_slot *) xmalloc (sizeof (struct string_slot));
- unsigned int i;
+ = XOBNEW (&ob->obstack, struct string_slot);
+ const char *string;
+
+ if (!persistent)
+ {
+ char *tmp;
+ string = tmp = XOBNEWVEC (&ob->obstack, char, len);
+ memcpy (tmp, s, len);
+ }
+ else
+ string = s;
new_slot->s = string;
new_slot->len = len;
new_slot->slot_num = start;
*slot = new_slot;
- lto_output_uleb128_stream (index_stream, start);
lto_output_uleb128_stream (string_stream, len);
- for (i = 0; i < len; i++)
- lto_output_1_stream (string_stream, string[i]);
+ lto_output_data_stream (string_stream, string, len);
+ return start + 1;
}
else
{
- struct string_slot *old_slot = (struct string_slot *)*slot;
- lto_output_uleb128_stream (index_stream, old_slot->slot_num);
- free (string);
+ struct string_slot *old_slot = *slot;
+ return old_slot->slot_num + 1;
}
}
+
+/* Output STRING of LEN characters to the string
+ table in OB. The string might or might not include a trailing '\0'.
+ Then put the index onto the INDEX_STREAM.
+ When PERSISTENT is set, the string S is supposed to not change during
+ duration of the OB and thus OB can keep pointer into it. */
+
+static void
+lto_output_string_with_length (struct output_block *ob,
+ struct lto_output_stream *index_stream,
+ const char *s,
+ unsigned int len,
+ bool persistent)
+{
+ if (s)
+ lto_output_uleb128_stream (index_stream,
+ lto_string_index (ob, s, len, persistent));
+ else
+ lto_output_1_stream (index_stream, 0);
+}
+
/* Output the '\0' terminated STRING to the string
- table in OB. Then put the index onto the INDEX_STREAM. */
+ table in OB. Then put the index onto the INDEX_STREAM.
+ When PERSISTENT is set, the string S is supposed to not change during
+ duration of the OB and thus OB can keep pointer into it. */
-void
+static void
lto_output_string (struct output_block *ob,
struct lto_output_stream *index_stream,
- const char *string)
+ const char *string,
+ bool persistent)
{
if (string)
lto_output_string_with_length (ob, index_stream, string,
- strlen (string) + 1);
+ strlen (string) + 1,
+ persistent);
else
- lto_output_uleb128_stream (index_stream, 1);
+ lto_output_1_stream (index_stream, 0);
}
struct lto_output_stream *index_stream,
tree string)
{
- if (string)
- lto_output_string_with_length (ob, index_stream,
- TREE_STRING_POINTER (string),
- TREE_STRING_LENGTH (string ));
- else
- lto_output_uleb128_stream (index_stream, 1);
+ lto_output_string_with_length (ob, index_stream,
+ TREE_STRING_POINTER (string),
+ TREE_STRING_LENGTH (string),
+ true);
}
struct lto_output_stream *index_stream,
tree id)
{
- if (id)
- lto_output_string_with_length (ob, index_stream,
- IDENTIFIER_POINTER (id),
- IDENTIFIER_LENGTH (id));
- else
- lto_output_uleb128_stream (index_stream, 1);
+ lto_output_string_with_length (ob, index_stream,
+ IDENTIFIER_POINTER (id),
+ IDENTIFIER_LENGTH (id),
+ true);
}
+
/* Write a zero to the output stream. */
static void
/* Output the start of a record with TAG to output block OB. */
-static void
+static inline void
output_record_start (struct output_block *ob, enum LTO_tags tag)
{
- /* Make sure TAG fits inside an unsigned int. */
- gcc_assert (tag == (enum LTO_tags) (unsigned) tag);
- output_uleb128 (ob, tag);
+ lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS, tag);
}
bp_pack_value (bp, 0, 1);
/* We write debug info two times, do not confuse the second one. */
bp_pack_value (bp, TYPE_P (expr) ? 0 : TREE_ASM_WRITTEN (expr), 1);
- bp_pack_value (bp, TREE_NO_WARNING (expr), 1);
+ if (TYPE_P (expr))
+ bp_pack_value (bp, TYPE_ARTIFICIAL (expr), 1);
+ else
+ bp_pack_value (bp, TREE_NO_WARNING (expr), 1);
bp_pack_value (bp, TREE_USED (expr), 1);
bp_pack_value (bp, TREE_NOTHROW (expr), 1);
bp_pack_value (bp, TREE_STATIC (expr), 1);
pack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
{
struct fixed_value fv = TREE_FIXED_CST (expr);
- bp_pack_value (bp, fv.data.low, HOST_BITS_PER_WIDE_INT);
- bp_pack_value (bp, fv.data.high, HOST_BITS_PER_WIDE_INT);
- bp_pack_value (bp, fv.mode, HOST_BITS_PER_INT);
+ bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, fv.mode);
+ bp_pack_var_len_int (bp, fv.data.low);
+ bp_pack_var_len_int (bp, fv.data.high);
}
static void
pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
{
- bp_pack_value (bp, DECL_MODE (expr), 8);
+ bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, DECL_MODE (expr));
bp_pack_value (bp, DECL_NONLOCAL (expr), 1);
bp_pack_value (bp, DECL_VIRTUAL_P (expr), 1);
bp_pack_value (bp, DECL_IGNORED_P (expr), 1);
bp_pack_value (bp, DECL_DEBUG_EXPR_IS_FROM (expr), 1);
bp_pack_value (bp, DECL_EXTERNAL (expr), 1);
bp_pack_value (bp, DECL_GIMPLE_REG_P (expr), 1);
- bp_pack_value (bp, DECL_ALIGN (expr), HOST_BITS_PER_INT);
+ bp_pack_var_len_unsigned (bp, DECL_ALIGN (expr));
if (TREE_CODE (expr) == LABEL_DECL)
{
always assume an initial value of -1 so that the
label_to_block_map is recreated by gimple_set_bb. */
bp_pack_value (bp, DECL_ERROR_ISSUED (expr), 1);
- bp_pack_value (bp, EH_LANDING_PAD_NR (expr), HOST_BITS_PER_INT);
+ bp_pack_var_len_unsigned (bp, EH_LANDING_PAD_NR (expr));
}
if (TREE_CODE (expr) == FIELD_DECL)
{
bp_pack_value (bp, DECL_PACKED (expr), 1);
bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
- bp_pack_value (bp, DECL_OFFSET_ALIGN (expr), 8);
+ bp_pack_value (bp, expr->decl_common.off_align, 8);
}
if (TREE_CODE (expr) == RESULT_DECL
}
if (VAR_OR_FUNCTION_DECL_P (expr))
- bp_pack_value (bp, DECL_INIT_PRIORITY (expr), HOST_BITS_PER_SHORT);
+ bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr));
}
should never be handled here. */
gcc_assert (!lto_stream_as_builtin_p (expr));
- bp_pack_value (bp, DECL_FUNCTION_CODE (expr), 11);
- bp_pack_value (bp, DECL_BUILT_IN_CLASS (expr), 2);
+ bp_pack_enum (bp, built_in_class, BUILT_IN_LAST,
+ DECL_BUILT_IN_CLASS (expr));
bp_pack_value (bp, DECL_STATIC_CONSTRUCTOR (expr), 1);
bp_pack_value (bp, DECL_STATIC_DESTRUCTOR (expr), 1);
bp_pack_value (bp, DECL_UNINLINABLE (expr), 1);
bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1);
bp_pack_value (bp, DECL_PURE_P (expr), 1);
bp_pack_value (bp, DECL_LOOPING_CONST_OR_PURE_P (expr), 1);
+ if (DECL_BUILT_IN_CLASS (expr) != NOT_BUILT_IN)
+ bp_pack_value (bp, DECL_FUNCTION_CODE (expr), 11);
if (DECL_STATIC_DESTRUCTOR (expr))
- bp_pack_value (bp, DECL_FINI_PRIORITY (expr), HOST_BITS_PER_SHORT);
+ bp_pack_var_len_unsigned (bp, DECL_FINI_PRIORITY (expr));
}
-/* Pack all the non-pointer fields of the TS_TYPE structure
+/* Pack all the non-pointer fields of the TS_TYPE_COMMON structure
of expression EXPR into bitpack BP. */
static void
-pack_ts_type_value_fields (struct bitpack_d *bp, tree expr)
+pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
{
- bp_pack_value (bp, TYPE_PRECISION (expr), 10);
- bp_pack_value (bp, TYPE_MODE (expr), 8);
+ bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, TYPE_MODE (expr));
bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1);
bp_pack_value (bp, TYPE_NO_FORCE_BLK (expr), 1);
bp_pack_value (bp, TYPE_NEEDS_CONSTRUCTING (expr), 1);
bp_pack_value (bp, TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr), 2);
bp_pack_value (bp, TYPE_USER_ALIGN (expr), 1);
bp_pack_value (bp, TYPE_READONLY (expr), 1);
- bp_pack_value (bp, TYPE_ALIGN (expr), HOST_BITS_PER_INT);
- bp_pack_value (bp, TYPE_ALIAS_SET (expr) == 0 ? 0 : -1, HOST_BITS_PER_INT);
+ bp_pack_var_len_unsigned (bp, TYPE_PRECISION (expr));
+ bp_pack_var_len_unsigned (bp, TYPE_ALIGN (expr));
+ bp_pack_var_len_int (bp, TYPE_ALIAS_SET (expr) == 0 ? 0 : -1);
}
pack_ts_block_value_fields (struct bitpack_d *bp, tree expr)
{
bp_pack_value (bp, BLOCK_ABSTRACT (expr), 1);
- bp_pack_value (bp, BLOCK_NUMBER (expr), 31);
+ /* BLOCK_NUMBER is recomputed. */
}
/* Pack all the non-pointer fields of the TS_TRANSLATION_UNIT_DECL structure
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
pack_ts_function_decl_value_fields (bp, expr);
- if (CODE_CONTAINS_STRUCT (code, TS_TYPE))
- pack_ts_type_value_fields (bp, expr);
+ if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
+ pack_ts_type_common_value_fields (bp, expr);
if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
pack_ts_block_value_fields (bp, expr);
- if (CODE_CONTAINS_STRUCT (code, TS_SSA_NAME))
- {
- /* We only stream the version number of SSA names. */
- gcc_unreachable ();
- }
-
- if (CODE_CONTAINS_STRUCT (code, TS_STATEMENT_LIST))
- {
- /* This is only used by GENERIC. */
- gcc_unreachable ();
- }
-
- if (CODE_CONTAINS_STRUCT (code, TS_OMP_CLAUSE))
- {
- /* This is only used by High GIMPLE. */
- gcc_unreachable ();
- }
-
if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
pack_ts_translation_unit_decl_value_fields (bp, expr);
+
+ if (streamer_hooks.pack_value_fields)
+ streamer_hooks.pack_value_fields (bp, expr);
}
-/* Emit location LOC to output block OB. */
+/* Output info about new location into bitpack BP.
+ After outputting bitpack, lto_output_location_data has
+ to be done to output actual data. */
-static void
-lto_output_location (struct output_block *ob, location_t loc)
+static inline void
+lto_output_location_bitpack (struct bitpack_d *bp,
+ struct output_block *ob,
+ location_t loc)
{
expanded_location xloc;
+ bp_pack_value (bp, loc == UNKNOWN_LOCATION, 1);
if (loc == UNKNOWN_LOCATION)
- {
- lto_output_string (ob, ob->main_stream, NULL);
- return;
- }
+ return;
xloc = expand_location (loc);
- lto_output_string (ob, ob->main_stream, xloc.file);
- output_sleb128 (ob, xloc.line);
- output_sleb128 (ob, xloc.column);
- output_sleb128 (ob, xloc.sysp);
-
+ bp_pack_value (bp, ob->current_file != xloc.file, 1);
+ if (ob->current_file != xloc.file)
+ bp_pack_var_len_unsigned (bp, lto_string_index (ob,
+ xloc.file,
+ strlen (xloc.file) + 1,
+ true));
ob->current_file = xloc.file;
+
+ bp_pack_value (bp, ob->current_line != xloc.line, 1);
+ if (ob->current_line != xloc.line)
+ bp_pack_var_len_unsigned (bp, xloc.line);
ob->current_line = xloc.line;
+
+ bp_pack_value (bp, ob->current_col != xloc.column, 1);
+ if (ob->current_col != xloc.column)
+ bp_pack_var_len_unsigned (bp, xloc.column);
ob->current_col = xloc.column;
}
+/* Emit location LOC to output block OB.
+ When bitpack is handy, it is more space effecient to call
+ lto_output_location_bitpack with existing bitpack. */
+
+static void
+lto_output_location (struct output_block *ob, location_t loc)
+{
+ struct bitpack_d bp = bitpack_create (ob->main_stream);
+ lto_output_location_bitpack (&bp, ob, loc);
+ lto_output_bitpack (&bp);
+}
+
+
/* Return true if tree node T is written to various tables. For these
nodes, we sometimes want to write their phyiscal representation
(via lto_output_tree), and sometimes we need to emit an index
if (expr == NULL_TREE)
{
- output_zero (ob);
+ output_record_start (ob, LTO_null);
return;
}
break;
default:
- /* No other node is indexable, so it should have been handled
- by lto_output_tree. */
- gcc_unreachable ();
+ {
+ /* See if the streamer allows this node to be indexable
+ like other global declarations. */
+ if (streamer_hooks.indexable_with_decls_p
+ && streamer_hooks.indexable_with_decls_p (expr))
+ {
+ output_record_start (ob, LTO_global_decl_ref);
+ lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
+ }
+ else
+ {
+ /* No other node is indexable, so it should have been
+ handled by lto_output_tree. */
+ gcc_unreachable ();
+ }
+ }
}
}
lto_output_tree_or_ref (ob, DECL_SIZE (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_SIZE_UNIT (expr), ref_p);
- if (TREE_CODE (expr) != FUNCTION_DECL
- && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
- {
- tree initial = DECL_INITIAL (expr);
- if (TREE_CODE (expr) == VAR_DECL
- && (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
- && initial)
- {
- lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
- struct varpool_node *vnode = varpool_get_node (expr);
- if (!vnode)
- initial = error_mark_node;
- else if (!lto_varpool_encoder_encode_initializer_p (varpool_encoder,
- vnode))
- initial = NULL;
- }
-
- lto_output_tree_or_ref (ob, initial, ref_p);
- }
+ /* Note, DECL_INITIAL is not handled here. Since DECL_INITIAL needs
+ special handling in LTO, it must be handled by streamer hooks. */
lto_output_tree_or_ref (ob, DECL_ATTRIBUTES (expr), ref_p);
+
/* Do not stream DECL_ABSTRACT_ORIGIN. We cannot handle debug information
for early inlining so drop it on the floor instead of ICEing in
dwarf2out.c. */
{
if (TREE_CODE (expr) == FUNCTION_DECL)
{
- /* DECL_SAVED_TREE holds the GENERIC representation for DECL.
- At this point, it should not exist. Either because it was
- converted to gimple or because DECL didn't have a GENERIC
- representation in this TU. */
- gcc_assert (DECL_SAVED_TREE (expr) == NULL_TREE);
lto_output_tree_or_ref (ob, DECL_ARGUMENTS (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_RESULT (expr), ref_p);
}
if (DECL_ASSEMBLER_NAME_SET_P (expr))
lto_output_tree_or_ref (ob, DECL_ASSEMBLER_NAME (expr), ref_p);
else
- output_zero (ob);
+ output_record_start (ob, LTO_null);
lto_output_tree_or_ref (ob, DECL_SECTION_NAME (expr), ref_p);
lto_output_tree_or_ref (ob, DECL_COMDAT_GROUP (expr), ref_p);
}
-/* Write all pointer fields in the TS_TYPE structure of EXPR to output
- block OB. If REF_P is true, write a reference to EXPR's pointer
- fields. */
+/* Write all pointer fields in the TS_TYPE_COMMON structure of EXPR to
+ output block OB. If REF_P is true, write a reference to EXPR's
+ pointer fields. */
static void
-lto_output_ts_type_tree_pointers (struct output_block *ob, tree expr,
- bool ref_p)
+lto_output_ts_type_common_tree_pointers (struct output_block *ob, tree expr,
+ bool ref_p)
+{
+ lto_output_tree_or_ref (ob, TYPE_SIZE (expr), ref_p);
+ lto_output_tree_or_ref (ob, TYPE_SIZE_UNIT (expr), ref_p);
+ lto_output_tree_or_ref (ob, TYPE_ATTRIBUTES (expr), ref_p);
+ lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p);
+ /* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO. They will be
+ reconstructed during fixup. */
+ /* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
+ during fixup. */
+ lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p);
+ lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p);
+ /* TYPE_CANONICAL is re-computed during type merging, so no need
+ to stream it here. */
+ lto_output_tree_or_ref (ob, TYPE_STUB_DECL (expr), ref_p);
+}
+
+/* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
+ to output block OB. If REF_P is true, write a reference to EXPR's
+ pointer fields. */
+
+static void
+lto_output_ts_type_non_common_tree_pointers (struct output_block *ob,
+ tree expr, bool ref_p)
{
if (TREE_CODE (expr) == ENUMERAL_TYPE)
lto_output_tree_or_ref (ob, TYPE_VALUES (expr), ref_p);
|| TREE_CODE (expr) == METHOD_TYPE)
lto_output_tree_or_ref (ob, TYPE_ARG_TYPES (expr), ref_p);
- lto_output_tree_or_ref (ob, TYPE_SIZE (expr), ref_p);
- lto_output_tree_or_ref (ob, TYPE_SIZE_UNIT (expr), ref_p);
- lto_output_tree_or_ref (ob, TYPE_ATTRIBUTES (expr), ref_p);
- lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p);
- /* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO nor
- TYPE_NEXT_PTR_TO or TYPE_NEXT_REF_TO. */
if (!POINTER_TYPE_P (expr))
lto_output_tree_or_ref (ob, TYPE_MINVAL (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MAXVAL (expr), ref_p);
- lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p);
- /* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
- during fixup. */
if (RECORD_OR_UNION_TYPE_P (expr))
lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
- lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p);
- /* TYPE_CANONICAL is re-computed during type merging, so no need
- to stream it here. */
- lto_output_tree_or_ref (ob, TYPE_STUB_DECL (expr), ref_p);
}
is needed to build the empty BINFO node on the reader side. */
FOR_EACH_VEC_ELT (tree, BINFO_BASE_BINFOS (expr), i, t)
lto_output_tree_or_ref (ob, t, ref_p);
- output_zero (ob);
+ output_record_start (ob, LTO_null);
lto_output_tree_or_ref (ob, BINFO_OFFSET (expr), ref_p);
lto_output_tree_or_ref (ob, BINFO_VTABLE (expr), ref_p);
- lto_output_tree_or_ref (ob, BINFO_VIRTUALS (expr), ref_p);
+ /* BINFO_VIRTUALS is used to drive type based devirtualizatoin. It often links
+ together large portions of programs making it harder to partition. Becuase
+ devirtualization is interesting before inlining, only, there is no real
+ need to ship it into ltrans partition. */
+ lto_output_tree_or_ref (ob, flag_wpa ? NULL : BINFO_VIRTUALS (expr), ref_p);
lto_output_tree_or_ref (ob, BINFO_VPTR_FIELD (expr), ref_p);
output_uleb128 (ob, VEC_length (tree, BINFO_BASE_ACCESSES (expr)));
lto_output_ts_translation_unit_decl_tree_pointers (struct output_block *ob,
tree expr)
{
- lto_output_string (ob, ob->main_stream, TRANSLATION_UNIT_LANGUAGE (expr));
+ lto_output_string (ob, ob->main_stream,
+ TRANSLATION_UNIT_LANGUAGE (expr), true);
}
/* Helper for lto_output_tree. Write all pointer fields in EXPR to output
code = TREE_CODE (expr);
- if (CODE_CONTAINS_STRUCT (code, TS_COMMON))
+ if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
lto_output_ts_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_VECTOR))
if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL))
lto_output_ts_function_decl_tree_pointers (ob, expr, ref_p);
- if (CODE_CONTAINS_STRUCT (code, TS_TYPE))
- lto_output_ts_type_tree_pointers (ob, expr, ref_p);
+ if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
+ lto_output_ts_type_common_tree_pointers (ob, expr, ref_p);
+
+ if (CODE_CONTAINS_STRUCT (code, TS_TYPE_NON_COMMON))
+ lto_output_ts_type_non_common_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_LIST))
lto_output_ts_list_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_EXP))
lto_output_ts_exp_tree_pointers (ob, expr, ref_p);
- if (CODE_CONTAINS_STRUCT (code, TS_SSA_NAME))
- {
- /* We only stream the version number of SSA names. */
- gcc_unreachable ();
- }
-
if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
lto_output_ts_block_tree_pointers (ob, expr, ref_p);
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
lto_output_ts_constructor_tree_pointers (ob, expr, ref_p);
- if (CODE_CONTAINS_STRUCT (code, TS_STATEMENT_LIST))
- {
- /* This should only appear in GENERIC. */
- gcc_unreachable ();
- }
-
- if (CODE_CONTAINS_STRUCT (code, TS_OMP_CLAUSE))
- {
- /* This should only appear in High GIMPLE. */
- gcc_unreachable ();
- }
-
- if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
- sorry ("gimple bytecode streams do not support the optimization attribute");
-
if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
lto_output_ts_target_option (ob, expr);
where EXPR is stored. REF_P is as in lto_output_tree. */
static void
-lto_output_tree_header (struct output_block *ob, tree expr, int ix)
+lto_output_tree_header (struct output_block *ob, tree expr)
{
enum LTO_tags tag;
enum tree_code code;
- /* We should not see any non-GIMPLE tree nodes here. */
+ /* We should not see any tree nodes not handled by the streamer. */
code = TREE_CODE (expr);
- if (!lto_is_streamable (expr))
- internal_error ("tree code %qs is not supported in gimple streams",
- tree_code_name[code]);
+ if (!streamer_hooks.is_streamable (expr))
+ internal_error ("tree code %qs is not supported in %s streams",
+ tree_code_name[code], streamer_hooks.name);
/* The header of a tree node consists of its tag, the size of
the node, and any other information needed to instantiate
variable sized nodes). */
tag = lto_tree_code_to_tag (code);
output_record_start (ob, tag);
- output_sleb128 (ob, ix);
/* The following will cause bootstrap miscomparisons. Enable with care. */
#ifdef LTO_STREAMER_DEBUG
output_sleb128 (ob, TREE_VEC_LENGTH (expr));
else if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
output_uleb128 (ob, BINFO_N_BASE_BINFOS (expr));
+
+ /* Allow the streamer to write any streamer-specific information
+ needed to instantiate the node when reading. */
+ if (streamer_hooks.output_tree_header)
+ streamer_hooks.output_tree_header (ob, expr);
}
the index into the streamer cache where EXPR is stored.*/
static void
-lto_output_builtin_tree (struct output_block *ob, tree expr, int ix)
+lto_output_builtin_tree (struct output_block *ob, tree expr)
{
gcc_assert (lto_stream_as_builtin_p (expr));
"functions on this target");
output_record_start (ob, LTO_builtin_decl);
- output_uleb128 (ob, DECL_BUILT_IN_CLASS (expr));
+ lto_output_enum (ob->main_stream, built_in_class, BUILT_IN_LAST,
+ DECL_BUILT_IN_CLASS (expr));
output_uleb128 (ob, DECL_FUNCTION_CODE (expr));
- output_sleb128 (ob, ix);
if (DECL_ASSEMBLER_NAME_SET_P (expr))
{
reader side from adding a second '*', we omit it here. */
const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (expr));
if (strlen (str) > 1 && str[0] == '*')
- lto_output_string (ob, ob->main_stream, &str[1]);
+ lto_output_string (ob, ob->main_stream, &str[1], true);
else
- lto_output_string (ob, ob->main_stream, NULL);
+ lto_output_string (ob, ob->main_stream, NULL, true);
}
else
- lto_output_string (ob, ob->main_stream, NULL);
+ lto_output_string (ob, ob->main_stream, NULL, true);
}
where EXPR is stored. */
static void
-lto_write_tree (struct output_block *ob, tree expr, bool ref_p, int ix)
+lto_write_tree (struct output_block *ob, tree expr, bool ref_p)
{
struct bitpack_d bp;
/* Write the header, containing everything needed to materialize
EXPR on the reading side. */
- lto_output_tree_header (ob, expr, ix);
+ lto_output_tree_header (ob, expr);
/* Pack all the non-pointer fields in EXPR into a bitpack and write
the resulting bitpack. */
/* Write all the pointer fields in EXPR. */
lto_output_tree_pointers (ob, expr, ref_p);
+ /* Call back into the streaming module to see if it needs to write
+ anything that was not written by the common streamer. */
+ if (streamer_hooks.write_tree)
+ streamer_hooks.write_tree (ob, expr, ref_p);
+
/* Mark the end of EXPR. */
output_zero (ob);
}
+/* GIMPLE hook for writing GIMPLE-specific parts of trees. OB, EXPR
+ and REF_P are as in lto_write_tree. */
+
+void
+lto_streamer_write_tree (struct output_block *ob, tree expr, bool ref_p)
+{
+ if (DECL_P (expr)
+ && TREE_CODE (expr) != FUNCTION_DECL
+ && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
+ {
+ /* Handle DECL_INITIAL for symbols. */
+ tree initial = DECL_INITIAL (expr);
+ if (TREE_CODE (expr) == VAR_DECL
+ && (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
+ && initial)
+ {
+ lto_varpool_encoder_t varpool_encoder;
+ struct varpool_node *vnode;
+
+ varpool_encoder = ob->decl_state->varpool_node_encoder;
+ vnode = varpool_get_node (expr);
+ if (!vnode)
+ initial = error_mark_node;
+ else if (!lto_varpool_encoder_encode_initializer_p (varpool_encoder,
+ vnode))
+ initial = NULL;
+ }
+
+ lto_output_tree_or_ref (ob, initial, ref_p);
+ }
+}
+
+
/* Emit the integer constant CST to output block OB. If REF_P is true,
CST's type will be emitted as a reference. */
void
lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
{
- int ix;
+ unsigned ix;
bool existed_p;
- unsigned offset;
if (expr == NULL_TREE)
{
- output_zero (ob);
+ output_record_start (ob, LTO_null);
return;
}
return;
}
- /* Determine the offset in the stream where EXPR will be written.
- This is used when emitting pickle references so the reader knows
- where to reconstruct the pickled object from. This allows
- circular and forward references within the same stream. */
- offset = ob->main_stream->total_size;
-
- existed_p = lto_streamer_cache_insert (ob->writer_cache, expr, &ix, &offset);
+ existed_p = lto_streamer_cache_insert (ob->writer_cache, expr, &ix);
if (existed_p)
{
/* If a node has already been streamed out, make sure that
we don't write it more than once. Otherwise, the reader
will instantiate two different nodes for the same object. */
output_record_start (ob, LTO_tree_pickle_reference);
- output_sleb128 (ob, ix);
- output_uleb128 (ob, lto_tree_code_to_tag (TREE_CODE (expr)));
- output_uleb128 (ob, offset);
+ output_uleb128 (ob, ix);
+ lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS,
+ lto_tree_code_to_tag (TREE_CODE (expr)));
}
else if (lto_stream_as_builtin_p (expr))
{
compiler on startup. The only builtins that need to
be written out are BUILT_IN_FRONTEND. For all other
builtins, we simply write the class and code. */
- lto_output_builtin_tree (ob, expr, ix);
+ lto_output_builtin_tree (ob, expr);
}
else
{
/* This is the first time we see EXPR, write its fields
to OB. */
- lto_write_tree (ob, expr, ref_p, ix);
+ lto_write_tree (ob, expr, ref_p);
}
}
lto_output_tree_ref (ob, n->label);
}
- output_zero (ob);
+ output_record_start (ob, LTO_null);
}
if (r == NULL)
{
- output_zero (ob);
+ output_record_start (ob, LTO_null);
return;
}
{
if (lp == NULL)
{
- output_zero (ob);
+ output_record_start (ob, LTO_null);
return;
}
}
}
- /* The 0 either terminates the record or indicates that there are no
- eh_records at all. */
- output_zero (ob);
+ /* The LTO_null either terminates the record or indicates that there
+ are no eh_records at all. */
+ output_record_start (ob, LTO_null);
}
ob->main_stream = ob->cfg_stream;
- output_uleb128 (ob, profile_status_for_function (fn));
+ lto_output_enum (ob->main_stream, profile_status_d, PROFILE_LAST,
+ profile_status_for_function (fn));
/* Output the number of the highest basic block. */
output_uleb128 (ob, last_basic_block_for_function (fn));
/* Emit the tuple header. */
bp = bitpack_create (ob->main_stream);
- bp_pack_value (&bp, gimple_num_ops (stmt), sizeof (unsigned) * 8);
+ bp_pack_var_len_unsigned (&bp, gimple_num_ops (stmt));
bp_pack_value (&bp, gimple_no_warning_p (stmt), 1);
if (is_gimple_assign (stmt))
bp_pack_value (&bp, gimple_assign_nontemporal_move_p (stmt), 1);
bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1);
- bp_pack_value (&bp, stmt->gsbase.subcode, 16);
+ bp_pack_var_len_unsigned (&bp, stmt->gsbase.subcode);
lto_output_bitpack (&bp);
/* Emit location information for the statement. */
lto_output_uleb128_stream (ob->main_stream, gimple_asm_noutputs (stmt));
lto_output_uleb128_stream (ob->main_stream, gimple_asm_nclobbers (stmt));
lto_output_uleb128_stream (ob->main_stream, gimple_asm_nlabels (stmt));
- lto_output_string (ob, ob->main_stream, gimple_asm_string (stmt));
+ lto_output_string (ob, ob->main_stream, gimple_asm_string (stmt), true);
/* Fallthru */
case GIMPLE_ASSIGN:
}
lto_output_tree_ref (ob, op);
}
+ if (is_gimple_call (stmt))
+ {
+ if (gimple_call_internal_p (stmt))
+ lto_output_enum (ob->main_stream, internal_fn,
+ IFN_LAST, gimple_call_internal_fn (stmt));
+ else
+ lto_output_tree_ref (ob, gimple_call_fntype (stmt));
+ }
break;
case GIMPLE_NOP:
output_sleb128 (ob, region);
}
else
- output_zero (ob);
+ output_record_start (ob, LTO_null);
}
- output_zero (ob);
+ output_record_start (ob, LTO_null);
for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
output_phi (ob, phi);
}
- output_zero (ob);
+ output_record_start (ob, LTO_null);
}
}
bp_pack_value (&bp, fn->can_throw_non_call_exceptions, 1);
bp_pack_value (&bp, fn->always_inline_functions_inlined, 1);
bp_pack_value (&bp, fn->after_inlining, 1);
- bp_pack_value (&bp, fn->dont_save_pending_sizes_p, 1);
bp_pack_value (&bp, fn->stdarg, 1);
bp_pack_value (&bp, fn->has_nonlocal_label, 1);
bp_pack_value (&bp, fn->calls_alloca, 1);
output_bb (ob, bb, fn);
/* The terminator for this function. */
- output_zero (ob);
+ output_record_start (ob, LTO_null);
output_cfg (ob, fn);
struct output_block *ob;
alias_pair *p;
unsigned i;
- struct varpool_node *vnode;
symbol_alias_set_t *defined;
struct sets setdata;
/* Make string 0 be a NULL string. */
lto_output_1_stream (ob->string_stream, 0);
- /* Emit references for all the global symbols. If a global symbol
- was never referenced in any of the functions of this file, it
- would not be emitted otherwise. This will result in unreferenced
- symbols at link time if a file defines a global symbol but
- never references it. */
- FOR_EACH_STATIC_VARIABLE (vnode)
- if (vnode->needed && varpool_node_in_set_p (vnode, vset))
- {
- tree var = vnode->decl;
-
- if (TREE_CODE (var) == VAR_DECL)
- {
- /* Output the object in order to output references used in the
- initialization. */
- lto_output_tree (ob, var, true);
-
- /* If it is public we also need a reference to the object itself. */
- if (TREE_PUBLIC (var))
- lto_output_tree_ref (ob, var);
- }
- }
-
- output_zero (ob);
-
/* We really need to propagate in both directoins:
for normal aliases we propagate from first defined alias to
all aliases defined based on it. For weakrefs we propagate in
}
symbol_alias_set_destroy (defined);
- output_zero (ob);
+ output_record_start (ob, LTO_null);
produce_asm (ob, NULL);
destroy_output_block (ob);
}
-/* Initialize the LTO writer. */
-
-static void
-lto_writer_init (void)
-{
- lto_streamer_init ();
-}
-
-
/* Main entry point from the pass manager. */
static void
int i, n_nodes;
lto_cgraph_encoder_t encoder = lto_get_out_decl_state ()->cgraph_node_encoder;
- lto_writer_init ();
+ /* Initialize the streamer. */
+ lto_streamer_init ();
n_nodes = lto_cgraph_encoder_size (encoder);
/* Process only the functions with bodies. */
for (i = 0; i < n_nodes; i++)
{
node = lto_cgraph_encoder_deref (encoder, i);
- if (lto_cgraph_encoder_encode_body_p (encoder, node))
+ if (lto_cgraph_encoder_encode_body_p (encoder, node)
+ && !node->alias
+ && !node->thunk.thunk_p)
{
#ifdef ENABLE_CHECKING
gcc_assert (!bitmap_bit_p (output, DECL_UID (node->decl)));
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
+ 0 /* todo_flags_finish */
},
NULL, /* generate_summary */
lto_output, /* write_summary */
struct lto_tree_ref_encoder *encoder)
{
tree t;
- int32_t index;
- const int32_t size = lto_tree_ref_encoder_size (encoder);
+ uint32_t index;
+ const uint32_t size = lto_tree_ref_encoder_size (encoder);
/* Write size as 32-bit unsigned. */
lto_output_data_stream (ref_stream, &size, sizeof (int32_t));
for (index = 0; index < size; index++)
{
- int32_t slot_num;
+ uint32_t slot_num;
t = lto_tree_ref_encoder_get_tree (encoder, index);
lto_streamer_cache_lookup (ob->writer_cache, t, &slot_num);
- gcc_assert (slot_num >= 0);
+ gcc_assert (slot_num != (unsigned)-1);
lto_output_data_stream (ref_stream, &slot_num, sizeof slot_num);
}
}
struct lto_out_decl_state *state)
{
unsigned i;
- int32_t ref;
+ uint32_t ref;
tree decl;
/* Write reference to FUNCTION_DECL. If there is not function,
write reference to void_type_node. */
decl = (state->fn_decl) ? state->fn_decl : void_type_node;
lto_streamer_cache_lookup (ob->writer_cache, decl, &ref);
- gcc_assert (ref >= 0);
- lto_output_data_stream (out_stream, &ref, sizeof (int32_t));
+ gcc_assert (ref != (unsigned)-1);
+ lto_output_data_stream (out_stream, &ref, sizeof (uint32_t));
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
write_global_references (ob, out_stream, &state->streams[i]);
const char *name;
enum gcc_plugin_symbol_kind kind;
enum gcc_plugin_symbol_visibility visibility;
- int slot_num;
+ unsigned slot_num;
uint64_t size;
const char *comdat;
unsigned char c;
pointer_set_insert (seen, name);
lto_streamer_cache_lookup (cache, t, &slot_num);
- gcc_assert (slot_num >= 0);
+ gcc_assert (slot_num != (unsigned)-1);
if (DECL_EXTERNAL (t))
{
struct lto_streamer_cache_d *cache = ob->writer_cache;
char *section_name = lto_get_section_name (LTO_section_symtab, NULL, NULL);
struct pointer_set_t *seen;
- struct cgraph_node *node, *alias;
- struct varpool_node *vnode, *valias;
+ struct cgraph_node *node;
+ struct varpool_node *vnode;
struct lto_output_stream stream;
lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
lto_cgraph_encoder_t encoder = ob->decl_state->cgraph_node_encoder;
memset (&stream, 0, sizeof (stream));
/* Write all functions.
- First write all defined functions and the write all used functions.
+ First write all defined functions and then write all used functions.
This is done so only to handle duplicated symbols in cgraph. */
for (i = 0; i < lto_cgraph_encoder_size (encoder); i++)
{
if (DECL_COMDAT (node->decl)
&& cgraph_comdat_can_be_unshared_p (node))
continue;
- if (node->alias || node->global.inlined_to)
+ if ((node->alias && !node->thunk.alias) || node->global.inlined_to)
continue;
write_symbol (cache, &stream, node->decl, seen, false);
- for (alias = node->same_body; alias; alias = alias->next)
- write_symbol (cache, &stream, alias->decl, seen, true);
}
for (i = 0; i < lto_cgraph_encoder_size (encoder); i++)
{
if (DECL_COMDAT (node->decl)
&& cgraph_comdat_can_be_unshared_p (node))
continue;
- if (node->alias || node->global.inlined_to)
+ if ((node->alias && !node->thunk.alias) || node->global.inlined_to)
continue;
write_symbol (cache, &stream, node->decl, seen, false);
- for (alias = node->same_body; alias; alias = alias->next)
- write_symbol (cache, &stream, alias->decl, seen, true);
}
/* Write all variables. */
&& vnode->finalized
&& DECL_VIRTUAL_P (vnode->decl))
continue;
- if (vnode->alias)
+ if (vnode->alias && !vnode->alias_of)
continue;
write_symbol (cache, &stream, vnode->decl, seen, false);
- for (valias = vnode->extra_name; valias; valias = valias->next)
- write_symbol (cache, &stream, valias->decl, seen, true);
}
for (i = 0; i < lto_varpool_encoder_size (varpool_encoder); i++)
{
&& vnode->finalized
&& DECL_VIRTUAL_P (vnode->decl))
continue;
- if (vnode->alias)
+ if (vnode->alias && !vnode->alias_of)
continue;
write_symbol (cache, &stream, vnode->decl, seen, false);
- for (valias = vnode->extra_name; valias; valias = valias->next)
- write_symbol (cache, &stream, valias->decl, seen, true);
}
/* Write all aliases. */