1 /* LTO IL compression streams.
3 Copyright (C) 2009-2022 Free Software Foundation, Inc.
4 Contributed by Simon Baldwin <simonb@google.com>
6 This file is part of GCC.
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)
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.
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/>. */
24 #include "coretypes.h"
29 #include "lto-streamer.h"
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
35 #include "lto-compress.h"
42 /* Compression stream structure, holds the flush callback and opaque token,
43 the buffered data, and a note of whether compressing or uncompressing. */
45 struct lto_compression_stream
47 void (*callback
) (const char *, unsigned, void *);
55 /* Overall compression constants for zlib. */
57 static const size_t Z_BUFFER_LENGTH
= 4096;
58 static const size_t MIN_STREAM_ALLOCATION
= 1024;
60 /* For zlib, allocate SIZE count of ITEMS and return the address, OPAQUE
64 lto_zalloc (void *opaque
, unsigned items
, unsigned size
)
66 gcc_assert (opaque
== Z_NULL
);
67 return xmalloc (items
* size
);
70 /* For zlib, free memory at ADDRESS, OPAQUE is unused. */
73 lto_zfree (void *opaque
, void *address
)
75 gcc_assert (opaque
== Z_NULL
);
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. */
84 lto_normalized_zlib_level (void)
86 int level
= flag_lto_compression_level
;
88 if (level
!= Z_DEFAULT_COMPRESSION
)
90 if (level
< Z_NO_COMPRESSION
)
91 level
= Z_NO_COMPRESSION
;
92 else if (level
> Z_BEST_COMPRESSION
)
93 level
= Z_BEST_COMPRESSION
;
99 /* Free the buffer and memory associated with STREAM. */
102 lto_destroy_compression_stream (struct lto_compression_stream
*stream
)
104 free (stream
->buffer
);
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. */
114 lto_normalized_zstd_level (void)
116 int level
= flag_lto_compression_level
;
120 else if (level
> ZSTD_maxCLevel ())
121 level
= ZSTD_maxCLevel ();
126 /* Compress STREAM using ZSTD algorithm. */
129 lto_compression_zstd (struct lto_compression_stream
*stream
)
131 unsigned char *cursor
= (unsigned char *) stream
->buffer
;
132 size_t size
= stream
->bytes
;
134 timevar_push (TV_IPA_LTO_COMPRESS
);
135 size_t const outbuf_length
= ZSTD_compressBound (size
);
136 char *outbuf
= (char *) xmalloc (outbuf_length
);
138 size_t const csize
= ZSTD_compress (outbuf
, outbuf_length
, cursor
, size
,
139 lto_normalized_zstd_level ());
141 if (ZSTD_isError (csize
))
142 internal_error ("compressed stream: %s", ZSTD_getErrorName (csize
));
144 lto_stats
.num_compressed_il_bytes
+= csize
;
145 stream
->callback (outbuf
, csize
, NULL
);
147 lto_destroy_compression_stream (stream
);
149 timevar_pop (TV_IPA_LTO_COMPRESS
);
152 /* Uncompress STREAM using ZSTD algorithm. */
155 lto_uncompression_zstd (struct lto_compression_stream
*stream
)
157 unsigned char *cursor
= (unsigned char *) stream
->buffer
;
158 size_t size
= stream
->bytes
;
160 timevar_push (TV_IPA_LTO_DECOMPRESS
);
161 unsigned long long const rsize
= ZSTD_getFrameContentSize (cursor
, size
);
162 if (rsize
== ZSTD_CONTENTSIZE_ERROR
)
163 internal_error ("original not compressed with zstd");
164 else if (rsize
== ZSTD_CONTENTSIZE_UNKNOWN
)
165 internal_error ("original size unknown");
167 char *outbuf
= (char *) xmalloc (rsize
);
168 size_t const dsize
= ZSTD_decompress (outbuf
, rsize
, cursor
, size
);
170 if (ZSTD_isError (dsize
))
171 internal_error ("decompressed stream: %s", ZSTD_getErrorName (dsize
));
173 lto_stats
.num_uncompressed_il_bytes
+= dsize
;
174 stream
->callback (outbuf
, dsize
, stream
->opaque
);
176 lto_destroy_compression_stream (stream
);
178 timevar_pop (TV_IPA_LTO_DECOMPRESS
);
183 /* Create a new compression stream, with CALLBACK flush function passed
184 OPAQUE token, IS_COMPRESSION indicates if compressing or uncompressing. */
186 static struct lto_compression_stream
*
187 lto_new_compression_stream (void (*callback
) (const char *, unsigned, void *),
188 void *opaque
, bool is_compression
)
190 struct lto_compression_stream
*stream
191 = (struct lto_compression_stream
*) xmalloc (sizeof (*stream
));
193 memset (stream
, 0, sizeof (*stream
));
194 stream
->callback
= callback
;
195 stream
->opaque
= opaque
;
196 stream
->is_compression
= is_compression
;
201 /* Append NUM_CHARS from address BASE to STREAM. */
204 lto_append_to_compression_stream (struct lto_compression_stream
*stream
,
205 const char *base
, size_t num_chars
)
207 size_t required
= stream
->bytes
+ num_chars
;
209 if (stream
->allocation
< required
)
211 if (stream
->allocation
== 0)
212 stream
->allocation
= MIN_STREAM_ALLOCATION
;
213 while (stream
->allocation
< required
)
214 stream
->allocation
*= 2;
216 stream
->buffer
= (char *) xrealloc (stream
->buffer
, stream
->allocation
);
219 memcpy (stream
->buffer
+ stream
->bytes
, base
, num_chars
);
220 stream
->bytes
+= num_chars
;
223 /* Return a new compression stream, with CALLBACK flush function passed
226 struct lto_compression_stream
*
227 lto_start_compression (void (*callback
) (const char *, unsigned, void *),
230 return lto_new_compression_stream (callback
, opaque
, true);
233 /* Append NUM_CHARS from address BASE to STREAM. */
236 lto_compress_block (struct lto_compression_stream
*stream
,
237 const char *base
, size_t num_chars
)
239 gcc_assert (stream
->is_compression
);
241 lto_append_to_compression_stream (stream
, base
, num_chars
);
242 lto_stats
.num_output_il_bytes
+= num_chars
;
245 static void ATTRIBUTE_UNUSED
246 lto_compression_zlib (struct lto_compression_stream
*stream
)
248 unsigned char *cursor
= (unsigned char *) stream
->buffer
;
249 size_t remaining
= stream
->bytes
;
250 const size_t outbuf_length
= Z_BUFFER_LENGTH
;
251 unsigned char *outbuf
= (unsigned char *) xmalloc (outbuf_length
);
255 gcc_assert (stream
->is_compression
);
257 timevar_push (TV_IPA_LTO_COMPRESS
);
259 out_stream
.next_out
= outbuf
;
260 out_stream
.avail_out
= outbuf_length
;
261 out_stream
.next_in
= cursor
;
262 out_stream
.avail_in
= remaining
;
263 out_stream
.zalloc
= lto_zalloc
;
264 out_stream
.zfree
= lto_zfree
;
265 out_stream
.opaque
= Z_NULL
;
267 status
= deflateInit (&out_stream
, lto_normalized_zlib_level ());
269 internal_error ("compressed stream: %s", zError (status
));
273 size_t in_bytes
, out_bytes
;
275 status
= deflate (&out_stream
, Z_FINISH
);
276 if (status
!= Z_OK
&& status
!= Z_STREAM_END
)
277 internal_error ("compressed stream: %s", zError (status
));
279 in_bytes
= remaining
- out_stream
.avail_in
;
280 out_bytes
= outbuf_length
- out_stream
.avail_out
;
282 stream
->callback ((const char *) outbuf
, out_bytes
, stream
->opaque
);
283 lto_stats
.num_compressed_il_bytes
+= out_bytes
;
286 remaining
-= in_bytes
;
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
;
293 while (status
!= Z_STREAM_END
);
295 status
= deflateEnd (&out_stream
);
297 internal_error ("compressed stream: %s", zError (status
));
299 lto_destroy_compression_stream (stream
);
301 timevar_pop (TV_IPA_LTO_COMPRESS
);
305 lto_end_compression (struct lto_compression_stream
*stream
)
308 lto_compression_zstd (stream
);
310 lto_compression_zlib (stream
);
314 /* Return a new uncompression stream, with CALLBACK flush function passed
317 struct lto_compression_stream
*
318 lto_start_uncompression (void (*callback
) (const char *, unsigned, void *),
321 return lto_new_compression_stream (callback
, opaque
, false);
324 /* Append NUM_CHARS from address BASE to STREAM. */
327 lto_uncompress_block (struct lto_compression_stream
*stream
,
328 const char *base
, size_t num_chars
)
330 gcc_assert (!stream
->is_compression
);
332 lto_append_to_compression_stream (stream
, base
, num_chars
);
333 lto_stats
.num_input_il_bytes
+= num_chars
;
337 lto_uncompression_zlib (struct lto_compression_stream
*stream
)
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
);
344 gcc_assert (!stream
->is_compression
);
345 timevar_push (TV_IPA_LTO_DECOMPRESS
);
347 while (remaining
> 0)
353 in_stream
.next_out
= outbuf
;
354 in_stream
.avail_out
= outbuf_length
;
355 in_stream
.next_in
= cursor
;
356 in_stream
.avail_in
= remaining
;
357 in_stream
.zalloc
= lto_zalloc
;
358 in_stream
.zfree
= lto_zfree
;
359 in_stream
.opaque
= Z_NULL
;
361 status
= inflateInit (&in_stream
);
363 internal_error ("compressed stream: %s", zError (status
));
369 status
= inflate (&in_stream
, Z_SYNC_FLUSH
);
370 if (status
!= Z_OK
&& status
!= Z_STREAM_END
)
371 internal_error ("compressed stream: %s", zError (status
));
373 in_bytes
= remaining
- in_stream
.avail_in
;
374 out_bytes
= outbuf_length
- in_stream
.avail_out
;
376 stream
->callback ((const char *) outbuf
, out_bytes
, stream
->opaque
);
377 lto_stats
.num_uncompressed_il_bytes
+= out_bytes
;
380 remaining
-= in_bytes
;
382 in_stream
.next_out
= outbuf
;
383 in_stream
.avail_out
= outbuf_length
;
384 in_stream
.next_in
= cursor
;
385 in_stream
.avail_in
= remaining
;
387 while (!(status
== Z_STREAM_END
&& out_bytes
== 0));
389 status
= inflateEnd (&in_stream
);
391 internal_error ("compressed stream: %s", zError (status
));
394 lto_destroy_compression_stream (stream
);
396 timevar_pop (TV_IPA_LTO_DECOMPRESS
);
400 lto_end_uncompression (struct lto_compression_stream
*stream
,
401 lto_compression compression
)
404 if (compression
== ZSTD
)
406 lto_uncompression_zstd (stream
);
410 if (compression
== ZSTD
)
411 internal_error ("compiler does not support ZSTD LTO compression");
413 lto_uncompression_zlib (stream
);