LCOV - code coverage report
Current view: top level - gcc - tree-streamer.c (source / functions) Hit Total Coverage
Test: gcc.info Lines: 164 171 95.9 %
Date: 2020-04-04 11:58:09 Functions: 12 12 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* Miscellaneous utilities for tree streaming.  Things that are used
       2                 :            :    in both input and output are here.
       3                 :            : 
       4                 :            :    Copyright (C) 2011-2020 Free Software Foundation, Inc.
       5                 :            :    Contributed by Diego Novillo <dnovillo@google.com>
       6                 :            : 
       7                 :            : This file is part of GCC.
       8                 :            : 
       9                 :            : GCC is free software; you can redistribute it and/or modify it under
      10                 :            : the terms of the GNU General Public License as published by the Free
      11                 :            : Software Foundation; either version 3, or (at your option) any later
      12                 :            : version.
      13                 :            : 
      14                 :            : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      15                 :            : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      16                 :            : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      17                 :            : for more details.
      18                 :            : 
      19                 :            : You should have received a copy of the GNU General Public License
      20                 :            : along with GCC; see the file COPYING3.  If not see
      21                 :            : <http://www.gnu.org/licenses/>.  */
      22                 :            : 
      23                 :            : #include "config.h"
      24                 :            : #include "system.h"
      25                 :            : #include "coretypes.h"
      26                 :            : #include "backend.h"
      27                 :            : #include "tree.h"
      28                 :            : #include "gimple.h"
      29                 :            : #include "tree-streamer.h"
      30                 :            : #include "cgraph.h"
      31                 :            : 
      32                 :            : /* Table indexed by machine_mode, used for 2 different purposes.
      33                 :            :    During streaming out we record there non-zero value for all modes
      34                 :            :    that were streamed out.
      35                 :            :    During streaming in, we translate the on the disk mode using this
      36                 :            :    table.  For normal LTO it is set to identity, for ACCEL_COMPILER
      37                 :            :    depending on the mode_table content.  */
      38                 :            : unsigned char streamer_mode_table[1 << 8];
      39                 :            : 
      40                 :            : /* Check that all the TS_* structures handled by the streamer_write_* and
      41                 :            :    streamer_read_* routines are exactly ALL the structures defined in
      42                 :            :    treestruct.def.  */
      43                 :            : 
      44                 :            : void
      45                 :      35823 : streamer_check_handled_ts_structures (void)
      46                 :            : {
      47                 :      35823 :   bool handled_p[LAST_TS_ENUM];
      48                 :      35823 :   unsigned i;
      49                 :            : 
      50                 :      35823 :   memset (&handled_p, 0, sizeof (handled_p));
      51                 :            : 
      52                 :            :   /* These are the TS_* structures that are either handled or
      53                 :            :      explicitly ignored by the streamer routines.  */
      54                 :      35823 :   handled_p[TS_BASE] = true;
      55                 :      35823 :   handled_p[TS_TYPED] = true;
      56                 :      35823 :   handled_p[TS_COMMON] = true;
      57                 :      35823 :   handled_p[TS_INT_CST] = true;
      58                 :      35823 :   handled_p[TS_POLY_INT_CST] = true;
      59                 :      35823 :   handled_p[TS_REAL_CST] = true;
      60                 :      35823 :   handled_p[TS_FIXED_CST] = true;
      61                 :      35823 :   handled_p[TS_VECTOR] = true;
      62                 :      35823 :   handled_p[TS_STRING] = true;
      63                 :      35823 :   handled_p[TS_COMPLEX] = true;
      64                 :      35823 :   handled_p[TS_IDENTIFIER] = true;
      65                 :      35823 :   handled_p[TS_DECL_MINIMAL] = true;
      66                 :      35823 :   handled_p[TS_DECL_COMMON] = true;
      67                 :      35823 :   handled_p[TS_DECL_WRTL] = true;
      68                 :      35823 :   handled_p[TS_DECL_NON_COMMON] = true;
      69                 :      35823 :   handled_p[TS_DECL_WITH_VIS] = true;
      70                 :      35823 :   handled_p[TS_FIELD_DECL] = true;
      71                 :      35823 :   handled_p[TS_VAR_DECL] = true;
      72                 :      35823 :   handled_p[TS_PARM_DECL] = true;
      73                 :      35823 :   handled_p[TS_LABEL_DECL] = true;
      74                 :      35823 :   handled_p[TS_RESULT_DECL] = true;
      75                 :      35823 :   handled_p[TS_CONST_DECL] = true;
      76                 :      35823 :   handled_p[TS_TYPE_DECL] = true;
      77                 :      35823 :   handled_p[TS_FUNCTION_DECL] = true;
      78                 :      35823 :   handled_p[TS_TYPE_COMMON] = true;
      79                 :      35823 :   handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
      80                 :      35823 :   handled_p[TS_TYPE_NON_COMMON] = true;
      81                 :      35823 :   handled_p[TS_LIST] = true;
      82                 :      35823 :   handled_p[TS_VEC] = true;
      83                 :      35823 :   handled_p[TS_EXP] = true;
      84                 :      35823 :   handled_p[TS_SSA_NAME] = true;
      85                 :      35823 :   handled_p[TS_BLOCK] = true;
      86                 :      35823 :   handled_p[TS_BINFO] = true;
      87                 :      35823 :   handled_p[TS_STATEMENT_LIST] = true;
      88                 :      35823 :   handled_p[TS_CONSTRUCTOR] = true;
      89                 :      35823 :   handled_p[TS_OMP_CLAUSE] = true;
      90                 :      35823 :   handled_p[TS_OPTIMIZATION] = true;
      91                 :      35823 :   handled_p[TS_TARGET_OPTION] = true;
      92                 :      35823 :   handled_p[TS_TRANSLATION_UNIT_DECL] = true;
      93                 :            : 
      94                 :            :   /* Anything not marked above will trigger the following assertion.
      95                 :            :      If this assertion triggers, it means that there is a new TS_*
      96                 :            :      structure that should be handled by the streamer.  */
      97                 :    1432920 :   for (i = 0; i < LAST_TS_ENUM; i++)
      98                 :    1397100 :     gcc_assert (handled_p[i]);
      99                 :      35823 : }
     100                 :            : 
     101                 :            : 
     102                 :            : /* Helper for streamer_tree_cache_insert_1.  Add T to CACHE->NODES at
     103                 :            :    slot IX.  */
     104                 :            : 
     105                 :            : static void
     106                 :   77575500 : streamer_tree_cache_add_to_node_array (struct streamer_tree_cache_d *cache,
     107                 :            :                                        unsigned ix, tree t, hashval_t hash)
     108                 :            : {
     109                 :            :   /* We're either replacing an old element or appending consecutively.  */
     110                 :   77575500 :   if (cache->nodes.exists ())
     111                 :            :     {
     112                 :   30626700 :       if (cache->nodes.length () == ix)
     113                 :   30489000 :         cache->nodes.safe_push (t);
     114                 :            :       else
     115                 :     137686 :         cache->nodes[ix] = t;
     116                 :            :     }
     117                 :   77575500 :   if (cache->hashes.exists ())
     118                 :            :     {
     119                 :   41319800 :       if (cache->hashes.length () == ix)
     120                 :   41319800 :         cache->hashes.safe_push (hash);
     121                 :            :       else
     122                 :          0 :         cache->hashes[ix] = hash;
     123                 :            :     }
     124                 :   77575500 : }
     125                 :            : 
     126                 :            : 
     127                 :            : /* Helper for streamer_tree_cache_insert and streamer_tree_cache_insert_at.
     128                 :            :    CACHE, T, and IX_P are as in streamer_tree_cache_insert.
     129                 :            : 
     130                 :            :    If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available
     131                 :            :    slot in the cache.  Otherwise, T is inserted at the position indicated
     132                 :            :    in *IX_P.
     133                 :            : 
     134                 :            :    If T already existed in CACHE, return true.  Otherwise,
     135                 :            :    return false.  */
     136                 :            : 
     137                 :            : static bool
     138                 :   46948800 : streamer_tree_cache_insert_1 (struct streamer_tree_cache_d *cache,
     139                 :            :                               tree t, hashval_t hash, unsigned *ix_p,
     140                 :            :                               bool insert_at_next_slot_p)
     141                 :            : {
     142                 :   46948800 :   bool existed_p;
     143                 :            : 
     144                 :   46948800 :   gcc_assert (t);
     145                 :            : 
     146                 :   46948800 :   unsigned int &ix = cache->node_map->get_or_insert (t, &existed_p);
     147                 :   46948800 :   if (!existed_p)
     148                 :            :     {
     149                 :            :       /* Determine the next slot to use in the cache.  */
     150                 :   30147200 :       if (insert_at_next_slot_p)
     151                 :    6271190 :         ix = cache->next_idx++;
     152                 :            :       else
     153                 :   23876000 :         ix = *ix_p;
     154                 :            : 
     155                 :   30147200 :       streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
     156                 :            :     }
     157                 :            :   else
     158                 :            :     {
     159                 :   16801600 :       if (!insert_at_next_slot_p && ix != *ix_p)
     160                 :            :         {
     161                 :            :           /* If the caller wants to insert T at a specific slot
     162                 :            :              location, and ENTRY->TO does not match *IX_P, add T to
     163                 :            :              the requested location slot.  */
     164                 :   16801600 :           ix = *ix_p;
     165                 :   16801600 :           streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
     166                 :            :         }
     167                 :            :     }
     168                 :            : 
     169                 :   46948800 :   if (ix_p)
     170                 :   46719000 :     *ix_p = ix;
     171                 :            : 
     172                 :   46948800 :   return existed_p;
     173                 :            : }
     174                 :            : 
     175                 :            : 
     176                 :            : /* Insert tree node T in CACHE.  If T already existed in the cache
     177                 :            :    return true.  Otherwise, return false.
     178                 :            : 
     179                 :            :    If IX_P is non-null, update it with the index into the cache where
     180                 :            :    T has been stored.  */
     181                 :            : 
     182                 :            : bool
     183                 :    6271190 : streamer_tree_cache_insert (struct streamer_tree_cache_d *cache, tree t,
     184                 :            :                             hashval_t hash, unsigned *ix_p)
     185                 :            : {
     186                 :    6271190 :   return streamer_tree_cache_insert_1 (cache, t, hash, ix_p, true);
     187                 :            : }
     188                 :            : 
     189                 :            : 
     190                 :            : /* Replace the tree node with T in CACHE at slot IX.  */
     191                 :            : 
     192                 :            : void
     193                 :     137686 : streamer_tree_cache_replace_tree (struct streamer_tree_cache_d *cache,
     194                 :            :                                   tree t, unsigned ix)
     195                 :            : {
     196                 :     137686 :   hashval_t hash = 0;
     197                 :     137686 :   if (cache->hashes.exists ())
     198                 :          0 :     hash = streamer_tree_cache_get_hash (cache, ix);
     199                 :     137686 :   if (!cache->node_map)
     200                 :     137686 :     streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
     201                 :            :   else
     202                 :          0 :     streamer_tree_cache_insert_1 (cache, t, hash, &ix, false);
     203                 :     137686 : }
     204                 :            : 
     205                 :            : 
     206                 :            : /* Appends tree node T to CACHE, even if T already existed in it.  */
     207                 :            : 
     208                 :            : void
     209                 :   71166600 : streamer_tree_cache_append (struct streamer_tree_cache_d *cache,
     210                 :            :                             tree t, hashval_t hash)
     211                 :            : {
     212                 :   71166600 :   unsigned ix = cache->next_idx++;
     213                 :   71166600 :   if (!cache->node_map)
     214                 :   30489000 :     streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
     215                 :            :   else
     216                 :   40677600 :     streamer_tree_cache_insert_1 (cache, t, hash, &ix, false);
     217                 :   71166600 : }
     218                 :            : 
     219                 :            : /* Return true if tree node T exists in CACHE, otherwise false.  If IX_P is
     220                 :            :    not NULL, write to *IX_P the index into the cache where T is stored
     221                 :            :    ((unsigned)-1 if T is not found).  */
     222                 :            : 
     223                 :            : bool
     224                 :   51191400 : streamer_tree_cache_lookup (struct streamer_tree_cache_d *cache, tree t,
     225                 :            :                             unsigned *ix_p)
     226                 :            : {
     227                 :   51191400 :   unsigned *slot;
     228                 :   51191400 :   bool retval;
     229                 :   51191400 :   unsigned ix;
     230                 :            : 
     231                 :   51191400 :   gcc_assert (t);
     232                 :            : 
     233                 :   51191400 :   slot = cache->node_map->get (t);
     234                 :   37050100 :   if (slot == NULL)
     235                 :            :     {
     236                 :            :       retval = false;
     237                 :            :       ix = -1;
     238                 :            :     }
     239                 :            :   else
     240                 :            :     {
     241                 :   37050100 :       retval = true;
     242                 :   37050100 :       ix = *slot;
     243                 :            :     }
     244                 :            : 
     245                 :   51191400 :   if (ix_p)
     246                 :   33354700 :     *ix_p = ix;
     247                 :            : 
     248                 :   51191400 :   return retval;
     249                 :            : }
     250                 :            : 
     251                 :            : 
     252                 :            : /* Verify that NODE is in CACHE.  */
     253                 :            : 
     254                 :            : static void
     255                 :    3312240 : verify_common_node_recorded (struct streamer_tree_cache_d *cache, tree node)
     256                 :            : {
     257                 :            :   /* Restrict this to flag_checking only because in general violating it is
     258                 :            :      harmless plus we never know what happens on all targets/frontend/flag(!)
     259                 :            :      combinations.  */
     260                 :    3312240 :   if (!flag_checking)
     261                 :            :     return;
     262                 :            : 
     263                 :    3312120 :   if (cache->node_map)
     264                 :    1989540 :     gcc_assert (streamer_tree_cache_lookup (cache, node, NULL));
     265                 :            :   else
     266                 :            :     {
     267                 :    1322580 :       bool found = false;
     268                 :    1322580 :       gcc_assert (cache->nodes.exists ());
     269                 :            :       /* Linear search...  */
     270                 :   72741700 :       for (unsigned i = 0; !found && i < cache->nodes.length (); ++i)
     271                 :   71419200 :         if (cache->nodes[i] == node)
     272                 :    1322580 :           found = true;
     273                 :    1322580 :       gcc_assert (found);
     274                 :            :     }
     275                 :            : }
     276                 :            : 
     277                 :            : 
     278                 :            : /* Record NODE in CACHE.  */
     279                 :            : 
     280                 :            : static void
     281                 :   62932600 : record_common_node (struct streamer_tree_cache_d *cache, tree node)
     282                 :            : {
     283                 :            :   /* If we recursively end up at nodes we do not want to preload simply don't.
     284                 :            :      ???  We'd want to verify that this doesn't happen, or alternatively
     285                 :            :      do not recurse at all.  */
     286                 :   67717000 :   if (node == char_type_node)
     287                 :            :     return;
     288                 :            : 
     289                 :   67717000 :   gcc_checking_assert (node != boolean_type_node
     290                 :            :                        && node != boolean_true_node
     291                 :            :                        && node != boolean_false_node);
     292                 :            : 
     293                 :            :   /* We have to make sure to fill exactly the same number of
     294                 :            :      elements for all frontends.  That can include NULL trees.
     295                 :            :      As our hash table can't deal with zero entries we'll simply stream
     296                 :            :      a random other tree.  A NULL tree never will be looked up so it
     297                 :            :      doesn't matter which tree we replace it with, just to be sure
     298                 :            :      use error_mark_node.  */
     299                 :   67717000 :   if (!node)
     300                 :    3680270 :     node = error_mark_node;
     301                 :            : 
     302                 :            :   /* ???  FIXME, devise a better hash value.  But the hash needs to be equal
     303                 :            :      for all frontend and lto1 invocations.  So just use the position
     304                 :            :      in the cache as hash value.  */
     305                 :   94756300 :   streamer_tree_cache_append (cache, node, cache->nodes.length ());
     306                 :            : 
     307                 :   67717000 :   switch (TREE_CODE (node))
     308                 :            :     {
     309                 :            :     case ERROR_MARK:
     310                 :            :     case FIELD_DECL:
     311                 :            :     case FIXED_POINT_TYPE:
     312                 :            :     case IDENTIFIER_NODE:
     313                 :            :     case INTEGER_CST:
     314                 :            :     case INTEGER_TYPE:
     315                 :            :     case REAL_TYPE:
     316                 :            :     case TREE_LIST:
     317                 :            :     case VOID_CST:
     318                 :            :     case VOID_TYPE:
     319                 :            :       /* No recursive trees.  */
     320                 :            :       break;
     321                 :    4784350 :     case ARRAY_TYPE:
     322                 :    4784350 :     case POINTER_TYPE:
     323                 :    4784350 :     case REFERENCE_TYPE:
     324                 :    4784350 :       record_common_node (cache, TREE_TYPE (node));
     325                 :    4784350 :       break;
     326                 :    3312240 :     case COMPLEX_TYPE:
     327                 :            :       /* Verify that a complex type's component type (node_type) has been
     328                 :            :          handled already (and we thus don't need to recurse here).  */
     329                 :    3312240 :       verify_common_node_recorded (cache, TREE_TYPE (node));
     330                 :    3312240 :       break;
     331                 :     368027 :     case RECORD_TYPE:
     332                 :            :       /* The FIELD_DECLs of structures should be shared, so that every
     333                 :            :          COMPONENT_REF uses the same tree node when referencing a field.
     334                 :            :          Pointer equality between FIELD_DECLs is used by the alias
     335                 :            :          machinery to compute overlapping component references (see
     336                 :            :          nonoverlapping_component_refs_p and
     337                 :            :          nonoverlapping_component_refs_of_decl_p).  */
     338                 :    1840140 :       for (tree f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
     339                 :    1472110 :         record_common_node (cache, f);
     340                 :            :       break;
     341                 :          0 :     default:
     342                 :            :       /* Unexpected tree code.  */
     343                 :          0 :       gcc_unreachable ();
     344                 :            :     }
     345                 :            : }
     346                 :            : 
     347                 :            : 
     348                 :            : /* Preload common nodes into CACHE and make sure they are merged
     349                 :            :    properly according to the gimple type table.  */
     350                 :            : 
     351                 :            : static void
     352                 :     368027 : preload_common_nodes (struct streamer_tree_cache_d *cache)
     353                 :            : {
     354                 :     368027 :   unsigned i;
     355                 :            : 
     356                 :    7360540 :   for (i = 0; i < itk_none; i++)
     357                 :            :     /* Skip itk_char.  char_type_node is dependent on -f[un]signed-char.  */
     358                 :    6992510 :     if (i != itk_char)
     359                 :    6624490 :       record_common_node (cache, integer_types[i]);
     360                 :            : 
     361                 :    1840140 :   for (i = 0; i < stk_type_kind_last; i++)
     362                 :    1472110 :     record_common_node (cache, sizetype_tab[i]);
     363                 :            : 
     364                 :   58516300 :   for (i = 0; i < TI_MAX; i++)
     365                 :            :     /* Skip boolean type and constants, they are frontend dependent.  */
     366                 :   58148300 :     if (i != TI_BOOLEAN_TYPE
     367                 :   58148300 :         && i != TI_BOOLEAN_FALSE
     368                 :   57412200 :         && i != TI_BOOLEAN_TRUE
     369                 :            :         /* MAIN_IDENTIFIER is not always initialized by Fortran FE.  */
     370                 :   57412200 :         && i != TI_MAIN_IDENTIFIER
     371                 :            :         /* PID_TYPE is initialized only by C family front-ends.  */
     372                 :   56676200 :         && i != TI_PID_TYPE
     373                 :            :         /* Skip optimization and target option nodes; they depend on flags.  */
     374                 :   56676200 :         && i != TI_OPTIMIZATION_DEFAULT
     375                 :            :         && i != TI_OPTIMIZATION_CURRENT
     376                 :   55940100 :         && i != TI_TARGET_OPTION_DEFAULT
     377                 :            :         && i != TI_TARGET_OPTION_CURRENT
     378                 :   55204000 :         && i != TI_CURRENT_TARGET_PRAGMA
     379                 :            :         && i != TI_CURRENT_OPTIMIZE_PRAGMA
     380                 :            :         /* SCEV state shouldn't reach the IL.  */
     381                 :   54468000 :         && i != TI_CHREC_DONT_KNOW
     382                 :   53731900 :         && i != TI_CHREC_KNOWN
     383                 :            :         /* Skip va_list* related nodes if offloading.  For native LTO
     384                 :            :            we want them to be merged for the stdarg pass, for offloading
     385                 :            :            they might not be identical between host and offloading target.  */
     386                 :   53363900 :         && (!lto_stream_offload_p
     387                 :          0 :             || (i != TI_VA_LIST_TYPE
     388                 :            :                 && i != TI_VA_LIST_GPR_COUNTER_FIELD
     389                 :          0 :                 && i != TI_VA_LIST_FPR_COUNTER_FIELD)))
     390                 :   53363900 :       record_common_node (cache, global_trees[i]);
     391                 :     368027 : }
     392                 :            : 
     393                 :            : 
     394                 :            : /* Create a cache of pickled nodes.  */
     395                 :            : 
     396                 :            : struct streamer_tree_cache_d *
     397                 :     368027 : streamer_tree_cache_create (bool with_hashes, bool with_map, bool with_vec)
     398                 :            : {
     399                 :     368027 :   struct streamer_tree_cache_d *cache;
     400                 :            : 
     401                 :     368027 :   cache = XCNEW (struct streamer_tree_cache_d);
     402                 :            : 
     403                 :     368027 :   if (with_map)
     404                 :     221074 :     cache->node_map = new hash_map<tree, unsigned> (251);
     405                 :     368027 :   cache->next_idx = 0;
     406                 :     368027 :   if (with_vec)
     407                 :     146953 :     cache->nodes.create (165);
     408                 :     368027 :   if (with_hashes)
     409                 :     193737 :     cache->hashes.create (165);
     410                 :            : 
     411                 :            :   /* Load all the well-known tree nodes that are always created by
     412                 :            :      the compiler on startup.  This prevents writing them out
     413                 :            :      unnecessarily.  */
     414                 :     368027 :   preload_common_nodes (cache);
     415                 :            : 
     416                 :     368027 :   return cache;
     417                 :            : }
     418                 :            : 
     419                 :            : 
     420                 :            : /* Delete the streamer cache C.  */
     421                 :            : 
     422                 :            : void
     423                 :     368027 : streamer_tree_cache_delete (struct streamer_tree_cache_d *c)
     424                 :            : {
     425                 :     368027 :   if (c == NULL)
     426                 :            :     return;
     427                 :            : 
     428                 :     589101 :   delete c->node_map;
     429                 :     368027 :   c->node_map = NULL;
     430                 :     368027 :   c->nodes.release ();
     431                 :     368027 :   c->hashes.release ();
     432                 :     368027 :   free (c);
     433                 :            : }

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.