/* Functions for writing LTO sections.
- Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2009-2020 Free Software Foundation, Inc.
Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "rtl.h"
#include "tree.h"
-#include "expr.h"
-#include "params.h"
-#include "input.h"
-#include "hashtab.h"
-#include "basic-block.h"
-#include "tree-flow.h"
+#include "gimple.h"
#include "cgraph.h"
-#include "function.h"
-#include "ggc.h"
-#include "except.h"
-#include "vec.h"
-#include "pointer-set.h"
-#include "bitmap.h"
-#include "langhooks.h"
#include "data-streamer.h"
-#include "lto-streamer.h"
+#include "langhooks.h"
#include "lto-compress.h"
+#include "print-tree.h"
-static VEC(lto_out_decl_state_ptr, heap) *decl_state_stack;
+static vec<lto_out_decl_state_ptr> decl_state_stack;
/* List of out decl states used by functions. We use this to
generate the decl directory later. */
-VEC(lto_out_decl_state_ptr, heap) *lto_function_decl_states;
-/* Returns a hash code for P. */
-
-hashval_t
-lto_hash_decl_slot_node (const void *p)
-{
- const struct lto_decl_slot *ds = (const struct lto_decl_slot *) p;
-
- /*
- return (hashval_t) DECL_UID (ds->t);
- */
- return (hashval_t) TREE_HASH (ds->t);
-}
-
-
-/* Returns nonzero if P1 and P2 are equal. */
-
-int
-lto_eq_decl_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 DECL_UID (ds1->t) == DECL_UID (ds2->t);
- */
- return ds1->t == ds2->t;
-}
-
-
-/* Returns a hash code for P. */
-
-hashval_t
-lto_hash_type_slot_node (const void *p)
-{
- const struct lto_decl_slot *ds = (const struct lto_decl_slot *) p;
- return (hashval_t) TYPE_UID (ds->t);
-}
-
+vec<lto_out_decl_state_ptr> lto_function_decl_states;
-/* Returns nonzero if P1 and P2 are equal. */
-
-int
-lto_eq_type_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 TYPE_UID (ds1->t) == TYPE_UID (ds2->t);
-}
/*****************************************************************************
Output routines shared by all of the serialization passes.
{
lang_hooks.lto.begin_section (name);
- /* FIXME lto: for now, suppress compression if the lang_hook that appends
- data is anything other than assembler output. The effect here is that
- we get compression of IL only in non-ltrans object files. */
+ if (streamer_dump_file)
+ {
+ if (flag_dump_unnumbered || flag_dump_noaddr)
+ fprintf (streamer_dump_file, "Creating %ssection\n",
+ compress ? "compressed " : "");
+ else
+ fprintf (streamer_dump_file, "Creating %ssection %s\n",
+ compress ? "compressed " : "", name);
+ }
gcc_assert (compression_stream == NULL);
if (compress)
compression_stream = lto_start_compression (lto_append_data, NULL);
lang_hooks.lto.end_section ();
}
+/* Write SIZE bytes starting at DATA to the assembler. */
+
+void
+lto_write_data (const void *data, unsigned int size)
+{
+ if (compression_stream)
+ lto_compress_block (compression_stream, (const char *)data, size);
+ else
+ lang_hooks.lto.append_data ((const char *)data, size, NULL);
+}
+
+/* Write SIZE bytes starting at DATA to the assembler. */
+
+void
+lto_write_raw_data (const void *data, unsigned int size)
+{
+ lang_hooks.lto.append_data ((const char *)data, size, NULL);
+}
/* Write all of the chars in OBS to the assembler. Recycle the blocks
in obs as this is being done. */
if (!next_block)
num_chars -= obs->left_in_block;
- /* FIXME lto: WPA mode uses an ELF function as a lang_hook to append
- output data. This hook is not happy with the way that compression
- blocks up output differently to the way it's blocked here. So for
- now, we don't compress WPA output. */
if (compression_stream)
- {
- lto_compress_block (compression_stream, base, num_chars);
- lang_hooks.lto.append_data (NULL, 0, block);
- }
+ lto_compress_block (compression_stream, base, num_chars);
else
lang_hooks.lto.append_data (base, num_chars, block);
+ free (block);
block_size *= 2;
}
}
-/* Adds a new block to output stream OBS. */
-
-void
-lto_append_block (struct lto_output_stream *obs)
-{
- struct lto_char_ptr_base *new_block;
-
- gcc_assert (obs->left_in_block == 0);
-
- if (obs->first_block == NULL)
- {
- /* This is the first time the stream has been written
- into. */
- obs->block_size = 1024;
- new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
- obs->first_block = new_block;
- }
- else
- {
- struct lto_char_ptr_base *tptr;
- /* Get a new block that is twice as big as the last block
- and link it into the list. */
- obs->block_size *= 2;
- new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
- /* The first bytes of the block are reserved as a pointer to
- the next block. Set the chain of the full block to the
- pointer to the new block. */
- tptr = obs->current_block;
- tptr->ptr = (char *) new_block;
- }
-
- /* Set the place for the next char at the first position after the
- chain to the next block. */
- obs->current_pointer
- = ((char *) new_block) + sizeof (struct lto_char_ptr_base);
- obs->current_block = new_block;
- /* Null out the newly allocated block's pointer to the next block. */
- new_block->ptr = NULL;
- obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
-}
-
-
-/* Write raw DATA of length LEN to the output block OB. */
-
-void
-lto_output_data_stream (struct lto_output_stream *obs, const void *data,
- size_t len)
-{
- while (len)
- {
- size_t copy;
-
- /* No space left. */
- if (obs->left_in_block == 0)
- lto_append_block (obs);
-
- /* Determine how many bytes to copy in this loop. */
- if (len <= obs->left_in_block)
- copy = len;
- else
- copy = obs->left_in_block;
-
- /* Copy the data and do bookkeeping. */
- memcpy (obs->current_pointer, data, copy);
- obs->current_pointer += copy;
- obs->total_size += copy;
- obs->left_in_block -= copy;
- data = (const char *) data + copy;
- len -= copy;
- }
-}
-
-
/* Lookup NAME in ENCODER. If NAME is not found, create a new entry in
ENCODER for NAME with the next available index of ENCODER, then
print the index to OBS. True is returned if NAME was added to
struct lto_tree_ref_encoder *encoder,
tree name, unsigned int *this_index)
{
- void **slot;
- struct lto_decl_slot d_slot;
- int index;
bool new_entry_p = FALSE;
+ bool existed_p;
- d_slot.t = name;
- slot = htab_find_slot (encoder->tree_hash_table, &d_slot, INSERT);
- if (*slot == NULL)
+ unsigned int &index
+ = encoder->tree_hash_table->get_or_insert (name, &existed_p);
+ if (!existed_p)
{
- struct lto_decl_slot *new_slot
- = (struct lto_decl_slot *) xmalloc (sizeof (struct lto_decl_slot));
- index = encoder->next_index++;
-
- new_slot->t = name;
- new_slot->slot_num = index;
- *slot = new_slot;
- VEC_safe_push (tree, heap, encoder->trees, name);
+ index = encoder->trees.length ();
+ if (streamer_dump_file)
+ {
+ print_node_brief (streamer_dump_file, " Encoding indexable ",
+ name, 4);
+ fprintf (streamer_dump_file, " as %i \n", index);
+ }
+ encoder->trees.safe_push (name);
new_entry_p = TRUE;
}
- else
- {
- struct lto_decl_slot *old_slot = (struct lto_decl_slot *)*slot;
- index = old_slot->slot_num;
- }
if (obs)
streamer_write_uhwi_stream (obs, index);
{
char *section_name;
struct lto_simple_header header;
- struct lto_output_stream *header_stream;
- section_name = lto_get_section_name (ob->section_type, NULL, NULL);
+ section_name = lto_get_section_name (ob->section_type, NULL, 0, NULL);
lto_begin_section (section_name, !flag_wpa);
free (section_name);
/* Write the header which says how to decode the pieces of the
t. */
memset (&header, 0, sizeof (struct lto_simple_header));
- header.lto_header.major_version = LTO_major_version;
- header.lto_header.minor_version = LTO_minor_version;
-
- header.compressed_size = 0;
-
header.main_size = ob->main_stream->total_size;
-
- header_stream = XCNEW (struct lto_output_stream);
- lto_output_data_stream (header_stream, &header, sizeof header);
- lto_write_stream (header_stream);
- free (header_stream);
+ lto_write_data (&header, sizeof header);
lto_write_stream (ob->main_stream);
{
struct lto_out_decl_state *state = XCNEW (struct lto_out_decl_state);
int i;
- htab_hash hash_fn;
- htab_eq eq_fn;
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
- {
- if (i == LTO_DECL_STREAM_TYPE)
- {
- hash_fn = lto_hash_type_slot_node;
- eq_fn = lto_eq_type_slot_node;
- }
- else
- {
- hash_fn = lto_hash_decl_slot_node;
- eq_fn = lto_eq_decl_slot_node;
- }
- lto_init_tree_ref_encoder (&state->streams[i], hash_fn, eq_fn);
- }
+ lto_init_tree_ref_encoder (&state->streams[i]);
+
+ /* At WPA time we do not compress sections by default. */
+ state->compressed = !flag_wpa;
return state;
}
struct lto_out_decl_state *
lto_get_out_decl_state (void)
{
- return VEC_last (lto_out_decl_state_ptr, decl_state_stack);
+ return decl_state_stack.last ();
}
/* Push STATE to top of out decl stack. */
void
lto_push_out_decl_state (struct lto_out_decl_state *state)
{
- VEC_safe_push (lto_out_decl_state_ptr, heap, decl_state_stack, state);
+ decl_state_stack.safe_push (state);
}
/* Pop the currently used out-decl state from top of stack. */
struct lto_out_decl_state *
lto_pop_out_decl_state (void)
{
- return VEC_pop (lto_out_decl_state_ptr, decl_state_stack);
+ return decl_state_stack.pop ();
}
/* Record STATE after it has been used in serializing the body of
for (i = 0; i < LTO_N_DECL_STREAMS; i++)
if (state->streams[i].tree_hash_table)
{
- htab_delete (state->streams[i].tree_hash_table);
+ delete state->streams[i].tree_hash_table;
state->streams[i].tree_hash_table = NULL;
}
state->fn_decl = fn_decl;
- VEC_safe_push (lto_out_decl_state_ptr, heap, lto_function_decl_states,
- state);
+ lto_function_decl_states.safe_push (state);
}