]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/lto-compress.c
2015-06-17 Andrew MacLeod <amacleod@redhat.com>
[thirdparty/gcc.git] / gcc / lto-compress.c
CommitLineData
7bfefa9d 1/* LTO IL compression streams.
2
d353bf18 3 Copyright (C) 2009-2015 Free Software Foundation, Inc.
7bfefa9d 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"
b20a8bb4 30#include "alias.h"
31#include "symtab.h"
32#include "options.h"
b20a8bb4 33#include "tree.h"
34#include "fold-const.h"
35#include "predict.h"
94ea8568 36#include "tm.h"
37#include "hard-reg-set.h"
94ea8568 38#include "function.h"
bc61cadb 39#include "basic-block.h"
40#include "tree-ssa-alias.h"
41#include "internal-fn.h"
42#include "gimple-expr.h"
b23fb4cb 43#include "gimple.h"
852f689e 44#include "diagnostic-core.h"
7bfefa9d 45#include "langhooks.h"
1140c305 46#include "plugin-api.h"
47#include "ipa-ref.h"
48#include "cgraph.h"
7bfefa9d 49#include "lto-streamer.h"
50#include "lto-compress.h"
51
52/* Compression stream structure, holds the flush callback and opaque token,
53 the buffered data, and a note of whether compressing or uncompressing. */
54
55struct lto_compression_stream
56{
57 void (*callback) (const char *, unsigned, void *);
58 void *opaque;
59 char *buffer;
60 size_t bytes;
61 size_t allocation;
62 bool is_compression;
63};
64
65/* Overall compression constants for zlib. */
66
67static const size_t Z_BUFFER_LENGTH = 4096;
68static const size_t MIN_STREAM_ALLOCATION = 1024;
69
70/* For zlib, allocate SIZE count of ITEMS and return the address, OPAQUE
71 is unused. */
72
73static void *
74lto_zalloc (void *opaque, unsigned items, unsigned size)
75{
76 gcc_assert (opaque == Z_NULL);
77 return xmalloc (items * size);
78}
79
80/* For zlib, free memory at ADDRESS, OPAQUE is unused. */
81
82static void
83lto_zfree (void *opaque, void *address)
84{
85 gcc_assert (opaque == Z_NULL);
86 free (address);
87}
88
89/* Return a zlib compression level that zlib will not reject. Normalizes
90 the compression level from the command line flag, clamping non-default
91 values to the appropriate end of their valid range. */
92
93static int
94lto_normalized_zlib_level (void)
95{
96 int level = flag_lto_compression_level;
97
98 if (level != Z_DEFAULT_COMPRESSION)
99 {
100 if (level < Z_NO_COMPRESSION)
101 level = Z_NO_COMPRESSION;
102 else if (level > Z_BEST_COMPRESSION)
103 level = Z_BEST_COMPRESSION;
104 }
105
106 return level;
107}
108
109/* Create a new compression stream, with CALLBACK flush function passed
110 OPAQUE token, IS_COMPRESSION indicates if compressing or uncompressing. */
111
112static struct lto_compression_stream *
113lto_new_compression_stream (void (*callback) (const char *, unsigned, void *),
114 void *opaque, bool is_compression)
115{
116 struct lto_compression_stream *stream
117 = (struct lto_compression_stream *) xmalloc (sizeof (*stream));
118
119 memset (stream, 0, sizeof (*stream));
120 stream->callback = callback;
121 stream->opaque = opaque;
122 stream->is_compression = is_compression;
123
124 return stream;
125}
126
127/* Append NUM_CHARS from address BASE to STREAM. */
128
129static void
130lto_append_to_compression_stream (struct lto_compression_stream *stream,
131 const char *base, size_t num_chars)
132{
133 size_t required = stream->bytes + num_chars;
134
135 if (stream->allocation < required)
136 {
137 if (stream->allocation == 0)
138 stream->allocation = MIN_STREAM_ALLOCATION;
139 while (stream->allocation < required)
140 stream->allocation *= 2;
141
142 stream->buffer = (char *) xrealloc (stream->buffer, stream->allocation);
143 }
144
145 memcpy (stream->buffer + stream->bytes, base, num_chars);
146 stream->bytes += num_chars;
147}
148
149/* Free the buffer and memory associated with STREAM. */
150
151static void
152lto_destroy_compression_stream (struct lto_compression_stream *stream)
153{
154 free (stream->buffer);
155 free (stream);
156}
157
158/* Return a new compression stream, with CALLBACK flush function passed
159 OPAQUE token. */
160
161struct lto_compression_stream *
162lto_start_compression (void (*callback) (const char *, unsigned, void *),
163 void *opaque)
164{
165 return lto_new_compression_stream (callback, opaque, true);
166}
167
168/* Append NUM_CHARS from address BASE to STREAM. */
169
170void
171lto_compress_block (struct lto_compression_stream *stream,
172 const char *base, size_t num_chars)
173{
174 gcc_assert (stream->is_compression);
175
176 lto_append_to_compression_stream (stream, base, num_chars);
177 lto_stats.num_output_il_bytes += num_chars;
178}
179
180/* Finalize STREAM compression, and free stream allocations. */
181
182void
183lto_end_compression (struct lto_compression_stream *stream)
184{
185 unsigned char *cursor = (unsigned char *) stream->buffer;
186 size_t remaining = stream->bytes;
187 const size_t outbuf_length = Z_BUFFER_LENGTH;
188 unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
189 z_stream out_stream;
190 size_t compressed_bytes = 0;
191 int status;
192
193 gcc_assert (stream->is_compression);
194
195 out_stream.next_out = outbuf;
196 out_stream.avail_out = outbuf_length;
197 out_stream.next_in = cursor;
198 out_stream.avail_in = remaining;
199 out_stream.zalloc = lto_zalloc;
200 out_stream.zfree = lto_zfree;
201 out_stream.opaque = Z_NULL;
202
203 status = deflateInit (&out_stream, lto_normalized_zlib_level ());
204 if (status != Z_OK)
205 internal_error ("compressed stream: %s", zError (status));
206
207 do
208 {
209 size_t in_bytes, out_bytes;
210
211 status = deflate (&out_stream, Z_FINISH);
212 if (status != Z_OK && status != Z_STREAM_END)
213 internal_error ("compressed stream: %s", zError (status));
214
215 in_bytes = remaining - out_stream.avail_in;
216 out_bytes = outbuf_length - out_stream.avail_out;
217
218 stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
219 lto_stats.num_compressed_il_bytes += out_bytes;
220 compressed_bytes += out_bytes;
221
222 cursor += in_bytes;
223 remaining -= in_bytes;
224
225 out_stream.next_out = outbuf;
226 out_stream.avail_out = outbuf_length;
227 out_stream.next_in = cursor;
228 out_stream.avail_in = remaining;
229 }
230 while (status != Z_STREAM_END);
231
232 status = deflateEnd (&out_stream);
233 if (status != Z_OK)
234 internal_error ("compressed stream: %s", zError (status));
235
236 lto_destroy_compression_stream (stream);
237 free (outbuf);
238}
239
240/* Return a new uncompression stream, with CALLBACK flush function passed
241 OPAQUE token. */
242
243struct lto_compression_stream *
244lto_start_uncompression (void (*callback) (const char *, unsigned, void *),
245 void *opaque)
246{
247 return lto_new_compression_stream (callback, opaque, false);
248}
249
250/* Append NUM_CHARS from address BASE to STREAM. */
251
252void
253lto_uncompress_block (struct lto_compression_stream *stream,
254 const char *base, size_t num_chars)
255{
256 gcc_assert (!stream->is_compression);
257
258 lto_append_to_compression_stream (stream, base, num_chars);
259 lto_stats.num_input_il_bytes += num_chars;
260}
261
262/* Finalize STREAM uncompression, and free stream allocations.
48e1416a 263
7bfefa9d 264 Because of the way LTO IL streams are compressed, there may be several
265 concatenated compressed segments in the accumulated data, so for this
266 function we iterate decompressions until no data remains. */
267
268void
269lto_end_uncompression (struct lto_compression_stream *stream)
270{
271 unsigned char *cursor = (unsigned char *) stream->buffer;
272 size_t remaining = stream->bytes;
273 const size_t outbuf_length = Z_BUFFER_LENGTH;
274 unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
275 size_t uncompressed_bytes = 0;
276
277 gcc_assert (!stream->is_compression);
278
279 while (remaining > 0)
280 {
281 z_stream in_stream;
282 size_t out_bytes;
283 int status;
284
285 in_stream.next_out = outbuf;
286 in_stream.avail_out = outbuf_length;
287 in_stream.next_in = cursor;
288 in_stream.avail_in = remaining;
289 in_stream.zalloc = lto_zalloc;
290 in_stream.zfree = lto_zfree;
291 in_stream.opaque = Z_NULL;
292
293 status = inflateInit (&in_stream);
294 if (status != Z_OK)
295 internal_error ("compressed stream: %s", zError (status));
296
297 do
298 {
299 size_t in_bytes;
300
301 status = inflate (&in_stream, Z_SYNC_FLUSH);
302 if (status != Z_OK && status != Z_STREAM_END)
303 internal_error ("compressed stream: %s", zError (status));
304
305 in_bytes = remaining - in_stream.avail_in;
306 out_bytes = outbuf_length - in_stream.avail_out;
307
308 stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
309 lto_stats.num_uncompressed_il_bytes += out_bytes;
310 uncompressed_bytes += out_bytes;
311
312 cursor += in_bytes;
313 remaining -= in_bytes;
314
315 in_stream.next_out = outbuf;
316 in_stream.avail_out = outbuf_length;
317 in_stream.next_in = cursor;
318 in_stream.avail_in = remaining;
319 }
320 while (!(status == Z_STREAM_END && out_bytes == 0));
321
322 status = inflateEnd (&in_stream);
323 if (status != Z_OK)
324 internal_error ("compressed stream: %s", zError (status));
325 }
326
327 lto_destroy_compression_stream (stream);
328 free (outbuf);
329}