LCOV - code coverage report
Current view: top level - gcc - lto-compress.c (source / functions) Hit Total Coverage
Test: gcc.info Lines: 75 186 40.3 %
Date: 2020-04-04 11:58:09 Functions: 11 17 64.7 %
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-2020 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                 :            :       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                 :     402166 : lto_destroy_compression_stream (struct lto_compression_stream *stream)
     103                 :            : {
     104                 :     402166 :   free (stream->buffer);
     105                 :     402166 :   free (stream);
     106                 :          0 : }
     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                 :     240819 : lto_normalized_zstd_level (void)
     115                 :            : {
     116                 :     240819 :   int level = flag_lto_compression_level;
     117                 :            : 
     118                 :     240819 :   if (level < 0)
     119                 :            :     level = 0;
     120                 :          0 :   else if (level > ZSTD_maxCLevel ())
     121                 :          0 :     level = ZSTD_maxCLevel ();
     122                 :            : 
     123                 :     240819 :   return level;
     124                 :            : }
     125                 :            : 
     126                 :            : /* Compress STREAM using ZSTD algorithm.  */
     127                 :            : 
     128                 :            : static void
     129                 :     240819 : lto_compression_zstd (struct lto_compression_stream *stream)
     130                 :            : {
     131                 :     240819 :   unsigned char *cursor = (unsigned char *) stream->buffer;
     132                 :     240819 :   size_t size = stream->bytes;
     133                 :            : 
     134                 :     240819 :   timevar_push (TV_IPA_LTO_COMPRESS);
     135                 :     240819 :   size_t const outbuf_length = ZSTD_compressBound (size);
     136                 :     240819 :   char *outbuf = (char *) xmalloc (outbuf_length);
     137                 :            : 
     138                 :     240819 :   size_t const csize = ZSTD_compress (outbuf, outbuf_length, cursor, size,
     139                 :            :                                       lto_normalized_zstd_level ());
     140                 :            : 
     141                 :     240819 :   if (ZSTD_isError (csize))
     142                 :          0 :     internal_error ("compressed stream: %s", ZSTD_getErrorName (csize));
     143                 :            : 
     144                 :     240819 :   stream->callback (outbuf, csize, NULL);
     145                 :            : 
     146                 :     240819 :   lto_destroy_compression_stream (stream);
     147                 :     240819 :   free (outbuf);
     148                 :     240819 :   timevar_pop (TV_IPA_LTO_COMPRESS);
     149                 :     240819 : }
     150                 :            : 
     151                 :            : /* Uncompress STREAM using ZSTD algorithm.  */
     152                 :            : 
     153                 :            : static void
     154                 :     161347 : lto_uncompression_zstd (struct lto_compression_stream *stream)
     155                 :            : {
     156                 :     161347 :   unsigned char *cursor = (unsigned char *) stream->buffer;
     157                 :     161347 :   size_t size = stream->bytes;
     158                 :            : 
     159                 :     161347 :   timevar_push (TV_IPA_LTO_DECOMPRESS);
     160                 :     161347 :   unsigned long long const rsize = ZSTD_getFrameContentSize (cursor, size);
     161                 :     161347 :   if (rsize == ZSTD_CONTENTSIZE_ERROR)
     162                 :          0 :     internal_error ("original not compressed with zstd");
     163                 :     161347 :   else if (rsize == ZSTD_CONTENTSIZE_UNKNOWN)
     164                 :          0 :     internal_error ("original size unknown");
     165                 :            : 
     166                 :     161347 :   char *outbuf = (char *) xmalloc (rsize);
     167                 :     161347 :   size_t const dsize = ZSTD_decompress (outbuf, rsize, cursor, size);
     168                 :            : 
     169                 :     161347 :   if (ZSTD_isError (dsize))
     170                 :          0 :     internal_error ("decompressed stream: %s", ZSTD_getErrorName (dsize));
     171                 :            : 
     172                 :     161347 :   stream->callback (outbuf, dsize, stream->opaque);
     173                 :            : 
     174                 :     161347 :   lto_destroy_compression_stream (stream);
     175                 :     161347 :   free (outbuf);
     176                 :     161347 :   timevar_pop (TV_IPA_LTO_DECOMPRESS);
     177                 :     161347 : }
     178                 :            : 
     179                 :            : #endif
     180                 :            : 
     181                 :            : /* Create a new compression stream, with CALLBACK flush function passed
     182                 :            :    OPAQUE token, IS_COMPRESSION indicates if compressing or uncompressing.  */
     183                 :            : 
     184                 :            : static struct lto_compression_stream *
     185                 :     402166 : lto_new_compression_stream (void (*callback) (const char *, unsigned, void *),
     186                 :            :                             void *opaque, bool is_compression)
     187                 :            : {
     188                 :     402166 :   struct lto_compression_stream *stream
     189                 :     402166 :     = (struct lto_compression_stream *) xmalloc (sizeof (*stream));
     190                 :            : 
     191                 :     402166 :   memset (stream, 0, sizeof (*stream));
     192                 :     402166 :   stream->callback = callback;
     193                 :     402166 :   stream->opaque = opaque;
     194                 :     402166 :   stream->is_compression = is_compression;
     195                 :            : 
     196                 :     402166 :   return stream;
     197                 :            : }
     198                 :            : 
     199                 :            : /* Append NUM_CHARS from address BASE to STREAM.  */
     200                 :            : 
     201                 :            : static void
     202                 :    1817020 : lto_append_to_compression_stream (struct lto_compression_stream *stream,
     203                 :            :                                   const char *base, size_t num_chars)
     204                 :            : {
     205                 :    1817020 :   size_t required = stream->bytes + num_chars;
     206                 :            : 
     207                 :    1817020 :   if (stream->allocation < required)
     208                 :            :     {
     209                 :     467390 :       if (stream->allocation == 0)
     210                 :     402166 :         stream->allocation = MIN_STREAM_ALLOCATION;
     211                 :     553650 :       while (stream->allocation < required)
     212                 :      86260 :         stream->allocation *= 2;
     213                 :            : 
     214                 :     467390 :       stream->buffer = (char *) xrealloc (stream->buffer, stream->allocation);
     215                 :            :     }
     216                 :            : 
     217                 :    1817020 :   memcpy (stream->buffer + stream->bytes, base, num_chars);
     218                 :    1817020 :   stream->bytes += num_chars;
     219                 :    1817020 : }
     220                 :            : 
     221                 :            : /* Return a new compression stream, with CALLBACK flush function passed
     222                 :            :    OPAQUE token.  */
     223                 :            : 
     224                 :            : struct lto_compression_stream *
     225                 :     240819 : lto_start_compression (void (*callback) (const char *, unsigned, void *),
     226                 :            :                        void *opaque)
     227                 :            : {
     228                 :     240819 :   return lto_new_compression_stream (callback, opaque, true);
     229                 :            : }
     230                 :            : 
     231                 :            : /* Append NUM_CHARS from address BASE to STREAM.  */
     232                 :            : 
     233                 :            : void
     234                 :    1655680 : lto_compress_block (struct lto_compression_stream *stream,
     235                 :            :                     const char *base, size_t num_chars)
     236                 :            : {
     237                 :    1655680 :   gcc_assert (stream->is_compression);
     238                 :            : 
     239                 :    1655680 :   lto_append_to_compression_stream (stream, base, num_chars);
     240                 :    1655680 :   lto_stats.num_output_il_bytes += num_chars;
     241                 :    1655680 : }
     242                 :            : 
     243                 :            : static void ATTRIBUTE_UNUSED
     244                 :          0 : lto_compression_zlib (struct lto_compression_stream *stream)
     245                 :            : {
     246                 :          0 :   unsigned char *cursor = (unsigned char *) stream->buffer;
     247                 :          0 :   size_t remaining = stream->bytes;
     248                 :          0 :   const size_t outbuf_length = Z_BUFFER_LENGTH;
     249                 :          0 :   unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length);
     250                 :          0 :   z_stream out_stream;
     251                 :          0 :   size_t compressed_bytes = 0;
     252                 :          0 :   int status;
     253                 :            : 
     254                 :          0 :   gcc_assert (stream->is_compression);
     255                 :            : 
     256                 :          0 :   timevar_push (TV_IPA_LTO_COMPRESS);
     257                 :            : 
     258                 :          0 :   out_stream.next_out = outbuf;
     259                 :          0 :   out_stream.avail_out = outbuf_length;
     260                 :          0 :   out_stream.next_in = cursor;
     261                 :          0 :   out_stream.avail_in = remaining;
     262                 :          0 :   out_stream.zalloc = lto_zalloc;
     263                 :          0 :   out_stream.zfree = lto_zfree;
     264                 :          0 :   out_stream.opaque = Z_NULL;
     265                 :            : 
     266                 :          0 :   status = deflateInit (&out_stream, lto_normalized_zlib_level ());
     267                 :          0 :   if (status != Z_OK)
     268                 :          0 :     internal_error ("compressed stream: %s", zError (status));
     269                 :            : 
     270                 :          0 :   do
     271                 :            :     {
     272                 :          0 :       size_t in_bytes, out_bytes;
     273                 :            : 
     274                 :          0 :       status = deflate (&out_stream, Z_FINISH);
     275                 :          0 :       if (status != Z_OK && status != Z_STREAM_END)
     276                 :          0 :         internal_error ("compressed stream: %s", zError (status));
     277                 :            : 
     278                 :          0 :       in_bytes = remaining - out_stream.avail_in;
     279                 :          0 :       out_bytes = outbuf_length - out_stream.avail_out;
     280                 :            : 
     281                 :          0 :       stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
     282                 :          0 :       lto_stats.num_compressed_il_bytes += out_bytes;
     283                 :          0 :       compressed_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                 :     240819 : lto_end_compression (struct lto_compression_stream *stream)
     306                 :            : {
     307                 :            : #ifdef HAVE_ZSTD_H
     308                 :     240819 :   lto_compression_zstd (stream);
     309                 :            : #else
     310                 :            :   lto_compression_zlib (stream);
     311                 :            : #endif
     312                 :     240819 : }
     313                 :            : 
     314                 :            : /* Return a new uncompression stream, with CALLBACK flush function passed
     315                 :            :    OPAQUE token.  */
     316                 :            : 
     317                 :            : struct lto_compression_stream *
     318                 :     161347 : lto_start_uncompression (void (*callback) (const char *, unsigned, void *),
     319                 :            :                          void *opaque)
     320                 :            : {
     321                 :     161347 :   return lto_new_compression_stream (callback, opaque, false);
     322                 :            : }
     323                 :            : 
     324                 :            : /* Append NUM_CHARS from address BASE to STREAM.  */
     325                 :            : 
     326                 :            : void
     327                 :     161347 : lto_uncompress_block (struct lto_compression_stream *stream,
     328                 :            :                       const char *base, size_t num_chars)
     329                 :            : {
     330                 :     161347 :   gcc_assert (!stream->is_compression);
     331                 :            : 
     332                 :     161347 :   lto_append_to_compression_stream (stream, base, num_chars);
     333                 :     161347 :   lto_stats.num_input_il_bytes += num_chars;
     334                 :     161347 : }
     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                 :          0 :   size_t uncompressed_bytes = 0;
     344                 :            : 
     345                 :          0 :   gcc_assert (!stream->is_compression);
     346                 :          0 :   timevar_push (TV_IPA_LTO_DECOMPRESS);
     347                 :            : 
     348                 :          0 :   while (remaining > 0)
     349                 :            :     {
     350                 :          0 :       z_stream in_stream;
     351                 :          0 :       size_t out_bytes;
     352                 :          0 :       int status;
     353                 :            : 
     354                 :          0 :       in_stream.next_out = outbuf;
     355                 :          0 :       in_stream.avail_out = outbuf_length;
     356                 :          0 :       in_stream.next_in = cursor;
     357                 :          0 :       in_stream.avail_in = remaining;
     358                 :          0 :       in_stream.zalloc = lto_zalloc;
     359                 :          0 :       in_stream.zfree = lto_zfree;
     360                 :          0 :       in_stream.opaque = Z_NULL;
     361                 :            : 
     362                 :          0 :       status = inflateInit (&in_stream);
     363                 :          0 :       if (status != Z_OK)
     364                 :          0 :         internal_error ("compressed stream: %s", zError (status));
     365                 :            : 
     366                 :          0 :       do
     367                 :            :         {
     368                 :          0 :           size_t in_bytes;
     369                 :            : 
     370                 :          0 :           status = inflate (&in_stream, Z_SYNC_FLUSH);
     371                 :          0 :           if (status != Z_OK && status != Z_STREAM_END)
     372                 :          0 :             internal_error ("compressed stream: %s", zError (status));
     373                 :            : 
     374                 :          0 :           in_bytes = remaining - in_stream.avail_in;
     375                 :          0 :           out_bytes = outbuf_length - in_stream.avail_out;
     376                 :            : 
     377                 :          0 :           stream->callback ((const char *) outbuf, out_bytes, stream->opaque);
     378                 :          0 :           lto_stats.num_uncompressed_il_bytes += out_bytes;
     379                 :          0 :           uncompressed_bytes += out_bytes;
     380                 :            : 
     381                 :          0 :           cursor += in_bytes;
     382                 :          0 :           remaining -= in_bytes;
     383                 :            : 
     384                 :          0 :           in_stream.next_out = outbuf;
     385                 :          0 :           in_stream.avail_out = outbuf_length;
     386                 :          0 :           in_stream.next_in = cursor;
     387                 :          0 :           in_stream.avail_in = remaining;
     388                 :            :         }
     389                 :          0 :       while (!(status == Z_STREAM_END && out_bytes == 0));
     390                 :            : 
     391                 :          0 :       status = inflateEnd (&in_stream);
     392                 :          0 :       if (status != Z_OK)
     393                 :          0 :         internal_error ("compressed stream: %s", zError (status));
     394                 :            :     }
     395                 :            : 
     396                 :          0 :   lto_destroy_compression_stream (stream);
     397                 :          0 :   free (outbuf);
     398                 :          0 :   timevar_pop (TV_IPA_LTO_DECOMPRESS);
     399                 :          0 : }
     400                 :            : 
     401                 :            : void
     402                 :     161347 : lto_end_uncompression (struct lto_compression_stream *stream,
     403                 :            :                        lto_compression compression)
     404                 :            : {
     405                 :            : #ifdef HAVE_ZSTD_H
     406                 :     161347 :   if (compression == ZSTD)
     407                 :            :     {
     408                 :     161347 :       lto_uncompression_zstd (stream);
     409                 :     161347 :       return;
     410                 :            :     }
     411                 :            : #endif
     412                 :          0 :   if (compression == ZSTD)
     413                 :            :     internal_error ("compiler does not support ZSTD LTO compression");
     414                 :            : 
     415                 :          0 :   lto_uncompression_zlib (stream);
     416                 :            : }

Generated by: LCOV version 1.0

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 --enable-host-shared. GCC test suite is run with the built compiler.