123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- /* LTO IL compression streams.
- Copyright (C) 2009-2015 Free Software Foundation, Inc.
- Contributed by Simon Baldwin <simonb@google.com>
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- GCC is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- License for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- #include "config.h"
- #include "system.h"
- /* zlib.h includes other system headers. Those headers may test feature
- test macros. config.h may define feature test macros. For this reason,
- zlib.h needs to be included after, rather than before, config.h and
- system.h. */
- #include <zlib.h>
- #include "coretypes.h"
- #include "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "options.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "fold-const.h"
- #include "predict.h"
- #include "tm.h"
- #include "hard-reg-set.h"
- #include "input.h"
- #include "function.h"
- #include "basic-block.h"
- #include "tree-ssa-alias.h"
- #include "internal-fn.h"
- #include "gimple-expr.h"
- #include "is-a.h"
- #include "gimple.h"
- #include "diagnostic-core.h"
- #include "langhooks.h"
- #include "hash-map.h"
- #include "plugin-api.h"
- #include "ipa-ref.h"
- #include "cgraph.h"
- #include "lto-streamer.h"
- #include "lto-compress.h"
- /* Compression stream structure, holds the flush callback and opaque token,
- the buffered data, and a note of whether compressing or uncompressing. */
- struct lto_compression_stream
- {
- void (*callback) (const char *, unsigned, void *);
- void *opaque;
- char *buffer;
- size_t bytes;
- size_t allocation;
- bool is_compression;
- };
- /* Overall compression constants for zlib. */
- static const size_t Z_BUFFER_LENGTH = 4096;
- static const size_t MIN_STREAM_ALLOCATION = 1024;
- /* For zlib, allocate SIZE count of ITEMS and return the address, OPAQUE
- is unused. */
- static void *
- lto_zalloc (void *opaque, unsigned items, unsigned size)
- {
- gcc_assert (opaque == Z_NULL);
- return xmalloc (items * size);
- }
- /* For zlib, free memory at ADDRESS, OPAQUE is unused. */
- static void
- lto_zfree (void *opaque, void *address)
- {
- gcc_assert (opaque == Z_NULL);
- free (address);
- }
- /* Return a zlib compression level that zlib will not reject. Normalizes
- the compression level from the command line flag, clamping non-default
- values to the appropriate end of their valid range. */
- static int
- lto_normalized_zlib_level (void)
- {
- int level = flag_lto_compression_level;
- if (level != Z_DEFAULT_COMPRESSION)
- {
- if (level < Z_NO_COMPRESSION)
- level = Z_NO_COMPRESSION;
- else if (level > Z_BEST_COMPRESSION)
- level = Z_BEST_COMPRESSION;
- }
- return level;
- }
- /* Create a new compression stream, with CALLBACK flush function passed
- OPAQUE token, IS_COMPRESSION indicates if compressing or uncompressing. */
- static struct lto_compression_stream *
- lto_new_compression_stream (void (*callback) (const char *, unsigned, void *),
- void *opaque, bool is_compression)
- {
- struct lto_compression_stream *stream
- = (struct lto_compression_stream *) xmalloc (sizeof (*stream));
- memset (stream, 0, sizeof (*stream));
- stream->callback = callback;
- stream->opaque = opaque;
- stream->is_compression = is_compression;
- return stream;
- }
- /* Append NUM_CHARS from address BASE to STREAM. */
- static void
- lto_append_to_compression_stream (struct lto_compression_stream *stream,
- const char *base, size_t num_chars)
- {
- size_t required = stream->bytes + num_chars;
- if (stream->allocation < required)
- {
- if (stream->allocation == 0)
- stream->allocation = MIN_STREAM_ALLOCATION;
- while (stream->allocation < required)
- stream->allocation *= 2;
- stream->buffer = (char *) xrealloc (stream->buffer, stream->allocation);
- }
- memcpy (stream->buffer + stream->bytes, base, num_chars);
- stream->bytes += num_chars;
- }
- /* Free the buffer and memory associated with STREAM. */
- static void
- lto_destroy_compression_stream (struct lto_compression_stream *stream)
- {
- free (stream->buffer);
- free (stream);
- }
- /* Return a new compression stream, with CALLBACK flush function passed
- OPAQUE token. */
- struct lto_compression_stream *
- lto_start_compression (void (*callback) (const char *, unsigned, void *),
- void *opaque)
- {
- return lto_new_compression_stream (callback, opaque, true);
- }
- /* Append NUM_CHARS from address BASE to STREAM. */
- void
- lto_compress_block (struct lto_compression_stream *stream,
- const char *base, size_t num_chars)
- {
- gcc_assert (stream->is_compression);
- lto_append_to_compression_stream (stream, base, num_chars);
- lto_stats.num_output_il_bytes += num_chars;
- }
- /* Finalize STREAM compression, and free stream allocations. */
- void
- lto_end_compression (struct lto_compression_stream *stream)
- {
- unsigned char *cursor = (unsigned char *) stream->buffer;
- size_t remaining = stream->bytes;
- const size_t outbuf_length = Z_BUFFER_LENGTH;
- unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
- z_stream out_stream;
- size_t compressed_bytes = 0;
- int status;
- gcc_assert (stream->is_compression);
- out_stream.next_out = outbuf;
- out_stream.avail_out = outbuf_length;
- out_stream.next_in = cursor;
- out_stream.avail_in = remaining;
- out_stream.zalloc = lto_zalloc;
- out_stream.zfree = lto_zfree;
- out_stream.opaque = Z_NULL;
- status = deflateInit (&out_stream, lto_normalized_zlib_level ());
- if (status != Z_OK)
- internal_error ("compressed stream: %s", zError (status));
- do
- {
- size_t in_bytes, out_bytes;
- status = deflate (&out_stream, Z_FINISH);
- if (status != Z_OK && status != Z_STREAM_END)
- internal_error ("compressed stream: %s", zError (status));
- in_bytes = remaining - out_stream.avail_in;
- out_bytes = outbuf_length - out_stream.avail_out;
- stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
- lto_stats.num_compressed_il_bytes += out_bytes;
- compressed_bytes += out_bytes;
- cursor += in_bytes;
- remaining -= in_bytes;
- out_stream.next_out = outbuf;
- out_stream.avail_out = outbuf_length;
- out_stream.next_in = cursor;
- out_stream.avail_in = remaining;
- }
- while (status != Z_STREAM_END);
- status = deflateEnd (&out_stream);
- if (status != Z_OK)
- internal_error ("compressed stream: %s", zError (status));
- lto_destroy_compression_stream (stream);
- free (outbuf);
- }
- /* Return a new uncompression stream, with CALLBACK flush function passed
- OPAQUE token. */
- struct lto_compression_stream *
- lto_start_uncompression (void (*callback) (const char *, unsigned, void *),
- void *opaque)
- {
- return lto_new_compression_stream (callback, opaque, false);
- }
- /* Append NUM_CHARS from address BASE to STREAM. */
- void
- lto_uncompress_block (struct lto_compression_stream *stream,
- const char *base, size_t num_chars)
- {
- gcc_assert (!stream->is_compression);
- lto_append_to_compression_stream (stream, base, num_chars);
- lto_stats.num_input_il_bytes += num_chars;
- }
- /* Finalize STREAM uncompression, and free stream allocations.
- Because of the way LTO IL streams are compressed, there may be several
- concatenated compressed segments in the accumulated data, so for this
- function we iterate decompressions until no data remains. */
- void
- lto_end_uncompression (struct lto_compression_stream *stream)
- {
- unsigned char *cursor = (unsigned char *) stream->buffer;
- size_t remaining = stream->bytes;
- const size_t outbuf_length = Z_BUFFER_LENGTH;
- unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
- size_t uncompressed_bytes = 0;
- gcc_assert (!stream->is_compression);
- while (remaining > 0)
- {
- z_stream in_stream;
- size_t out_bytes;
- int status;
- in_stream.next_out = outbuf;
- in_stream.avail_out = outbuf_length;
- in_stream.next_in = cursor;
- in_stream.avail_in = remaining;
- in_stream.zalloc = lto_zalloc;
- in_stream.zfree = lto_zfree;
- in_stream.opaque = Z_NULL;
- status = inflateInit (&in_stream);
- if (status != Z_OK)
- internal_error ("compressed stream: %s", zError (status));
- do
- {
- size_t in_bytes;
- status = inflate (&in_stream, Z_SYNC_FLUSH);
- if (status != Z_OK && status != Z_STREAM_END)
- internal_error ("compressed stream: %s", zError (status));
- in_bytes = remaining - in_stream.avail_in;
- out_bytes = outbuf_length - in_stream.avail_out;
- stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
- lto_stats.num_uncompressed_il_bytes += out_bytes;
- uncompressed_bytes += out_bytes;
- cursor += in_bytes;
- remaining -= in_bytes;
- in_stream.next_out = outbuf;
- in_stream.avail_out = outbuf_length;
- in_stream.next_in = cursor;
- in_stream.avail_in = remaining;
- }
- while (!(status == Z_STREAM_END && out_bytes == 0));
- status = inflateEnd (&in_stream);
- if (status != Z_OK)
- internal_error ("compressed stream: %s", zError (status));
- }
- lto_destroy_compression_stream (stream);
- free (outbuf);
- }
|