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