1/* LTO IL compression streams. 2 3 Copyright (C) 2009-2015 Free Software Foundation, Inc. 4 Contributed by Simon Baldwin <simonb@google.com> 5 6This file is part of GCC. 7 8GCC is free software; you can redistribute it and/or modify it 9under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 3, or (at your option) 11any later version. 12 13GCC is distributed in the hope that it will be useful, but WITHOUT 14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16License for more details. 17 18You should have received a copy of the GNU General Public License 19along with GCC; see the file COPYING3. If not see 20<http://www.gnu.org/licenses/>. */ 21 22#include "config.h" 23#include "system.h" 24/* zlib.h includes other system headers. Those headers may test feature 25 test macros. config.h may define feature test macros. For this reason, 26 zlib.h needs to be included after, rather than before, config.h and 27 system.h. */ 28#include <zlib.h> 29#include "coretypes.h" 30#include "hash-set.h" 31#include "machmode.h" 32#include "vec.h" 33#include "double-int.h" 34#include "input.h" 35#include "alias.h" 36#include "symtab.h" 37#include "options.h" 38#include "wide-int.h" 39#include "inchash.h" 40#include "tree.h" 41#include "fold-const.h" 42#include "predict.h" 43#include "tm.h" 44#include "hard-reg-set.h" 45#include "input.h" 46#include "function.h" 47#include "basic-block.h" 48#include "tree-ssa-alias.h" 49#include "internal-fn.h" 50#include "gimple-expr.h" 51#include "is-a.h" 52#include "gimple.h" 53#include "diagnostic-core.h" 54#include "langhooks.h" 55#include "hash-map.h" 56#include "plugin-api.h" 57#include "ipa-ref.h" 58#include "cgraph.h" 59#include "lto-streamer.h" 60#include "lto-compress.h" 61 62/* Compression stream structure, holds the flush callback and opaque token, 63 the buffered data, and a note of whether compressing or uncompressing. */ 64 65struct lto_compression_stream 66{ 67 void (*callback) (const char *, unsigned, void *); 68 void *opaque; 69 char *buffer; 70 size_t bytes; 71 size_t allocation; 72 bool is_compression; 73}; 74 75/* Overall compression constants for zlib. */ 76 77static const size_t Z_BUFFER_LENGTH = 4096; 78static const size_t MIN_STREAM_ALLOCATION = 1024; 79 80/* For zlib, allocate SIZE count of ITEMS and return the address, OPAQUE 81 is unused. */ 82 83static void * 84lto_zalloc (void *opaque, unsigned items, unsigned size) 85{ 86 gcc_assert (opaque == Z_NULL); 87 return xmalloc (items * size); 88} 89 90/* For zlib, free memory at ADDRESS, OPAQUE is unused. */ 91 92static void 93lto_zfree (void *opaque, void *address) 94{ 95 gcc_assert (opaque == Z_NULL); 96 free (address); 97} 98 99/* Return a zlib compression level that zlib will not reject. Normalizes 100 the compression level from the command line flag, clamping non-default 101 values to the appropriate end of their valid range. */ 102 103static int 104lto_normalized_zlib_level (void) 105{ 106 int level = flag_lto_compression_level; 107 108 if (level != Z_DEFAULT_COMPRESSION) 109 { 110 if (level < Z_NO_COMPRESSION) 111 level = Z_NO_COMPRESSION; 112 else if (level > Z_BEST_COMPRESSION) 113 level = Z_BEST_COMPRESSION; 114 } 115 116 return level; 117} 118 119/* Create a new compression stream, with CALLBACK flush function passed 120 OPAQUE token, IS_COMPRESSION indicates if compressing or uncompressing. */ 121 122static struct lto_compression_stream * 123lto_new_compression_stream (void (*callback) (const char *, unsigned, void *), 124 void *opaque, bool is_compression) 125{ 126 struct lto_compression_stream *stream 127 = (struct lto_compression_stream *) xmalloc (sizeof (*stream)); 128 129 memset (stream, 0, sizeof (*stream)); 130 stream->callback = callback; 131 stream->opaque = opaque; 132 stream->is_compression = is_compression; 133 134 return stream; 135} 136 137/* Append NUM_CHARS from address BASE to STREAM. */ 138 139static void 140lto_append_to_compression_stream (struct lto_compression_stream *stream, 141 const char *base, size_t num_chars) 142{ 143 size_t required = stream->bytes + num_chars; 144 145 if (stream->allocation < required) 146 { 147 if (stream->allocation == 0) 148 stream->allocation = MIN_STREAM_ALLOCATION; 149 while (stream->allocation < required) 150 stream->allocation *= 2; 151 152 stream->buffer = (char *) xrealloc (stream->buffer, stream->allocation); 153 } 154 155 memcpy (stream->buffer + stream->bytes, base, num_chars); 156 stream->bytes += num_chars; 157} 158 159/* Free the buffer and memory associated with STREAM. */ 160 161static void 162lto_destroy_compression_stream (struct lto_compression_stream *stream) 163{ 164 free (stream->buffer); 165 free (stream); 166} 167 168/* Return a new compression stream, with CALLBACK flush function passed 169 OPAQUE token. */ 170 171struct lto_compression_stream * 172lto_start_compression (void (*callback) (const char *, unsigned, void *), 173 void *opaque) 174{ 175 return lto_new_compression_stream (callback, opaque, true); 176} 177 178/* Append NUM_CHARS from address BASE to STREAM. */ 179 180void 181lto_compress_block (struct lto_compression_stream *stream, 182 const char *base, size_t num_chars) 183{ 184 gcc_assert (stream->is_compression); 185 186 lto_append_to_compression_stream (stream, base, num_chars); 187 lto_stats.num_output_il_bytes += num_chars; 188} 189 190/* Finalize STREAM compression, and free stream allocations. */ 191 192void 193lto_end_compression (struct lto_compression_stream *stream) 194{ 195 unsigned char *cursor = (unsigned char *) stream->buffer; 196 size_t remaining = stream->bytes; 197 const size_t outbuf_length = Z_BUFFER_LENGTH; 198 unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length); 199 z_stream out_stream; 200 size_t compressed_bytes = 0; 201 int status; 202 203 gcc_assert (stream->is_compression); 204 205 out_stream.next_out = outbuf; 206 out_stream.avail_out = outbuf_length; 207 out_stream.next_in = cursor; 208 out_stream.avail_in = remaining; 209 out_stream.zalloc = lto_zalloc; 210 out_stream.zfree = lto_zfree; 211 out_stream.opaque = Z_NULL; 212 213 status = deflateInit (&out_stream, lto_normalized_zlib_level ()); 214 if (status != Z_OK) 215 internal_error ("compressed stream: %s", zError (status)); 216 217 do 218 { 219 size_t in_bytes, out_bytes; 220 221 status = deflate (&out_stream, Z_FINISH); 222 if (status != Z_OK && status != Z_STREAM_END) 223 internal_error ("compressed stream: %s", zError (status)); 224 225 in_bytes = remaining - out_stream.avail_in; 226 out_bytes = outbuf_length - out_stream.avail_out; 227 228 stream->callback ((const char *) outbuf, out_bytes, stream->opaque); 229 lto_stats.num_compressed_il_bytes += out_bytes; 230 compressed_bytes += out_bytes; 231 232 cursor += in_bytes; 233 remaining -= in_bytes; 234 235 out_stream.next_out = outbuf; 236 out_stream.avail_out = outbuf_length; 237 out_stream.next_in = cursor; 238 out_stream.avail_in = remaining; 239 } 240 while (status != Z_STREAM_END); 241 242 status = deflateEnd (&out_stream); 243 if (status != Z_OK) 244 internal_error ("compressed stream: %s", zError (status)); 245 246 lto_destroy_compression_stream (stream); 247 free (outbuf); 248} 249 250/* Return a new uncompression stream, with CALLBACK flush function passed 251 OPAQUE token. */ 252 253struct lto_compression_stream * 254lto_start_uncompression (void (*callback) (const char *, unsigned, void *), 255 void *opaque) 256{ 257 return lto_new_compression_stream (callback, opaque, false); 258} 259 260/* Append NUM_CHARS from address BASE to STREAM. */ 261 262void 263lto_uncompress_block (struct lto_compression_stream *stream, 264 const char *base, size_t num_chars) 265{ 266 gcc_assert (!stream->is_compression); 267 268 lto_append_to_compression_stream (stream, base, num_chars); 269 lto_stats.num_input_il_bytes += num_chars; 270} 271 272/* Finalize STREAM uncompression, and free stream allocations. 273 274 Because of the way LTO IL streams are compressed, there may be several 275 concatenated compressed segments in the accumulated data, so for this 276 function we iterate decompressions until no data remains. */ 277 278void 279lto_end_uncompression (struct lto_compression_stream *stream) 280{ 281 unsigned char *cursor = (unsigned char *) stream->buffer; 282 size_t remaining = stream->bytes; 283 const size_t outbuf_length = Z_BUFFER_LENGTH; 284 unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length); 285 size_t uncompressed_bytes = 0; 286 287 gcc_assert (!stream->is_compression); 288 289 while (remaining > 0) 290 { 291 z_stream in_stream; 292 size_t out_bytes; 293 int status; 294 295 in_stream.next_out = outbuf; 296 in_stream.avail_out = outbuf_length; 297 in_stream.next_in = cursor; 298 in_stream.avail_in = remaining; 299 in_stream.zalloc = lto_zalloc; 300 in_stream.zfree = lto_zfree; 301 in_stream.opaque = Z_NULL; 302 303 status = inflateInit (&in_stream); 304 if (status != Z_OK) 305 internal_error ("compressed stream: %s", zError (status)); 306 307 do 308 { 309 size_t in_bytes; 310 311 status = inflate (&in_stream, Z_SYNC_FLUSH); 312 if (status != Z_OK && status != Z_STREAM_END) 313 internal_error ("compressed stream: %s", zError (status)); 314 315 in_bytes = remaining - in_stream.avail_in; 316 out_bytes = outbuf_length - in_stream.avail_out; 317 318 stream->callback ((const char *) outbuf, out_bytes, stream->opaque); 319 lto_stats.num_uncompressed_il_bytes += out_bytes; 320 uncompressed_bytes += out_bytes; 321 322 cursor += in_bytes; 323 remaining -= in_bytes; 324 325 in_stream.next_out = outbuf; 326 in_stream.avail_out = outbuf_length; 327 in_stream.next_in = cursor; 328 in_stream.avail_in = remaining; 329 } 330 while (!(status == Z_STREAM_END && out_bytes == 0)); 331 332 status = inflateEnd (&in_stream); 333 if (status != Z_OK) 334 internal_error ("compressed stream: %s", zError (status)); 335 } 336 337 lto_destroy_compression_stream (stream); 338 free (outbuf); 339} 340