Home | History | Annotate | Line # | Download | only in gcc
      1  1.1  mrg /* Routines for saving various data types to a file stream.  This deals
      2  1.1  mrg    with various data types like strings, integers, enums, etc.
      3  1.1  mrg 
      4  1.1  mrg    Copyright (C) 2011-2022 Free Software Foundation, Inc.
      5  1.1  mrg    Contributed by Diego Novillo <dnovillo (at) google.com>
      6  1.1  mrg 
      7  1.1  mrg This file is part of GCC.
      8  1.1  mrg 
      9  1.1  mrg GCC is free software; you can redistribute it and/or modify it under
     10  1.1  mrg the terms of the GNU General Public License as published by the Free
     11  1.1  mrg Software Foundation; either version 3, or (at your option) any later
     12  1.1  mrg version.
     13  1.1  mrg 
     14  1.1  mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     15  1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
     16  1.1  mrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     17  1.1  mrg for more details.
     18  1.1  mrg 
     19  1.1  mrg You should have received a copy of the GNU General Public License
     20  1.1  mrg along with GCC; see the file COPYING3.  If not see
     21  1.1  mrg <http://www.gnu.org/licenses/>.  */
     22  1.1  mrg 
     23  1.1  mrg #include "config.h"
     24  1.1  mrg #include "system.h"
     25  1.1  mrg #include "coretypes.h"
     26  1.1  mrg #include "backend.h"
     27  1.1  mrg #include "tree.h"
     28  1.1  mrg #include "gimple.h"
     29  1.1  mrg #include "cgraph.h"
     30  1.1  mrg #include "data-streamer.h"
     31  1.1  mrg 
     32  1.1  mrg 
     33  1.1  mrg /* Adds a new block to output stream OBS.  */
     34  1.1  mrg 
     35  1.1  mrg void
     36  1.1  mrg lto_append_block (struct lto_output_stream *obs)
     37  1.1  mrg {
     38  1.1  mrg   struct lto_char_ptr_base *new_block;
     39  1.1  mrg 
     40  1.1  mrg   gcc_assert (obs->left_in_block == 0);
     41  1.1  mrg 
     42  1.1  mrg   if (obs->first_block == NULL)
     43  1.1  mrg     {
     44  1.1  mrg       /* This is the first time the stream has been written
     45  1.1  mrg 	 into.  */
     46  1.1  mrg       obs->block_size = 1024;
     47  1.1  mrg       new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
     48  1.1  mrg       obs->first_block = new_block;
     49  1.1  mrg     }
     50  1.1  mrg   else
     51  1.1  mrg     {
     52  1.1  mrg       struct lto_char_ptr_base *tptr;
     53  1.1  mrg       /* Get a new block that is twice as big as the last block
     54  1.1  mrg 	 and link it into the list.  */
     55  1.1  mrg       obs->block_size *= 2;
     56  1.1  mrg       new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size);
     57  1.1  mrg       /* The first bytes of the block are reserved as a pointer to
     58  1.1  mrg 	 the next block.  Set the chain of the full block to the
     59  1.1  mrg 	 pointer to the new block.  */
     60  1.1  mrg       tptr = obs->current_block;
     61  1.1  mrg       tptr->ptr = (char *) new_block;
     62  1.1  mrg     }
     63  1.1  mrg 
     64  1.1  mrg   /* Set the place for the next char at the first position after the
     65  1.1  mrg      chain to the next block.  */
     66  1.1  mrg   obs->current_pointer
     67  1.1  mrg     = ((char *) new_block) + sizeof (struct lto_char_ptr_base);
     68  1.1  mrg   obs->current_block = new_block;
     69  1.1  mrg   /* Null out the newly allocated block's pointer to the next block.  */
     70  1.1  mrg   new_block->ptr = NULL;
     71  1.1  mrg   obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base);
     72  1.1  mrg }
     73  1.1  mrg 
     74  1.1  mrg 
     75  1.1  mrg /* Return index used to reference STRING of LEN characters in the string table
     76  1.1  mrg    in OB.  The string might or might not include a trailing '\0'.
     77  1.1  mrg    Then put the index onto the INDEX_STREAM.
     78  1.1  mrg    When PERSISTENT is set, the string S is supposed to not change during
     79  1.1  mrg    duration of the OB and thus OB can keep pointer into it.  */
     80  1.1  mrg 
     81  1.1  mrg static unsigned
     82  1.1  mrg streamer_string_index (struct output_block *ob, const char *s, unsigned int len,
     83  1.1  mrg 		       bool persistent)
     84  1.1  mrg {
     85  1.1  mrg   struct string_slot **slot;
     86  1.1  mrg   struct string_slot s_slot;
     87  1.1  mrg 
     88  1.1  mrg   s_slot.s = s;
     89  1.1  mrg   s_slot.len = len;
     90  1.1  mrg   s_slot.slot_num = 0;
     91  1.1  mrg 
     92  1.1  mrg   slot = ob->string_hash_table->find_slot (&s_slot, INSERT);
     93  1.1  mrg   if (*slot == NULL)
     94  1.1  mrg     {
     95  1.1  mrg       struct lto_output_stream *string_stream = ob->string_stream;
     96  1.1  mrg       unsigned int start = string_stream->total_size;
     97  1.1  mrg       struct string_slot *new_slot = XOBNEW (&ob->obstack, struct string_slot);
     98  1.1  mrg       const char *string;
     99  1.1  mrg 
    100  1.1  mrg       if (!persistent)
    101  1.1  mrg 	{
    102  1.1  mrg 	  char *tmp;
    103  1.1  mrg 	  string = tmp = XOBNEWVEC (&ob->obstack, char, len);
    104  1.1  mrg           memcpy (tmp, s, len);
    105  1.1  mrg         }
    106  1.1  mrg       else
    107  1.1  mrg 	string = s;
    108  1.1  mrg 
    109  1.1  mrg       new_slot->s = string;
    110  1.1  mrg       new_slot->len = len;
    111  1.1  mrg       new_slot->slot_num = start;
    112  1.1  mrg       *slot = new_slot;
    113  1.1  mrg       streamer_write_uhwi_stream (string_stream, len);
    114  1.1  mrg       streamer_write_data_stream (string_stream, string, len);
    115  1.1  mrg       return start + 1;
    116  1.1  mrg     }
    117  1.1  mrg   else
    118  1.1  mrg     {
    119  1.1  mrg       struct string_slot *old_slot = *slot;
    120  1.1  mrg       return old_slot->slot_num + 1;
    121  1.1  mrg     }
    122  1.1  mrg }
    123  1.1  mrg 
    124  1.1  mrg 
    125  1.1  mrg /* Output STRING of LEN characters to the string table in OB. The
    126  1.1  mrg    string might or might not include a trailing '\0'. Then put the
    127  1.1  mrg    index onto the INDEX_STREAM.
    128  1.1  mrg    When PERSISTENT is set, the string S is supposed to not change during
    129  1.1  mrg    duration of the OB and thus OB can keep pointer into it.  */
    130  1.1  mrg 
    131  1.1  mrg void
    132  1.1  mrg streamer_write_string_with_length (struct output_block *ob,
    133  1.1  mrg 				   struct lto_output_stream *index_stream,
    134  1.1  mrg 				   const char *s, unsigned int len,
    135  1.1  mrg 				   bool persistent)
    136  1.1  mrg {
    137  1.1  mrg   if (s)
    138  1.1  mrg     streamer_write_uhwi_stream (index_stream,
    139  1.1  mrg 			        streamer_string_index (ob, s, len, persistent));
    140  1.1  mrg   else
    141  1.1  mrg     streamer_write_char_stream (index_stream, 0);
    142  1.1  mrg }
    143  1.1  mrg 
    144  1.1  mrg 
    145  1.1  mrg /* Output the '\0' terminated STRING to the string
    146  1.1  mrg    table in OB.  Then put the index onto the INDEX_STREAM.
    147  1.1  mrg    When PERSISTENT is set, the string S is supposed to not change during
    148  1.1  mrg    duration of the OB and thus OB can keep pointer into it.  */
    149  1.1  mrg 
    150  1.1  mrg void
    151  1.1  mrg streamer_write_string (struct output_block *ob,
    152  1.1  mrg 		       struct lto_output_stream *index_stream,
    153  1.1  mrg 		       const char *string, bool persistent)
    154  1.1  mrg {
    155  1.1  mrg   if (string)
    156  1.1  mrg     streamer_write_string_with_length (ob, index_stream, string,
    157  1.1  mrg 				       strlen (string) + 1,
    158  1.1  mrg 				       persistent);
    159  1.1  mrg   else
    160  1.1  mrg     streamer_write_char_stream (index_stream, 0);
    161  1.1  mrg }
    162  1.1  mrg 
    163  1.1  mrg 
    164  1.1  mrg /* Output STRING of LEN characters to the string table in OB.  Then
    165  1.1  mrg    put the index into BP.
    166  1.1  mrg    When PERSISTENT is set, the string S is supposed to not change during
    167  1.1  mrg    duration of the OB and thus OB can keep pointer into it.  */
    168  1.1  mrg 
    169  1.1  mrg void
    170  1.1  mrg bp_pack_string_with_length (struct output_block *ob, struct bitpack_d *bp,
    171  1.1  mrg 			    const char *s, unsigned int len, bool persistent)
    172  1.1  mrg {
    173  1.1  mrg   unsigned index = 0;
    174  1.1  mrg   if (s)
    175  1.1  mrg     index = streamer_string_index (ob, s, len, persistent);
    176  1.1  mrg   bp_pack_var_len_unsigned (bp, index);
    177  1.1  mrg }
    178  1.1  mrg 
    179  1.1  mrg 
    180  1.1  mrg /* Output the '\0' terminated STRING to the string
    181  1.1  mrg    table in OB.  Then put the index onto the bitpack BP.
    182  1.1  mrg    When PERSISTENT is set, the string S is supposed to not change during
    183  1.1  mrg    duration of the OB and thus OB can keep pointer into it.  */
    184  1.1  mrg 
    185  1.1  mrg void
    186  1.1  mrg bp_pack_string (struct output_block *ob, struct bitpack_d *bp,
    187  1.1  mrg 		const char *s, bool persistent)
    188  1.1  mrg {
    189  1.1  mrg   unsigned index = 0;
    190  1.1  mrg   if (s)
    191  1.1  mrg     index = streamer_string_index (ob, s, strlen (s) + 1, persistent);
    192  1.1  mrg   bp_pack_var_len_unsigned (bp, index);
    193  1.1  mrg }
    194  1.1  mrg 
    195  1.1  mrg 
    196  1.1  mrg 
    197  1.1  mrg /* Write a zero to the output stream.  */
    198  1.1  mrg 
    199  1.1  mrg void
    200  1.1  mrg streamer_write_zero (struct output_block *ob)
    201  1.1  mrg {
    202  1.1  mrg   streamer_write_char_stream (ob->main_stream, 0);
    203  1.1  mrg }
    204  1.1  mrg 
    205  1.1  mrg 
    206  1.1  mrg /* Write an unsigned HOST_WIDE_INT value WORK to OB->main_stream.  */
    207  1.1  mrg 
    208  1.1  mrg void
    209  1.1  mrg streamer_write_uhwi (struct output_block *ob, unsigned HOST_WIDE_INT work)
    210  1.1  mrg {
    211  1.1  mrg   streamer_write_uhwi_stream (ob->main_stream, work);
    212  1.1  mrg }
    213  1.1  mrg 
    214  1.1  mrg 
    215  1.1  mrg /* Write a HOST_WIDE_INT value WORK to OB->main_stream.  */
    216  1.1  mrg 
    217  1.1  mrg void
    218  1.1  mrg streamer_write_hwi (struct output_block *ob, HOST_WIDE_INT work)
    219  1.1  mrg {
    220  1.1  mrg   streamer_write_hwi_stream (ob->main_stream, work);
    221  1.1  mrg }
    222  1.1  mrg 
    223  1.1  mrg /* Write a poly_uint64 value WORK to OB->main_stream.  */
    224  1.1  mrg 
    225  1.1  mrg void
    226  1.1  mrg streamer_write_poly_uint64 (struct output_block *ob, poly_uint64 work)
    227  1.1  mrg {
    228  1.1  mrg   for (int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
    229  1.1  mrg     streamer_write_uhwi_stream (ob->main_stream, work.coeffs[i]);
    230  1.1  mrg }
    231  1.1  mrg 
    232  1.1  mrg /* Write a poly_int64 value WORK to OB->main_stream.  */
    233  1.1  mrg 
    234  1.1  mrg void
    235  1.1  mrg streamer_write_poly_int64 (struct output_block *ob, poly_int64 work)
    236  1.1  mrg {
    237  1.1  mrg   for (int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
    238  1.1  mrg     streamer_write_hwi_stream (ob->main_stream, work.coeffs[i]);
    239  1.1  mrg }
    240  1.1  mrg 
    241  1.1  mrg /* Write a gcov counter value WORK to OB->main_stream.  */
    242  1.1  mrg 
    243  1.1  mrg void
    244  1.1  mrg streamer_write_gcov_count (struct output_block *ob, gcov_type work)
    245  1.1  mrg {
    246  1.1  mrg   streamer_write_gcov_count_stream (ob->main_stream, work);
    247  1.1  mrg }
    248  1.1  mrg 
    249  1.1  mrg /* Write an unsigned HOST_WIDE_INT value WORK to OBS.  */
    250  1.1  mrg 
    251  1.1  mrg void
    252  1.1  mrg streamer_write_uhwi_stream (struct lto_output_stream *obs,
    253  1.1  mrg                             unsigned HOST_WIDE_INT work)
    254  1.1  mrg {
    255  1.1  mrg   if (obs->left_in_block == 0)
    256  1.1  mrg     lto_append_block (obs);
    257  1.1  mrg   char *current_pointer = obs->current_pointer;
    258  1.1  mrg   unsigned int left_in_block = obs->left_in_block;
    259  1.1  mrg   unsigned int size = 0;
    260  1.1  mrg   do
    261  1.1  mrg     {
    262  1.1  mrg       unsigned int byte = (work & 0x7f);
    263  1.1  mrg       work >>= 7;
    264  1.1  mrg       if (work != 0)
    265  1.1  mrg 	/* More bytes to follow.  */
    266  1.1  mrg 	byte |= 0x80;
    267  1.1  mrg 
    268  1.1  mrg       *(current_pointer++) = byte;
    269  1.1  mrg       left_in_block--;
    270  1.1  mrg       size++;
    271  1.1  mrg     }
    272  1.1  mrg   while (work != 0 && left_in_block > 0);
    273  1.1  mrg   if (work != 0)
    274  1.1  mrg     {
    275  1.1  mrg       obs->left_in_block = 0;
    276  1.1  mrg       lto_append_block (obs);
    277  1.1  mrg       current_pointer = obs->current_pointer;
    278  1.1  mrg       left_in_block = obs->left_in_block;
    279  1.1  mrg       do
    280  1.1  mrg 	{
    281  1.1  mrg 	  unsigned int byte = (work & 0x7f);
    282  1.1  mrg 	  work >>= 7;
    283  1.1  mrg 	  if (work != 0)
    284  1.1  mrg 	    /* More bytes to follow.  */
    285  1.1  mrg 	    byte |= 0x80;
    286  1.1  mrg 
    287  1.1  mrg 	  *(current_pointer++) = byte;
    288  1.1  mrg 	  left_in_block--;
    289  1.1  mrg 	  size++;
    290  1.1  mrg 	}
    291  1.1  mrg       while (work != 0);
    292  1.1  mrg     }
    293  1.1  mrg   obs->current_pointer = current_pointer;
    294  1.1  mrg   obs->left_in_block = left_in_block;
    295  1.1  mrg   obs->total_size += size;
    296  1.1  mrg }
    297  1.1  mrg 
    298  1.1  mrg 
    299  1.1  mrg /* Write a HOST_WIDE_INT value WORK to OBS.  */
    300  1.1  mrg 
    301  1.1  mrg void
    302  1.1  mrg streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
    303  1.1  mrg {
    304  1.1  mrg   if (obs->left_in_block == 0)
    305  1.1  mrg     lto_append_block (obs);
    306  1.1  mrg   char *current_pointer = obs->current_pointer;
    307  1.1  mrg   unsigned int left_in_block = obs->left_in_block;
    308  1.1  mrg   unsigned int size = 0;
    309  1.1  mrg   bool more;
    310  1.1  mrg   do
    311  1.1  mrg     {
    312  1.1  mrg       unsigned int byte = (work & 0x7f);
    313  1.1  mrg       /* If the lower 7-bits are sign-extended 0 or -1 we are finished.  */
    314  1.1  mrg       work >>= 6;
    315  1.1  mrg       more = !(work == 0 || work == -1);
    316  1.1  mrg       if (more)
    317  1.1  mrg 	{
    318  1.1  mrg 	  /* More bits to follow.  */
    319  1.1  mrg 	  work >>= 1;
    320  1.1  mrg 	  byte |= 0x80;
    321  1.1  mrg 	}
    322  1.1  mrg 
    323  1.1  mrg       *(current_pointer++) = byte;
    324  1.1  mrg       left_in_block--;
    325  1.1  mrg       size++;
    326  1.1  mrg     }
    327  1.1  mrg   while (more && left_in_block > 0);
    328  1.1  mrg   if (more)
    329  1.1  mrg     {
    330  1.1  mrg       obs->left_in_block = 0;
    331  1.1  mrg       lto_append_block (obs);
    332  1.1  mrg       current_pointer = obs->current_pointer;
    333  1.1  mrg       left_in_block = obs->left_in_block;
    334  1.1  mrg       do
    335  1.1  mrg 	{
    336  1.1  mrg 	  unsigned int byte = (work & 0x7f);
    337  1.1  mrg 	  work >>= 6;
    338  1.1  mrg 	  more = !(work == 0 || work == -1);
    339  1.1  mrg 	  if (more)
    340  1.1  mrg 	    {
    341  1.1  mrg 	      work >>= 1;
    342  1.1  mrg 	      byte |= 0x80;
    343  1.1  mrg 	    }
    344  1.1  mrg 
    345  1.1  mrg 	  *(current_pointer++) = byte;
    346  1.1  mrg 	  left_in_block--;
    347  1.1  mrg 	  size++;
    348  1.1  mrg 	}
    349  1.1  mrg       while (more);
    350  1.1  mrg     }
    351  1.1  mrg   obs->current_pointer = current_pointer;
    352  1.1  mrg   obs->left_in_block = left_in_block;
    353  1.1  mrg   obs->total_size += size;
    354  1.1  mrg }
    355  1.1  mrg 
    356  1.1  mrg /* Write a GCOV counter value WORK to OBS.  */
    357  1.1  mrg 
    358  1.1  mrg void
    359  1.1  mrg streamer_write_gcov_count_stream (struct lto_output_stream *obs, gcov_type work)
    360  1.1  mrg {
    361  1.1  mrg   gcc_assert ((HOST_WIDE_INT) work == work);
    362  1.1  mrg   streamer_write_hwi_stream (obs, work);
    363  1.1  mrg }
    364  1.1  mrg 
    365  1.1  mrg /* Write raw DATA of length LEN to the output block OB.  */
    366  1.1  mrg 
    367  1.1  mrg void
    368  1.1  mrg streamer_write_data_stream (struct lto_output_stream *obs, const void *data,
    369  1.1  mrg 			    size_t len)
    370  1.1  mrg {
    371  1.1  mrg   while (len)
    372  1.1  mrg     {
    373  1.1  mrg       size_t copy;
    374  1.1  mrg 
    375  1.1  mrg       /* No space left.  */
    376  1.1  mrg       if (obs->left_in_block == 0)
    377  1.1  mrg 	lto_append_block (obs);
    378  1.1  mrg 
    379  1.1  mrg       /* Determine how many bytes to copy in this loop.  */
    380  1.1  mrg       if (len <= obs->left_in_block)
    381  1.1  mrg 	copy = len;
    382  1.1  mrg       else
    383  1.1  mrg 	copy = obs->left_in_block;
    384  1.1  mrg 
    385  1.1  mrg       /* Copy the data and do bookkeeping.  */
    386  1.1  mrg       memcpy (obs->current_pointer, data, copy);
    387  1.1  mrg       obs->current_pointer += copy;
    388  1.1  mrg       obs->total_size += copy;
    389  1.1  mrg       obs->left_in_block -= copy;
    390  1.1  mrg       data = (const char *) data + copy;
    391  1.1  mrg       len -= copy;
    392  1.1  mrg     }
    393  1.1  mrg }
    394  1.1  mrg 
    395  1.1  mrg /* Emit the physical representation of wide_int VAL to output block OB.  */
    396  1.1  mrg 
    397  1.1  mrg void
    398  1.1  mrg streamer_write_wide_int (struct output_block *ob, const wide_int &val)
    399  1.1  mrg {
    400  1.1  mrg   int len = val.get_len ();
    401  1.1  mrg 
    402  1.1  mrg   streamer_write_uhwi (ob, val.get_precision ());
    403  1.1  mrg   streamer_write_uhwi (ob, len);
    404  1.1  mrg   for (int i = 0; i < len; i++)
    405  1.1  mrg     streamer_write_hwi (ob, val.elt (i));
    406  1.1  mrg }
    407  1.1  mrg 
    408  1.1  mrg /* Emit the physical representation of widest_int W to output block OB.  */
    409  1.1  mrg 
    410  1.1  mrg void
    411  1.1  mrg streamer_write_widest_int (struct output_block *ob,
    412  1.1  mrg 			   const widest_int &w)
    413  1.1  mrg {
    414  1.1  mrg   int len = w.get_len ();
    415  1.1  mrg 
    416  1.1  mrg   streamer_write_uhwi (ob, w.get_precision ());
    417  1.1  mrg   streamer_write_uhwi (ob, len);
    418  1.1  mrg   for (int i = 0; i < len; i++)
    419  1.1  mrg     streamer_write_hwi (ob, w.elt (i));
    420  1.1  mrg }
    421  1.1  mrg 
    422