aboutsummaryrefslogtreecommitdiff
path: root/gcc/lto-section-out.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/lto-section-out.c')
-rw-r--r--gcc/lto-section-out.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/gcc/lto-section-out.c b/gcc/lto-section-out.c
new file mode 100644
index 00000000000..33d9e2372bd
--- /dev/null
+++ b/gcc/lto-section-out.c
@@ -0,0 +1,265 @@
+/* LTO output code.
+ Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+ Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "toplev.h"
+#include "tree.h"
+#include "expr.h"
+#include "flags.h"
+#include "params.h"
+#include "input.h"
+#include "varray.h"
+#include "hashtab.h"
+#include "langhooks.h"
+#include "basic-block.h"
+#include "tree-iterator.h"
+#include "tree-pass.h"
+#include "tree-flow.h"
+#include "cgraph.h"
+#include "function.h"
+#include "ggc.h"
+#include "diagnostic.h"
+#include "except.h"
+#include "debug.h"
+#include "vec.h"
+#include "tree-vectorizer.h"
+#include "timevar.h"
+#include "dwarf2asm.h"
+#include "dwarf2out.h"
+#include "output.h"
+#include "lto-tags.h"
+#include "lto-section-out.h"
+#include <ctype.h>
+
+/* Write all of the chars in OBS to the assembler. Recycle the blocks
+ in obs as this is being done. */
+
+void
+lto_write_stream (struct lto_output_stream *obs)
+{
+ unsigned int block_size = 1024;
+ unsigned int num_chars;
+ struct lto_char_ptr_base *block;
+ if (!obs->first_block)
+ return;
+
+ block = obs->first_block;
+ while (block)
+ {
+ const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base);
+ struct lto_char_ptr_base *old_block = block;
+ block = (struct lto_char_ptr_base *)block->ptr;
+ /* If there is a next block, then this one is full, if there is
+ not a next block, then the left_in_block field says how many
+ chars there are in this block. */
+ num_chars = block_size - sizeof (struct lto_char_ptr_base);
+ if (!block)
+ num_chars = num_chars - obs->left_in_block;
+
+ assemble_string (base, num_chars);
+ free (old_block);
+ block_size *= 2;
+ }
+}
+
+
+/* Write a character to the output block. */
+
+void
+lto_output_1_stream (struct lto_output_stream *obs, char c)
+{
+ /* No space left. */
+ if (obs->left_in_block == 0)
+ {
+ struct lto_char_ptr_base *new_block;
+
+ 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 the actual character. */
+ *obs->current_pointer = c;
+ obs->current_pointer++;
+ obs->total_size++;
+ obs->left_in_block--;
+}
+
+
+/* Output an unsigned LEB128 quantity to OBS. */
+
+void
+lto_output_uleb128_stream (struct lto_output_stream *obs, unsigned HOST_WIDE_INT work)
+{
+ LTO_DEBUG_WIDE ("U", work);
+ do
+ {
+ unsigned int byte = (work & 0x7f);
+ work >>= 7;
+ if (work != 0)
+ /* More bytes to follow. */
+ byte |= 0x80;
+
+ lto_output_1_stream (obs, byte);
+ }
+ while (work != 0);
+}
+
+/* Identical to output_uleb128_stream above except using unsigned
+ HOST_WIDEST_INT type. For efficiency on host where unsigned HOST_WIDEST_INT
+ is not native, we only use this if we know that HOST_WIDE_INT is not wide
+ enough. */
+
+void
+lto_output_widest_uint_uleb128_stream (struct lto_output_stream *obs,
+ unsigned HOST_WIDEST_INT work)
+{
+ LTO_DEBUG_WIDE ("U", work);
+ do
+ {
+ unsigned int byte = (work & 0x7f);
+ work >>= 7;
+ if (work != 0)
+ /* More bytes to follow. */
+ byte |= 0x80;
+
+ lto_output_1_stream (obs, byte);
+ }
+ while (work != 0);
+}
+
+
+/* Output a signed LEB128 quantity. */
+
+void
+lto_output_sleb128_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
+{
+ int more, byte;
+ LTO_DEBUG_WIDE ("S", work);
+ do
+ {
+ byte = (work & 0x7f);
+ /* arithmetic shift */
+ work >>= 7;
+ more = !((work == 0 && (byte & 0x40) == 0)
+ || (work == -1 && (byte & 0x40) != 0));
+ if (more)
+ byte |= 0x80;
+
+ lto_output_1_stream (obs, byte);
+ }
+ while (more);
+}
+
+
+/* Put out a integer constant. These are stored as two HOST_WIDE_INTS
+ so games may have to be played to shift the data from the high to
+ the low value. */
+
+void
+lto_output_integer_stream (struct lto_output_stream *obs, tree t)
+{
+ HOST_WIDE_INT low = TREE_INT_CST_LOW (t);
+ HOST_WIDE_INT high = TREE_INT_CST_HIGH (t);
+ int more, byte;
+
+ /* Of course if the high value is just sign bits for the signed low
+ value, we can just punt and call lto_output_sleb128 and be done with
+ it. */
+ if (((high == -1) && (low < 0))
+ || ((high == 0) && (low >= 0)))
+ {
+ lto_output_sleb128_stream (obs, low);
+ return;
+ }
+
+ LTO_DEBUG_INTEGER ("SS", high, low);
+
+ /* This is just a copy of the lto_output_sleb128 code with extra
+ operations to transfer the low 7 bits of the high value to the
+ top 7 bits of the low value, shift the high down by 7 and then do
+ a slightly more complex exit test. */
+ do
+ {
+ unsigned HOST_WIDE_INT transfer = (high & 0x7f);
+ high = ((unsigned HOST_WIDE_INT) high) >> 7;
+ transfer <<= (HOST_BITS_PER_WIDE_INT - 7);
+
+ byte = (low & 0x7f);
+
+ /* Logical shift. */
+ low = ((unsigned HOST_WIDE_INT) low) >> 7;
+ low |= transfer;
+ more = !((high == 0 && low == 0 && (byte & 0x40) == 0)
+ || (high == -1 && low == -1 && (byte & 0x40) != 0));
+ if (more)
+ byte |= 0x80;
+
+ lto_output_1_stream (obs, byte);
+ }
+ while (more);
+}
+
+#ifdef LTO_STREAM_DEBUGGING
+
+struct lto_debug_context lto_debug_context;
+
+/* The low level output routine to print a single character to the
+ debugging stream. */
+
+void
+lto_debug_out_fun (struct lto_debug_context *context, char c)
+{
+ struct lto_output_stream * stream
+ = (struct lto_output_stream *)context->current_data;
+ lto_output_1_stream (stream, c);
+}
+
+#endif