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