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