LCOV - code coverage report
Current view: top level - gcc - lto-compress.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 42.2 % 185 78
Test Date: 2024-04-20 14:03:02 Functions: 70.6 % 17 12
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* LTO IL compression streams.
       2                 :             : 
       3                 :             :    Copyright (C) 2009-2024 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                 :             : #include "coretypes.h"
      25                 :             : #include "backend.h"
      26                 :             : #include "tree.h"
      27                 :             : #include "gimple.h"
      28                 :             : #include "cgraph.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
      33                 :             :    system.h.  */
      34                 :             : #include <zlib.h>
      35                 :             : #include "lto-compress.h"
      36                 :             : #include "timevar.h"
      37                 :             : 
      38                 :             : #ifdef HAVE_ZSTD_H
      39                 :             : #include <zstd.h>
      40                 :             : #endif
      41                 :             : 
      42                 :             : /* Compression stream structure, holds the flush callback and opaque token,
      43                 :             :    the buffered data, and a note of whether compressing or uncompressing.  */
      44                 :             : 
      45                 :             : struct 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                 :             : 
      57                 :             : static const size_t Z_BUFFER_LENGTH = 4096;
      58                 :             : static 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                 :             : 
      63                 :             : static void *
      64                 :           0 : lto_zalloc (void *opaque, unsigned items, unsigned size)
      65                 :             : {
      66                 :           0 :   gcc_assert (opaque == Z_NULL);
      67                 :           0 :   return xmalloc (items * size);
      68                 :             : }
      69                 :             : 
      70                 :             : /* For zlib, free memory at ADDRESS, OPAQUE is unused.  */
      71                 :             : 
      72                 :             : static void
      73                 :           0 : lto_zfree (void *opaque, void *address)
      74                 :             : {
      75                 :           0 :   gcc_assert (opaque == Z_NULL);
      76                 :           0 :   free (address);
      77                 :           0 : }
      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                 :             : 
      83                 :             : static int
      84                 :           0 : lto_normalized_zlib_level (void)
      85                 :             : {
      86                 :           0 :   int level = flag_lto_compression_level;
      87                 :             : 
      88                 :           0 :   if (level != Z_DEFAULT_COMPRESSION)
      89                 :             :     {
      90                 :           0 :       if (level < Z_NO_COMPRESSION)
      91                 :             :         level = Z_NO_COMPRESSION;
      92                 :           0 :       else if (level > Z_BEST_COMPRESSION)
      93                 :             :         level = Z_BEST_COMPRESSION;
      94                 :             :     }
      95                 :             : 
      96                 :           0 :   return level;
      97                 :             : }
      98                 :             : 
      99                 :             : /* Free the buffer and memory associated with STREAM.  */
     100                 :             : 
     101                 :             : static void
     102                 :      518559 : lto_destroy_compression_stream (struct lto_compression_stream *stream)
     103                 :             : {
     104                 :      518559 :   free (stream->buffer);
     105                 :      518559 :   free (stream);
     106                 :      518559 : }
     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                 :             : 
     113                 :             : static int
     114                 :      317268 : lto_normalized_zstd_level (void)
     115                 :             : {
     116                 :      317268 :   int level = flag_lto_compression_level;
     117                 :             : 
     118                 :      317268 :   if (level < 0)
     119                 :             :     level = 0;
     120                 :           0 :   else if (level > ZSTD_maxCLevel ())
     121                 :           0 :     level = ZSTD_maxCLevel ();
     122                 :             : 
     123                 :      317268 :   return level;
     124                 :             : }
     125                 :             : 
     126                 :             : /* Compress STREAM using ZSTD algorithm.  */
     127                 :             : 
     128                 :             : static void
     129                 :      317268 : lto_compression_zstd (struct lto_compression_stream *stream)
     130                 :             : {
     131                 :      317268 :   unsigned char *cursor = (unsigned char *) stream->buffer;
     132                 :      317268 :   size_t size = stream->bytes;
     133                 :             : 
     134                 :      317268 :   timevar_push (TV_IPA_LTO_COMPRESS);
     135                 :      317268 :   size_t const outbuf_length = ZSTD_compressBound (size);
     136                 :      317268 :   char *outbuf = (char *) xmalloc (outbuf_length);
     137                 :             : 
     138                 :      317268 :   size_t const csize = ZSTD_compress (outbuf, outbuf_length, cursor, size,
     139                 :             :                                       lto_normalized_zstd_level ());
     140                 :             : 
     141                 :      317268 :   if (ZSTD_isError (csize))
     142                 :           0 :     internal_error ("compressed stream: %s", ZSTD_getErrorName (csize));
     143                 :             : 
     144                 :      317268 :   lto_stats.num_compressed_il_bytes += csize;
     145                 :      317268 :   stream->callback (outbuf, csize, NULL);
     146                 :             : 
     147                 :      317268 :   lto_destroy_compression_stream (stream);
     148                 :      317268 :   free (outbuf);
     149                 :      317268 :   timevar_pop (TV_IPA_LTO_COMPRESS);
     150                 :      317268 : }
     151                 :             : 
     152                 :             : /* Uncompress STREAM using ZSTD algorithm.  */
     153                 :             : 
     154                 :             : static void
     155                 :      201291 : lto_uncompression_zstd (struct lto_compression_stream *stream)
     156                 :             : {
     157                 :      201291 :   unsigned char *cursor = (unsigned char *) stream->buffer;
     158                 :      201291 :   size_t size = stream->bytes;
     159                 :             : 
     160                 :      201291 :   timevar_push (TV_IPA_LTO_DECOMPRESS);
     161                 :      201291 :   unsigned long long const rsize = ZSTD_getFrameContentSize (cursor, size);
     162                 :      201291 :   if (rsize == ZSTD_CONTENTSIZE_ERROR)
     163                 :           0 :     internal_error ("original not compressed with zstd");
     164                 :      201291 :   else if (rsize == ZSTD_CONTENTSIZE_UNKNOWN)
     165                 :           0 :     internal_error ("original size unknown");
     166                 :             : 
     167                 :      201291 :   char *outbuf = (char *) xmalloc (rsize);
     168                 :      201291 :   size_t const dsize = ZSTD_decompress (outbuf, rsize, cursor, size);
     169                 :             : 
     170                 :      201291 :   if (ZSTD_isError (dsize))
     171                 :           0 :     internal_error ("decompressed stream: %s", ZSTD_getErrorName (dsize));
     172                 :             : 
     173                 :      201291 :   lto_stats.num_uncompressed_il_bytes += dsize;
     174                 :      201291 :   stream->callback (outbuf, dsize, stream->opaque);
     175                 :             : 
     176                 :      201291 :   lto_destroy_compression_stream (stream);
     177                 :      201291 :   free (outbuf);
     178                 :      201291 :   timevar_pop (TV_IPA_LTO_DECOMPRESS);
     179                 :      201291 : }
     180                 :             : 
     181                 :             : #endif
     182                 :             : 
     183                 :             : /* Create a new compression stream, with CALLBACK flush function passed
     184                 :             :    OPAQUE token, IS_COMPRESSION indicates if compressing or uncompressing.  */
     185                 :             : 
     186                 :             : static struct lto_compression_stream *
     187                 :      518559 : lto_new_compression_stream (void (*callback) (const char *, unsigned, void *),
     188                 :             :                             void *opaque, bool is_compression)
     189                 :             : {
     190                 :      518559 :   struct lto_compression_stream *stream
     191                 :      518559 :     = (struct lto_compression_stream *) xmalloc (sizeof (*stream));
     192                 :             : 
     193                 :      518559 :   memset (stream, 0, sizeof (*stream));
     194                 :      518559 :   stream->callback = callback;
     195                 :      518559 :   stream->opaque = opaque;
     196                 :      518559 :   stream->is_compression = is_compression;
     197                 :             : 
     198                 :      518559 :   return stream;
     199                 :             : }
     200                 :             : 
     201                 :             : /* Append NUM_CHARS from address BASE to STREAM.  */
     202                 :             : 
     203                 :             : static void
     204                 :     1390263 : lto_append_to_compression_stream (struct lto_compression_stream *stream,
     205                 :             :                                   const char *base, size_t num_chars)
     206                 :             : {
     207                 :     1390263 :   size_t required = stream->bytes + num_chars;
     208                 :             : 
     209                 :     1390263 :   if (stream->allocation < required)
     210                 :             :     {
     211                 :      569306 :       if (stream->allocation == 0)
     212                 :      518559 :         stream->allocation = MIN_STREAM_ALLOCATION;
     213                 :      639281 :       while (stream->allocation < required)
     214                 :       69975 :         stream->allocation *= 2;
     215                 :             : 
     216                 :      569306 :       stream->buffer = (char *) xrealloc (stream->buffer, stream->allocation);
     217                 :             :     }
     218                 :             : 
     219                 :     1390263 :   memcpy (stream->buffer + stream->bytes, base, num_chars);
     220                 :     1390263 :   stream->bytes += num_chars;
     221                 :     1390263 : }
     222                 :             : 
     223                 :             : /* Return a new compression stream, with CALLBACK flush function passed
     224                 :             :    OPAQUE token.  */
     225                 :             : 
     226                 :             : struct lto_compression_stream *
     227                 :      317268 : lto_start_compression (void (*callback) (const char *, unsigned, void *),
     228                 :             :                        void *opaque)
     229                 :             : {
     230                 :      317268 :   return lto_new_compression_stream (callback, opaque, true);
     231                 :             : }
     232                 :             : 
     233                 :             : /* Append NUM_CHARS from address BASE to STREAM.  */
     234                 :             : 
     235                 :             : void
     236                 :     1188972 : lto_compress_block (struct lto_compression_stream *stream,
     237                 :             :                     const char *base, size_t num_chars)
     238                 :             : {
     239                 :     1188972 :   gcc_assert (stream->is_compression);
     240                 :             : 
     241                 :     1188972 :   lto_append_to_compression_stream (stream, base, num_chars);
     242                 :     1188972 :   lto_stats.num_output_il_bytes += num_chars;
     243                 :     1188972 : }
     244                 :             : 
     245                 :             : static void ATTRIBUTE_UNUSED
     246                 :           0 : lto_compression_zlib (struct lto_compression_stream *stream)
     247                 :             : {
     248                 :           0 :   unsigned char *cursor = (unsigned char *) stream->buffer;
     249                 :           0 :   size_t remaining = stream->bytes;
     250                 :           0 :   const size_t outbuf_length = Z_BUFFER_LENGTH;
     251                 :           0 :   unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
     252                 :           0 :   z_stream out_stream;
     253                 :           0 :   int status;
     254                 :             : 
     255                 :           0 :   gcc_assert (stream->is_compression);
     256                 :             : 
     257                 :           0 :   timevar_push (TV_IPA_LTO_COMPRESS);
     258                 :             : 
     259                 :           0 :   out_stream.next_out = outbuf;
     260                 :           0 :   out_stream.avail_out = outbuf_length;
     261                 :           0 :   out_stream.next_in = cursor;
     262                 :           0 :   out_stream.avail_in = remaining;
     263                 :           0 :   out_stream.zalloc = lto_zalloc;
     264                 :           0 :   out_stream.zfree = lto_zfree;
     265                 :           0 :   out_stream.opaque = Z_NULL;
     266                 :             : 
     267                 :           0 :   status = deflateInit (&out_stream, lto_normalized_zlib_level ());
     268                 :           0 :   if (status != Z_OK)
     269                 :           0 :     internal_error ("compressed stream: %s", zError (status));
     270                 :             : 
     271                 :           0 :   do
     272                 :             :     {
     273                 :           0 :       size_t in_bytes, out_bytes;
     274                 :             : 
     275                 :           0 :       status = deflate (&out_stream, Z_FINISH);
     276                 :           0 :       if (status != Z_OK && status != Z_STREAM_END)
     277                 :           0 :         internal_error ("compressed stream: %s", zError (status));
     278                 :             : 
     279                 :           0 :       in_bytes = remaining - out_stream.avail_in;
     280                 :           0 :       out_bytes = outbuf_length - out_stream.avail_out;
     281                 :             : 
     282                 :           0 :       stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
     283                 :           0 :       lto_stats.num_compressed_il_bytes += out_bytes;
     284                 :             : 
     285                 :           0 :       cursor += in_bytes;
     286                 :           0 :       remaining -= in_bytes;
     287                 :             : 
     288                 :           0 :       out_stream.next_out = outbuf;
     289                 :           0 :       out_stream.avail_out = outbuf_length;
     290                 :           0 :       out_stream.next_in = cursor;
     291                 :           0 :       out_stream.avail_in = remaining;
     292                 :             :     }
     293                 :           0 :   while (status != Z_STREAM_END);
     294                 :             : 
     295                 :           0 :   status = deflateEnd (&out_stream);
     296                 :           0 :   if (status != Z_OK)
     297                 :           0 :     internal_error ("compressed stream: %s", zError (status));
     298                 :             : 
     299                 :           0 :   lto_destroy_compression_stream (stream);
     300                 :           0 :   free (outbuf);
     301                 :           0 :   timevar_pop (TV_IPA_LTO_COMPRESS);
     302                 :           0 : }
     303                 :             : 
     304                 :             : void
     305                 :      317268 : lto_end_compression (struct lto_compression_stream *stream)
     306                 :             : {
     307                 :             : #ifdef HAVE_ZSTD_H
     308                 :      317268 :   lto_compression_zstd (stream);
     309                 :             : #else
     310                 :             :   lto_compression_zlib (stream);
     311                 :             : #endif
     312                 :      317268 : }
     313                 :             : 
     314                 :             : /* Return a new uncompression stream, with CALLBACK flush function passed
     315                 :             :    OPAQUE token.  */
     316                 :             : 
     317                 :             : struct lto_compression_stream *
     318                 :      201291 : lto_start_uncompression (void (*callback) (const char *, unsigned, void *),
     319                 :             :                          void *opaque)
     320                 :             : {
     321                 :      201291 :   return lto_new_compression_stream (callback, opaque, false);
     322                 :             : }
     323                 :             : 
     324                 :             : /* Append NUM_CHARS from address BASE to STREAM.  */
     325                 :             : 
     326                 :             : void
     327                 :      201291 : lto_uncompress_block (struct lto_compression_stream *stream,
     328                 :             :                       const char *base, size_t num_chars)
     329                 :             : {
     330                 :      201291 :   gcc_assert (!stream->is_compression);
     331                 :             : 
     332                 :      201291 :   lto_append_to_compression_stream (stream, base, num_chars);
     333                 :      201291 :   lto_stats.num_input_il_bytes += num_chars;
     334                 :      201291 : }
     335                 :             : 
     336                 :             : static void
     337                 :           0 : lto_uncompression_zlib (struct lto_compression_stream *stream)
     338                 :             : {
     339                 :           0 :   unsigned char *cursor = (unsigned char *) stream->buffer;
     340                 :           0 :   size_t remaining = stream->bytes;
     341                 :           0 :   const size_t outbuf_length = Z_BUFFER_LENGTH;
     342                 :           0 :   unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
     343                 :             : 
     344                 :           0 :   gcc_assert (!stream->is_compression);
     345                 :           0 :   timevar_push (TV_IPA_LTO_DECOMPRESS);
     346                 :             : 
     347                 :           0 :   while (remaining > 0)
     348                 :             :     {
     349                 :           0 :       z_stream in_stream;
     350                 :           0 :       size_t out_bytes;
     351                 :           0 :       int status;
     352                 :             : 
     353                 :           0 :       in_stream.next_out = outbuf;
     354                 :           0 :       in_stream.avail_out = outbuf_length;
     355                 :           0 :       in_stream.next_in = cursor;
     356                 :           0 :       in_stream.avail_in = remaining;
     357                 :           0 :       in_stream.zalloc = lto_zalloc;
     358                 :           0 :       in_stream.zfree = lto_zfree;
     359                 :           0 :       in_stream.opaque = Z_NULL;
     360                 :             : 
     361                 :           0 :       status = inflateInit (&in_stream);
     362                 :           0 :       if (status != Z_OK)
     363                 :           0 :         internal_error ("compressed stream: %s", zError (status));
     364                 :             : 
     365                 :           0 :       do
     366                 :             :         {
     367                 :           0 :           size_t in_bytes;
     368                 :             : 
     369                 :           0 :           status = inflate (&in_stream, Z_SYNC_FLUSH);
     370                 :           0 :           if (status != Z_OK && status != Z_STREAM_END)
     371                 :           0 :             internal_error ("compressed stream: %s", zError (status));
     372                 :             : 
     373                 :           0 :           in_bytes = remaining - in_stream.avail_in;
     374                 :           0 :           out_bytes = outbuf_length - in_stream.avail_out;
     375                 :             : 
     376                 :           0 :           stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
     377                 :           0 :           lto_stats.num_uncompressed_il_bytes += out_bytes;
     378                 :             : 
     379                 :           0 :           cursor += in_bytes;
     380                 :           0 :           remaining -= in_bytes;
     381                 :             : 
     382                 :           0 :           in_stream.next_out = outbuf;
     383                 :           0 :           in_stream.avail_out = outbuf_length;
     384                 :           0 :           in_stream.next_in = cursor;
     385                 :           0 :           in_stream.avail_in = remaining;
     386                 :             :         }
     387                 :           0 :       while (!(status == Z_STREAM_END && out_bytes == 0));
     388                 :             : 
     389                 :           0 :       status = inflateEnd (&in_stream);
     390                 :           0 :       if (status != Z_OK)
     391                 :           0 :         internal_error ("compressed stream: %s", zError (status));
     392                 :             :     }
     393                 :             : 
     394                 :           0 :   lto_destroy_compression_stream (stream);
     395                 :           0 :   free (outbuf);
     396                 :           0 :   timevar_pop (TV_IPA_LTO_DECOMPRESS);
     397                 :           0 : }
     398                 :             : 
     399                 :             : void
     400                 :      201291 : lto_end_uncompression (struct lto_compression_stream *stream,
     401                 :             :                        lto_compression compression)
     402                 :             : {
     403                 :             : #ifdef HAVE_ZSTD_H
     404                 :      201291 :   if (compression == ZSTD)
     405                 :             :     {
     406                 :      201291 :       lto_uncompression_zstd (stream);
     407                 :      201291 :       return;
     408                 :             :     }
     409                 :             : #endif
     410                 :           0 :   if (compression == ZSTD)
     411                 :             :     fatal_error (UNKNOWN_LOCATION, "compiler does not support ZSTD LTO compression");
     412                 :             : 
     413                 :           0 :   lto_uncompression_zlib (stream);
     414                 :             : }
        

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.