LCOV - code coverage report
Current view: top level - gcc - tree-streamer.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.8 % 168 161
Test Date: 2024-04-20 14:03:02 Functions: 100.0 % 12 12
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-2024 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[MAX_MACHINE_MODE];
      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                 :       51113 : streamer_check_handled_ts_structures (void)
      46                 :             : {
      47                 :       51113 :   bool handled_p[LAST_TS_ENUM];
      48                 :       51113 :   unsigned i;
      49                 :             : 
      50                 :       51113 :   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                 :       51113 :   handled_p[TS_BASE] = true;
      55                 :       51113 :   handled_p[TS_TYPED] = true;
      56                 :       51113 :   handled_p[TS_COMMON] = true;
      57                 :       51113 :   handled_p[TS_INT_CST] = true;
      58                 :       51113 :   handled_p[TS_POLY_INT_CST] = true;
      59                 :       51113 :   handled_p[TS_REAL_CST] = true;
      60                 :       51113 :   handled_p[TS_FIXED_CST] = true;
      61                 :       51113 :   handled_p[TS_VECTOR] = true;
      62                 :       51113 :   handled_p[TS_STRING] = true;
      63                 :       51113 :   handled_p[TS_COMPLEX] = true;
      64                 :       51113 :   handled_p[TS_IDENTIFIER] = true;
      65                 :       51113 :   handled_p[TS_DECL_MINIMAL] = true;
      66                 :       51113 :   handled_p[TS_DECL_COMMON] = true;
      67                 :       51113 :   handled_p[TS_DECL_WRTL] = true;
      68                 :       51113 :   handled_p[TS_DECL_NON_COMMON] = true;
      69                 :       51113 :   handled_p[TS_DECL_WITH_VIS] = true;
      70                 :       51113 :   handled_p[TS_FIELD_DECL] = true;
      71                 :       51113 :   handled_p[TS_VAR_DECL] = true;
      72                 :       51113 :   handled_p[TS_PARM_DECL] = true;
      73                 :       51113 :   handled_p[TS_LABEL_DECL] = true;
      74                 :       51113 :   handled_p[TS_RESULT_DECL] = true;
      75                 :       51113 :   handled_p[TS_CONST_DECL] = true;
      76                 :       51113 :   handled_p[TS_TYPE_DECL] = true;
      77                 :       51113 :   handled_p[TS_FUNCTION_DECL] = true;
      78                 :       51113 :   handled_p[TS_TYPE_COMMON] = true;
      79                 :       51113 :   handled_p[TS_TYPE_WITH_LANG_SPECIFIC] = true;
      80                 :       51113 :   handled_p[TS_TYPE_NON_COMMON] = true;
      81                 :       51113 :   handled_p[TS_LIST] = true;
      82                 :       51113 :   handled_p[TS_VEC] = true;
      83                 :       51113 :   handled_p[TS_EXP] = true;
      84                 :       51113 :   handled_p[TS_SSA_NAME] = true;
      85                 :       51113 :   handled_p[TS_BLOCK] = true;
      86                 :       51113 :   handled_p[TS_BINFO] = true;
      87                 :       51113 :   handled_p[TS_STATEMENT_LIST] = true;
      88                 :       51113 :   handled_p[TS_CONSTRUCTOR] = true;
      89                 :       51113 :   handled_p[TS_OMP_CLAUSE] = true;
      90                 :       51113 :   handled_p[TS_OPTIMIZATION] = true;
      91                 :       51113 :   handled_p[TS_TARGET_OPTION] = true;
      92                 :       51113 :   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                 :     2044520 :   for (i = 0; i < LAST_TS_ENUM; i++)
      98                 :     1993407 :     gcc_assert (handled_p[i]);
      99                 :       51113 : }
     100                 :             : 
     101                 :             : 
     102                 :             : /* Helper for streamer_tree_cache_insert_1.  Add T to CACHE->NODES at
     103                 :             :    slot IX.  */
     104                 :             : 
     105                 :             : static void
     106                 :   106498167 : 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                 :   106498167 :   if (cache->nodes.exists ())
     111                 :             :     {
     112                 :    41365816 :       if (cache->nodes.length () == ix)
     113                 :    41214645 :         cache->nodes.safe_push (t);
     114                 :             :       else
     115                 :      151171 :         cache->nodes[ix] = t;
     116                 :             :     }
     117                 :   106498167 :   if (cache->hashes.exists ())
     118                 :             :     {
     119                 :    55516023 :       if (cache->hashes.length () == ix)
     120                 :    55516023 :         cache->hashes.safe_push (hash);
     121                 :             :       else
     122                 :           0 :         cache->hashes[ix] = hash;
     123                 :             :     }
     124                 :   106498167 : }
     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                 :    65132351 : 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                 :    65132351 :   bool existed_p;
     143                 :             : 
     144                 :    65132351 :   gcc_assert (t);
     145                 :             : 
     146                 :    65132351 :   unsigned int &ix = cache->node_map->get_or_insert (t, &existed_p);
     147                 :    65132351 :   if (!existed_p)
     148                 :             :     {
     149                 :             :       /* Determine the next slot to use in the cache.  */
     150                 :    41714360 :       if (insert_at_next_slot_p)
     151                 :     7820551 :         ix = cache->next_idx++;
     152                 :             :       else
     153                 :    33893809 :         ix = *ix_p;
     154                 :             : 
     155                 :    41714360 :       streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
     156                 :             :     }
     157                 :             :   else
     158                 :             :     {
     159                 :    23417991 :       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                 :    23417991 :           ix = *ix_p;
     165                 :    23417991 :           streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
     166                 :             :         }
     167                 :             :     }
     168                 :             : 
     169                 :    65132351 :   if (ix_p)
     170                 :    64879248 :     *ix_p = ix;
     171                 :             : 
     172                 :    65132351 :   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                 :     7820551 : streamer_tree_cache_insert (struct streamer_tree_cache_d *cache, tree t,
     184                 :             :                             hashval_t hash, unsigned *ix_p)
     185                 :             : {
     186                 :     7820551 :   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                 :      151171 : streamer_tree_cache_replace_tree (struct streamer_tree_cache_d *cache,
     194                 :             :                                   tree t, unsigned ix)
     195                 :             : {
     196                 :      151171 :   hashval_t hash = 0;
     197                 :      151171 :   if (cache->hashes.exists ())
     198                 :           0 :     hash = streamer_tree_cache_get_hash (cache, ix);
     199                 :      151171 :   if (!cache->node_map)
     200                 :      151171 :     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                 :      151171 : }
     204                 :             : 
     205                 :             : 
     206                 :             : /* Appends tree node T to CACHE, even if T already existed in it.  */
     207                 :             : 
     208                 :             : void
     209                 :    98526445 : streamer_tree_cache_append (struct streamer_tree_cache_d *cache,
     210                 :             :                             tree t, hashval_t hash)
     211                 :             : {
     212                 :    98526445 :   unsigned ix = cache->next_idx++;
     213                 :    98526445 :   if (!cache->node_map)
     214                 :    41214645 :     streamer_tree_cache_add_to_node_array (cache, ix, t, hash);
     215                 :             :   else
     216                 :    57311800 :     streamer_tree_cache_insert_1 (cache, t, hash, &ix, false);
     217                 :    98526445 : }
     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                 :    58112785 : streamer_tree_cache_lookup (struct streamer_tree_cache_d *cache, tree t,
     225                 :             :                             unsigned *ix_p)
     226                 :             : {
     227                 :    58112785 :   unsigned *slot;
     228                 :    58112785 :   bool retval;
     229                 :    58112785 :   unsigned ix;
     230                 :             : 
     231                 :    58112785 :   gcc_assert (t);
     232                 :             : 
     233                 :    58112785 :   slot = cache->node_map->get (t);
     234                 :    58112785 :   if (slot == NULL)
     235                 :             :     {
     236                 :             :       retval = false;
     237                 :             :       ix = -1;
     238                 :             :     }
     239                 :             :   else
     240                 :             :     {
     241                 :    38038900 :       retval = true;
     242                 :    38038900 :       ix = *slot;
     243                 :             :     }
     244                 :             : 
     245                 :    58112785 :   if (ix_p)
     246                 :    36239726 :     *ix_p = ix;
     247                 :             : 
     248                 :    58112785 :   return retval;
     249                 :             : }
     250                 :             : 
     251                 :             : 
     252                 :             : /* Verify that NODE is in CACHE.  */
     253                 :             : 
     254                 :             : static void
     255                 :     4986860 : 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                 :     4986860 :   if (!flag_checking)
     261                 :             :     return;
     262                 :             : 
     263                 :     4986450 :   if (cache->node_map)
     264                 :     3048090 :     gcc_assert (streamer_tree_cache_lookup (cache, node, NULL));
     265                 :             :   else
     266                 :             :     {
     267                 :     1938360 :       bool found = false;
     268                 :     1938360 :       gcc_assert (cache->nodes.exists ());
     269                 :             :       /* Linear search...  */
     270                 :   110486520 :       for (unsigned i = 0; !found && i < cache->nodes.length (); ++i)
     271                 :   108548160 :         if (cache->nodes[i] == node)
     272                 :     1938360 :           found = true;
     273                 :     1938360 :       gcc_assert (found);
     274                 :             :     }
     275                 :             : }
     276                 :             : 
     277                 :             : 
     278                 :             : /* Record NODE in CACHE.  */
     279                 :             : 
     280                 :             : static void
     281                 :    87270050 : 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                 :    93752968 :   if (node == char_type_node)
     287                 :             :     return;
     288                 :             : 
     289                 :    93752968 :   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                 :    93752968 :   if (!node)
     300                 :     4488174 :     node = error_mark_node;
     301                 :             : 
     302                 :             :   /* This hash needs to be equal for all frontend and lto1 invocations.  So
     303                 :             :      just use the position in the cache as hash value.
     304                 :             :      Small integers are used by hash_tree to record positions within scc
     305                 :             :      hash. Values are not in same range.  */
     306                 :    93752968 :   streamer_tree_cache_append (cache, node, cache->next_idx + 0xc001);
     307                 :             : 
     308                 :    93752968 :   switch (TREE_CODE (node))
     309                 :             :     {
     310                 :             :     case ERROR_MARK:
     311                 :             :     case FIELD_DECL:
     312                 :             :     case FIXED_POINT_TYPE:
     313                 :             :     case IDENTIFIER_NODE:
     314                 :             :     case INTEGER_CST:
     315                 :             :     case INTEGER_TYPE:
     316                 :             :     case REAL_TYPE:
     317                 :             :     case TREE_LIST:
     318                 :             :     case VOID_CST:
     319                 :             :     case VOID_TYPE:
     320                 :             :     case OPAQUE_TYPE:
     321                 :             :       /* No recursive trees.  */
     322                 :             :       break;
     323                 :     6482918 :     case ARRAY_TYPE:
     324                 :     6482918 :     case POINTER_TYPE:
     325                 :     6482918 :     case REFERENCE_TYPE:
     326                 :     6482918 :       record_common_node (cache, TREE_TYPE (node));
     327                 :     6482918 :       break;
     328                 :     4986860 :     case COMPLEX_TYPE:
     329                 :             :       /* Verify that a complex type's component type (node_type) has been
     330                 :             :          handled already (and we thus don't need to recurse here).  */
     331                 :     4986860 :       verify_common_node_recorded (cache, TREE_TYPE (node));
     332                 :     4986860 :       break;
     333                 :      498686 :     case RECORD_TYPE:
     334                 :             :       /* The FIELD_DECLs of structures should be shared, so that every
     335                 :             :          COMPONENT_REF uses the same tree node when referencing a field.
     336                 :             :          Pointer equality between FIELD_DECLs is used by the alias
     337                 :             :          machinery to compute overlapping component references (see
     338                 :             :          nonoverlapping_component_refs_p and
     339                 :             :          nonoverlapping_component_refs_of_decl_p).  */
     340                 :     2493430 :       for (tree f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
     341                 :     1994744 :         record_common_node (cache, f);
     342                 :             :       break;
     343                 :           0 :     default:
     344                 :             :       /* Unexpected tree code.  */
     345                 :           0 :       gcc_unreachable ();
     346                 :             :     }
     347                 :             : }
     348                 :             : 
     349                 :             : 
     350                 :             : /* Preload common nodes into CACHE and make sure they are merged
     351                 :             :    properly according to the gimple type table.  */
     352                 :             : 
     353                 :             : static void
     354                 :      498686 : preload_common_nodes (struct streamer_tree_cache_d *cache)
     355                 :             : {
     356                 :      498686 :   unsigned i;
     357                 :             : 
     358                 :     9973720 :   for (i = 0; i < itk_none; i++)
     359                 :             :     /* Skip itk_char.  char_type_node is dependent on -f[un]signed-char.  */
     360                 :     9475034 :     if (i != itk_char)
     361                 :     8976348 :       record_common_node (cache, integer_types[i]);
     362                 :             : 
     363                 :     2493430 :   for (i = 0; i < stk_type_kind_last; i++)
     364                 :     1994744 :     record_common_node (cache, sizetype_tab[i]);
     365                 :             : 
     366                 :    81285818 :   for (i = 0; i < TI_MAX; i++)
     367                 :             :     /* Skip boolean type and constants, they are frontend dependent.  */
     368                 :    80787132 :     if (i != TI_BOOLEAN_TYPE
     369                 :    80787132 :         && i != TI_BOOLEAN_FALSE
     370                 :    79789760 :         && i != TI_BOOLEAN_TRUE
     371                 :             :         /* MAIN_IDENTIFIER is not always initialized by Fortran FE.  */
     372                 :    79789760 :         && i != TI_MAIN_IDENTIFIER
     373                 :             :         /* PID_TYPE is initialized only by C family front-ends.  */
     374                 :    78792388 :         && i != TI_PID_TYPE
     375                 :             :         /* Skip optimization and target option nodes; they depend on flags.  */
     376                 :    78792388 :         && i != TI_OPTIMIZATION_DEFAULT
     377                 :             :         && i != TI_OPTIMIZATION_CURRENT
     378                 :    77795016 :         && i != TI_TARGET_OPTION_DEFAULT
     379                 :             :         && i != TI_TARGET_OPTION_CURRENT
     380                 :             :         && i != TI_CURRENT_TARGET_PRAGMA
     381                 :             :         && i != TI_CURRENT_OPTIMIZE_PRAGMA
     382                 :             :         /* SCEV state shouldn't reach the IL.  */
     383                 :             :         && i != TI_CHREC_DONT_KNOW
     384                 :             :         && i != TI_CHREC_KNOWN
     385                 :             :         /* Skip va_list* related nodes if offloading.  For native LTO
     386                 :             :            we want them to be merged for the stdarg pass, for offloading
     387                 :             :            they might not be identical between host and offloading target.  */
     388                 :    74304214 :         && (!lto_stream_offload_p
     389                 :           0 :             || (i != TI_VA_LIST_TYPE
     390                 :             :                 && i != TI_VA_LIST_GPR_COUNTER_FIELD
     391                 :           0 :                 && i != TI_VA_LIST_FPR_COUNTER_FIELD)))
     392                 :    74304214 :       record_common_node (cache, global_trees[i]);
     393                 :      498686 : }
     394                 :             : 
     395                 :             : 
     396                 :             : /* Create a cache of pickled nodes.  */
     397                 :             : 
     398                 :             : struct streamer_tree_cache_d *
     399                 :      498686 : streamer_tree_cache_create (bool with_hashes, bool with_map, bool with_vec)
     400                 :             : {
     401                 :      498686 :   struct streamer_tree_cache_d *cache;
     402                 :             : 
     403                 :      498686 :   cache = XCNEW (struct streamer_tree_cache_d);
     404                 :             : 
     405                 :      498686 :   if (with_map)
     406                 :      304850 :     cache->node_map = new hash_map<tree, unsigned> (251);
     407                 :      498686 :   cache->next_idx = 0;
     408                 :      498686 :   if (with_vec)
     409                 :      193836 :     cache->nodes.create (165);
     410                 :      498686 :   if (with_hashes)
     411                 :      257771 :     cache->hashes.create (165);
     412                 :             : 
     413                 :             :   /* Load all the well-known tree nodes that are always created by
     414                 :             :      the compiler on startup.  This prevents writing them out
     415                 :             :      unnecessarily.  */
     416                 :      498686 :   preload_common_nodes (cache);
     417                 :             : 
     418                 :      498686 :   return cache;
     419                 :             : }
     420                 :             : 
     421                 :             : 
     422                 :             : /* Delete the streamer cache C.  */
     423                 :             : 
     424                 :             : void
     425                 :      498686 : streamer_tree_cache_delete (struct streamer_tree_cache_d *c)
     426                 :             : {
     427                 :      498686 :   if (c == NULL)
     428                 :             :     return;
     429                 :             : 
     430                 :      803536 :   delete c->node_map;
     431                 :      498686 :   c->node_map = NULL;
     432                 :      498686 :   c->nodes.release ();
     433                 :      498686 :   c->hashes.release ();
     434                 :      498686 :   free (c);
     435                 :             : }
        

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.