]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/lto-compress.c
Update copyright years.
[thirdparty/gcc.git] / gcc / lto-compress.c
CommitLineData
d7f09764
DN
1/* LTO IL compression streams.
2
8d9254fc 3 Copyright (C) 2009-2020 Free Software Foundation, Inc.
d7f09764
DN
4 Contributed by Simon Baldwin <simonb@google.com>
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it
9under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 3, or (at your option)
11any later version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16License for more details.
17
18You should have received a copy of the GNU General Public License
19along with GCC; see the file COPYING3. If not see
20<http://www.gnu.org/licenses/>. */
21
22#include "config.h"
23#include "system.h"
957060b5
AM
24#include "coretypes.h"
25#include "backend.h"
957060b5
AM
26#include "tree.h"
27#include "gimple.h"
28#include "cgraph.h"
29#include "lto-streamer.h"
d7f09764
DN
30/* zlib.h includes other system headers. Those headers may test feature
31 test macros. config.h may define feature test macros. For this reason,
32 zlib.h needs to be included after, rather than before, config.h and
33 system.h. */
34#include <zlib.h>
d7f09764 35#include "lto-compress.h"
ed7dc894 36#include "timevar.h"
d7f09764 37
87741e51
ML
38#ifdef HAVE_ZSTD_H
39#include <zstd.h>
40#endif
41
d7f09764
DN
42/* Compression stream structure, holds the flush callback and opaque token,
43 the buffered data, and a note of whether compressing or uncompressing. */
44
45struct lto_compression_stream
46{
47 void (*callback) (const char *, unsigned, void *);
48 void *opaque;
49 char *buffer;
50 size_t bytes;
51 size_t allocation;
52 bool is_compression;
53};
54
55/* Overall compression constants for zlib. */
56
57static const size_t Z_BUFFER_LENGTH = 4096;
58static const size_t MIN_STREAM_ALLOCATION = 1024;
59
60/* For zlib, allocate SIZE count of ITEMS and return the address, OPAQUE
61 is unused. */
62
63static void *
64lto_zalloc (void *opaque, unsigned items, unsigned size)
65{
66 gcc_assert (opaque == Z_NULL);
67 return xmalloc (items * size);
68}
69
70/* For zlib, free memory at ADDRESS, OPAQUE is unused. */
71
72static void
73lto_zfree (void *opaque, void *address)
74{
75 gcc_assert (opaque == Z_NULL);
76 free (address);
77}
78
79/* Return a zlib compression level that zlib will not reject. Normalizes
80 the compression level from the command line flag, clamping non-default
81 values to the appropriate end of their valid range. */
82
83static int
84lto_normalized_zlib_level (void)
85{
86 int level = flag_lto_compression_level;
87
88 if (level != Z_DEFAULT_COMPRESSION)
89 {
90 if (level < Z_NO_COMPRESSION)
91 level = Z_NO_COMPRESSION;
92 else if (level > Z_BEST_COMPRESSION)
93 level = Z_BEST_COMPRESSION;
94 }
95
96 return level;
97}
98
87741e51
ML
99/* Free the buffer and memory associated with STREAM. */
100
101static void
102lto_destroy_compression_stream (struct lto_compression_stream *stream)
103{
104 free (stream->buffer);
105 free (stream);
106}
107
108#ifdef HAVE_ZSTD_H
109/* Return a zstd compression level that zstd will not reject. Normalizes
110 the compression level from the command line flag, clamping non-default
111 values to the appropriate end of their valid range. */
112
113static int
114lto_normalized_zstd_level (void)
115{
116 int level = flag_lto_compression_level;
117
7a26ff04
ML
118 if (level < 0)
119 level = 0;
120 else if (level > ZSTD_maxCLevel ())
121 level = ZSTD_maxCLevel ();
87741e51
ML
122
123 return level;
124}
125
126/* Compress STREAM using ZSTD algorithm. */
127
128static void
129lto_compression_zstd (struct lto_compression_stream *stream)
130{
131 unsigned char *cursor = (unsigned char *) stream->buffer;
132 size_t size = stream->bytes;
133
134 timevar_push (TV_IPA_LTO_COMPRESS);
135 size_t const outbuf_length = ZSTD_compressBound (size);
136 char *outbuf = (char *) xmalloc (outbuf_length);
137
138 size_t const csize = ZSTD_compress (outbuf, outbuf_length, cursor, size,
139 lto_normalized_zstd_level ());
140
141 if (ZSTD_isError (csize))
142 internal_error ("compressed stream: %s", ZSTD_getErrorName (csize));
143
144 stream->callback (outbuf, csize, NULL);
145
146 lto_destroy_compression_stream (stream);
147 free (outbuf);
148 timevar_pop (TV_IPA_LTO_COMPRESS);
149}
150
151/* Uncompress STREAM using ZSTD algorithm. */
152
153static void
154lto_uncompression_zstd (struct lto_compression_stream *stream)
155{
156 unsigned char *cursor = (unsigned char *) stream->buffer;
157 size_t size = stream->bytes;
158
159 timevar_push (TV_IPA_LTO_DECOMPRESS);
160 unsigned long long const rsize = ZSTD_getFrameContentSize (cursor, size);
161 if (rsize == ZSTD_CONTENTSIZE_ERROR)
162 internal_error ("original not compressed with zstd");
163 else if (rsize == ZSTD_CONTENTSIZE_UNKNOWN)
164 internal_error ("original size unknown");
165
166 char *outbuf = (char *) xmalloc (rsize);
167 size_t const dsize = ZSTD_decompress (outbuf, rsize, cursor, size);
168
169 if (ZSTD_isError (dsize))
170 internal_error ("decompressed stream: %s", ZSTD_getErrorName (dsize));
171
172 stream->callback (outbuf, dsize, stream->opaque);
173
174 lto_destroy_compression_stream (stream);
175 free (outbuf);
176 timevar_pop (TV_IPA_LTO_DECOMPRESS);
177}
178
179#endif
180
d7f09764
DN
181/* Create a new compression stream, with CALLBACK flush function passed
182 OPAQUE token, IS_COMPRESSION indicates if compressing or uncompressing. */
183
184static struct lto_compression_stream *
185lto_new_compression_stream (void (*callback) (const char *, unsigned, void *),
186 void *opaque, bool is_compression)
187{
188 struct lto_compression_stream *stream
189 = (struct lto_compression_stream *) xmalloc (sizeof (*stream));
190
191 memset (stream, 0, sizeof (*stream));
192 stream->callback = callback;
193 stream->opaque = opaque;
194 stream->is_compression = is_compression;
195
196 return stream;
197}
198
199/* Append NUM_CHARS from address BASE to STREAM. */
200
201static void
202lto_append_to_compression_stream (struct lto_compression_stream *stream,
203 const char *base, size_t num_chars)
204{
205 size_t required = stream->bytes + num_chars;
206
207 if (stream->allocation < required)
208 {
209 if (stream->allocation == 0)
210 stream->allocation = MIN_STREAM_ALLOCATION;
211 while (stream->allocation < required)
212 stream->allocation *= 2;
213
214 stream->buffer = (char *) xrealloc (stream->buffer, stream->allocation);
215 }
216
217 memcpy (stream->buffer + stream->bytes, base, num_chars);
218 stream->bytes += num_chars;
219}
220
d7f09764
DN
221/* Return a new compression stream, with CALLBACK flush function passed
222 OPAQUE token. */
223
224struct lto_compression_stream *
225lto_start_compression (void (*callback) (const char *, unsigned, void *),
226 void *opaque)
227{
228 return lto_new_compression_stream (callback, opaque, true);
229}
230
231/* Append NUM_CHARS from address BASE to STREAM. */
232
233void
234lto_compress_block (struct lto_compression_stream *stream,
235 const char *base, size_t num_chars)
236{
237 gcc_assert (stream->is_compression);
238
239 lto_append_to_compression_stream (stream, base, num_chars);
240 lto_stats.num_output_il_bytes += num_chars;
241}
242
87741e51
ML
243static void ATTRIBUTE_UNUSED
244lto_compression_zlib (struct lto_compression_stream *stream)
d7f09764
DN
245{
246 unsigned char *cursor = (unsigned char *) stream->buffer;
247 size_t remaining = stream->bytes;
248 const size_t outbuf_length = Z_BUFFER_LENGTH;
249 unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
250 z_stream out_stream;
251 size_t compressed_bytes = 0;
252 int status;
253
254 gcc_assert (stream->is_compression);
255
ed7dc894
JH
256 timevar_push (TV_IPA_LTO_COMPRESS);
257
d7f09764
DN
258 out_stream.next_out = outbuf;
259 out_stream.avail_out = outbuf_length;
260 out_stream.next_in = cursor;
261 out_stream.avail_in = remaining;
262 out_stream.zalloc = lto_zalloc;
263 out_stream.zfree = lto_zfree;
264 out_stream.opaque = Z_NULL;
265
266 status = deflateInit (&out_stream, lto_normalized_zlib_level ());
267 if (status != Z_OK)
268 internal_error ("compressed stream: %s", zError (status));
269
270 do
271 {
272 size_t in_bytes, out_bytes;
273
274 status = deflate (&out_stream, Z_FINISH);
275 if (status != Z_OK && status != Z_STREAM_END)
276 internal_error ("compressed stream: %s", zError (status));
277
278 in_bytes = remaining - out_stream.avail_in;
279 out_bytes = outbuf_length - out_stream.avail_out;
280
281 stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
282 lto_stats.num_compressed_il_bytes += out_bytes;
283 compressed_bytes += out_bytes;
284
285 cursor += in_bytes;
286 remaining -= in_bytes;
287
288 out_stream.next_out = outbuf;
289 out_stream.avail_out = outbuf_length;
290 out_stream.next_in = cursor;
291 out_stream.avail_in = remaining;
292 }
293 while (status != Z_STREAM_END);
294
295 status = deflateEnd (&out_stream);
296 if (status != Z_OK)
297 internal_error ("compressed stream: %s", zError (status));
298
299 lto_destroy_compression_stream (stream);
300 free (outbuf);
ed7dc894 301 timevar_pop (TV_IPA_LTO_COMPRESS);
d7f09764
DN
302}
303
87741e51
ML
304void
305lto_end_compression (struct lto_compression_stream *stream)
306{
307#ifdef HAVE_ZSTD_H
308 lto_compression_zstd (stream);
309#else
310 lto_compression_zlib (stream);
311#endif
312}
313
d7f09764
DN
314/* Return a new uncompression stream, with CALLBACK flush function passed
315 OPAQUE token. */
316
317struct lto_compression_stream *
318lto_start_uncompression (void (*callback) (const char *, unsigned, void *),
319 void *opaque)
320{
321 return lto_new_compression_stream (callback, opaque, false);
322}
323
324/* Append NUM_CHARS from address BASE to STREAM. */
325
326void
327lto_uncompress_block (struct lto_compression_stream *stream,
328 const char *base, size_t num_chars)
329{
330 gcc_assert (!stream->is_compression);
331
332 lto_append_to_compression_stream (stream, base, num_chars);
333 lto_stats.num_input_il_bytes += num_chars;
334}
335
87741e51
ML
336static void
337lto_uncompression_zlib (struct lto_compression_stream *stream)
d7f09764
DN
338{
339 unsigned char *cursor = (unsigned char *) stream->buffer;
340 size_t remaining = stream->bytes;
341 const size_t outbuf_length = Z_BUFFER_LENGTH;
342 unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
343 size_t uncompressed_bytes = 0;
344
345 gcc_assert (!stream->is_compression);
ed7dc894 346 timevar_push (TV_IPA_LTO_DECOMPRESS);
d7f09764
DN
347
348 while (remaining > 0)
349 {
350 z_stream in_stream;
351 size_t out_bytes;
352 int status;
353
354 in_stream.next_out = outbuf;
355 in_stream.avail_out = outbuf_length;
356 in_stream.next_in = cursor;
357 in_stream.avail_in = remaining;
358 in_stream.zalloc = lto_zalloc;
359 in_stream.zfree = lto_zfree;
360 in_stream.opaque = Z_NULL;
361
362 status = inflateInit (&in_stream);
363 if (status != Z_OK)
364 internal_error ("compressed stream: %s", zError (status));
365
366 do
367 {
368 size_t in_bytes;
369
370 status = inflate (&in_stream, Z_SYNC_FLUSH);
371 if (status != Z_OK && status != Z_STREAM_END)
372 internal_error ("compressed stream: %s", zError (status));
373
374 in_bytes = remaining - in_stream.avail_in;
375 out_bytes = outbuf_length - in_stream.avail_out;
376
377 stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
378 lto_stats.num_uncompressed_il_bytes += out_bytes;
379 uncompressed_bytes += out_bytes;
380
381 cursor += in_bytes;
382 remaining -= in_bytes;
383
384 in_stream.next_out = outbuf;
385 in_stream.avail_out = outbuf_length;
386 in_stream.next_in = cursor;
387 in_stream.avail_in = remaining;
388 }
389 while (!(status == Z_STREAM_END && out_bytes == 0));
390
391 status = inflateEnd (&in_stream);
392 if (status != Z_OK)
393 internal_error ("compressed stream: %s", zError (status));
394 }
395
396 lto_destroy_compression_stream (stream);
397 free (outbuf);
ed7dc894 398 timevar_pop (TV_IPA_LTO_DECOMPRESS);
d7f09764 399}
87741e51
ML
400
401void
402lto_end_uncompression (struct lto_compression_stream *stream,
403 lto_compression compression)
404{
405#ifdef HAVE_ZSTD_H
406 if (compression == ZSTD)
407 {
408 lto_uncompression_zstd (stream);
409 return;
410 }
411#endif
412 if (compression == ZSTD)
413 internal_error ("compiler does not support ZSTD LTO compression");
414
415 lto_uncompression_zlib (stream);
416}