OSDN Git Service

gcc/:
[pf3gnuchains/gcc-fork.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 }