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