xref: /dflybsd-src/contrib/gcc-8.0/gcc/lto-compress.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
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