LCOV - code coverage report
Current view: top level - gcc - regstat.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 79.6 % 206 164
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Scanning of rtl for dataflow analysis.
       2              :    Copyright (C) 2007-2026 Free Software Foundation, Inc.
       3              :    Contributed by Kenneth Zadeck (zadeck@naturalbridge.com).
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it under
       8              : the terms of the GNU General Public License as published by the Free
       9              : Software Foundation; either version 3, or (at your option) any later
      10              : version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15              : for more details.
      16              : 
      17              : You should have received a copy of the GNU General Public License
      18              : along with GCC; see the file COPYING3.  If not see
      19              : <http://www.gnu.org/licenses/>.  */
      20              : 
      21              : 
      22              : #include "config.h"
      23              : #include "system.h"
      24              : #include "coretypes.h"
      25              : #include "backend.h"
      26              : #include "rtl.h"
      27              : #include "predict.h"
      28              : #include "df.h"
      29              : #include "regs.h"
      30              : 
      31              : 
      32              : struct regstat_n_sets_and_refs_t *regstat_n_sets_and_refs;
      33              : 
      34              : /*----------------------------------------------------------------------------
      35              :    REG_N_SETS and REG_N_REFS.
      36              :    ----------------------------------------------------------------------------*/
      37              : 
      38              : /* If a pass need to change these values in some magical way or the
      39              :    pass needs to have accurate values for these and is not using
      40              :    incremental df scanning, then it should use REG_N_SETS and
      41              :    REG_N_USES.  If the pass is doing incremental scanning then it
      42              :    should be getting the info from DF_REG_DEF_COUNT and
      43              :    DF_REG_USE_COUNT.  */
      44              : 
      45              : void
      46      3660838 : regstat_init_n_sets_and_refs (void)
      47              : {
      48      3660838 :   unsigned int i;
      49      3660838 :   unsigned int max_regno = max_reg_num ();
      50              : 
      51      3660838 :   timevar_push (TV_REG_STATS);
      52      3660838 :   df_grow_reg_info ();
      53      3660838 :   gcc_assert (!regstat_n_sets_and_refs);
      54              : 
      55      3660838 :   regstat_n_sets_and_refs = XNEWVEC (struct regstat_n_sets_and_refs_t, max_regno);
      56              : 
      57      3660838 :   if (MAY_HAVE_DEBUG_BIND_INSNS)
      58    243538761 :     for (i = 0; i < max_regno; i++)
      59              :       {
      60    241984605 :         int use_count;
      61    241984605 :         df_ref use;
      62              : 
      63    241984605 :         use_count = DF_REG_USE_COUNT (i);
      64    556142172 :         for (use = DF_REG_USE_CHAIN (i); use; use = DF_REF_NEXT_REG (use))
      65    314157567 :           if (DF_REF_INSN_INFO (use) && DEBUG_INSN_P (DF_REF_INSN (use)))
      66     35440006 :             use_count--;
      67              : 
      68              : 
      69    241984605 :         SET_REG_N_SETS (i, DF_REG_DEF_COUNT (i));
      70    241984605 :         SET_REG_N_REFS (i, use_count + REG_N_SETS (i));
      71              :       }
      72              :   else
      73    283210099 :     for (i = 0; i < max_regno; i++)
      74              :       {
      75    281103417 :         SET_REG_N_SETS (i, DF_REG_DEF_COUNT (i));
      76    281103417 :         SET_REG_N_REFS (i, DF_REG_USE_COUNT (i) + REG_N_SETS (i));
      77              :       }
      78      3660838 :   timevar_pop (TV_REG_STATS);
      79              : 
      80      3660838 : }
      81              : 
      82              : 
      83              : /* Free the array that holds the REG_N_SETS and REG_N_REFS.  */
      84              : 
      85              : void
      86      3660838 : regstat_free_n_sets_and_refs (void)
      87              : {
      88      3660838 :   gcc_assert (regstat_n_sets_and_refs);
      89      3660838 :   free (regstat_n_sets_and_refs);
      90      3660838 :   regstat_n_sets_and_refs = NULL;
      91      3660838 : }
      92              : 
      93              : 
      94              : /*----------------------------------------------------------------------------
      95              :    REGISTER INFORMATION
      96              : 
      97              :    Process REG_N_DEATHS, REG_N_CALLS_CROSSED, and REG_BASIC_BLOCK.
      98              : 
      99              :    ----------------------------------------------------------------------------*/
     100              : 
     101              : static bitmap setjmp_crosses;
     102              : struct reg_info_t *reg_info_p;
     103              : 
     104              : /* The number allocated elements of reg_info_p.  */
     105              : size_t reg_info_p_size;
     106              : 
     107              : /* Compute register info: lifetime, bb, and number of defs and uses
     108              :    for basic block BB.  LIVE is a scratch bitvector used here.  */
     109              : 
     110              : static void
     111     29807352 : regstat_bb_compute_ri (basic_block bb, bitmap live)
     112              : {
     113     29807352 :   rtx_insn *insn;
     114     29807352 :   df_ref def, use;
     115     29807352 :   bitmap_iterator bi;
     116     29807352 :   unsigned int regno;
     117              : 
     118     29807352 :   bitmap_copy (live, df_get_live_out (bb));
     119              : 
     120              :   /* Process the regs live at the end of the block.  Mark them as
     121              :      not local to any one basic block.  */
     122    426009100 :   EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
     123    396201748 :     REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
     124              : 
     125              :   /* Process the artificial defs and uses at the bottom of the block
     126              :      to begin processing.  */
     127     60500037 :   FOR_EACH_ARTIFICIAL_DEF (def, bb->index)
     128       885333 :     if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0)
     129            0 :       bitmap_clear_bit (live, DF_REF_REGNO (def));
     130              : 
     131    178844112 :   FOR_EACH_ARTIFICIAL_USE (use, bb->index)
     132    119229408 :     if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == 0)
     133              :       {
     134    119229408 :         regno = DF_REF_REGNO (use);
     135    119229408 :         bitmap_set_bit (live, regno);
     136              :       }
     137              : 
     138    370367565 :   FOR_BB_INSNS_REVERSE (bb, insn)
     139              :     {
     140    340560213 :       struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
     141    340560213 :       bitmap_iterator bi;
     142    340560213 :       rtx link;
     143              : 
     144    340560213 :       if (!NONDEBUG_INSN_P (insn))
     145    173199490 :         continue;
     146              : 
     147    167360723 :       link = REG_NOTES (insn);
     148    346487260 :       while (link)
     149              :         {
     150    179126537 :           if (REG_NOTE_KIND (link) == REG_DEAD)
     151     99022575 :             REG_N_DEATHS (REGNO (XEXP (link, 0)))++;
     152    179126537 :           link = XEXP (link, 1);
     153              :         }
     154              : 
     155              :       /* Process the defs.  */
     156    167360723 :       if (CALL_P (insn))
     157              :         {
     158     11814232 :           bool set_jump = (find_reg_note (insn, REG_SETJMP, NULL) != NULL);
     159    204712956 :           EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
     160              :             {
     161    192898724 :               REG_N_CALLS_CROSSED (regno)++;
     162              : 
     163              :               /* We have a problem with any pseudoreg that lives
     164              :                  across the setjmp.  ANSI says that if a user variable
     165              :                  does not change in value between the setjmp and the
     166              :                  longjmp, then the longjmp preserves it.  This
     167              :                  includes longjmp from a place where the pseudo
     168              :                  appears dead.  (In principle, the value still exists
     169              :                  if it is in scope.)  If the pseudo goes in a hard
     170              :                  reg, some other value may occupy that hard reg where
     171              :                  this pseudo is dead, thus clobbering the pseudo.
     172              :                  Conclusion: such a pseudo must not go in a hard
     173              :                  reg.  */
     174    192898724 :               if (set_jump)
     175        11559 :                 bitmap_set_bit (setjmp_crosses, regno);
     176              :             }
     177              :         }
     178              : 
     179              :       /* All of the defs except the return value are some sort of
     180              :          clobber.  This code is for the return.  */
     181   1272767832 :       FOR_EACH_INSN_INFO_DEF (def, insn_info)
     182              :         {
     183   1105407109 :           if ((!CALL_P (insn))
     184    968937718 :               || (!(DF_REF_FLAGS (def)
     185              :                     & (DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))))
     186              :             {
     187    142019255 :               unsigned int dregno = DF_REF_REGNO (def);
     188              : 
     189              :               /* Kill this register if it is not a subreg store or
     190              :                  conditional store.
     191              :                  ??? This means that any partial store is live from
     192              :                  the last use in a basic block to the start of this
     193              :                  basic block.  */
     194    142019255 :               if (!(DF_REF_FLAGS (def)
     195              :                     & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
     196    141354732 :                 bitmap_clear_bit (live, dregno);
     197              : 
     198    142019255 :               if (dregno >= FIRST_PSEUDO_REGISTER)
     199              :                 {
     200     68755466 :                   REG_FREQ (dregno) += REG_FREQ_FROM_BB (bb);
     201     68755466 :                   REG_FREQ (dregno) =
     202     68755466 :                     MIN (REG_FREQ (dregno), REG_FREQ_MAX);
     203              : 
     204     68755466 :                   if (REG_BASIC_BLOCK (dregno) == REG_BLOCK_UNKNOWN)
     205       900691 :                     REG_BASIC_BLOCK (dregno) = bb->index;
     206     67854775 :                   else if (REG_BASIC_BLOCK (dregno) != bb->index)
     207     25859064 :                     REG_BASIC_BLOCK (dregno) = REG_BLOCK_GLOBAL;
     208              :                 }
     209              :             }
     210              :         }
     211              : 
     212    373024869 :       FOR_EACH_INSN_INFO_USE (use, insn_info)
     213              :         {
     214    205664146 :           unsigned int uregno = DF_REF_REGNO (use);
     215              : 
     216    205664146 :           if (uregno >= FIRST_PSEUDO_REGISTER)
     217              :             {
     218    107581117 :               REG_FREQ (uregno) += REG_FREQ_FROM_BB (bb);
     219    107581117 :               REG_FREQ (uregno) =
     220    107581117 :                 MIN (REG_FREQ (uregno), REG_FREQ_MAX);
     221              : 
     222    107581117 :               if (REG_BASIC_BLOCK (uregno) == REG_BLOCK_UNKNOWN)
     223     40991675 :                 REG_BASIC_BLOCK (uregno) = bb->index;
     224     66589442 :               else if (REG_BASIC_BLOCK (uregno) != bb->index)
     225     57037485 :                 REG_BASIC_BLOCK (uregno) = REG_BLOCK_GLOBAL;
     226              :             }
     227              :         }
     228              :     }
     229     29807352 : }
     230              : 
     231              : 
     232              : /* Compute register info: lifetime, bb, and number of defs and uses.  */
     233              : void
     234      2587795 : regstat_compute_ri (void)
     235              : {
     236      2587795 :   basic_block bb;
     237      2587795 :   bitmap live = BITMAP_ALLOC (&df_bitmap_obstack);
     238      2587795 :   unsigned int regno;
     239      2587795 :   bitmap_iterator bi;
     240              : 
     241              :   /* Initialize everything.  */
     242              : 
     243      2587795 :   gcc_assert (!reg_info_p);
     244              : 
     245      2587795 :   timevar_push (TV_REG_STATS);
     246      2587795 :   setjmp_crosses = BITMAP_ALLOC (&df_bitmap_obstack);
     247      2587795 :   max_regno = max_reg_num ();
     248      2587795 :   reg_info_p_size = max_regno;
     249      2587795 :   reg_info_p = XCNEWVEC (struct reg_info_t, max_regno);
     250              : 
     251     32395147 :   FOR_EACH_BB_FN (bb, cfun)
     252              :     {
     253     29807352 :       regstat_bb_compute_ri (bb, live);
     254              :     }
     255              : 
     256      2587795 :   BITMAP_FREE (live);
     257              : 
     258              :   /* See the setjmp comment in regstat_bb_compute_ri.  */
     259      2589130 :   EXECUTE_IF_SET_IN_BITMAP (setjmp_crosses, FIRST_PSEUDO_REGISTER, regno, bi)
     260              :     {
     261         1335 :       REG_BASIC_BLOCK (regno) = REG_BLOCK_UNKNOWN;
     262              :     }
     263              : 
     264      2587795 :   timevar_pop (TV_REG_STATS);
     265      2587795 : }
     266              : 
     267              : 
     268              : /* Free all storage associated with the problem.  */
     269              : 
     270              : void
     271      2587795 : regstat_free_ri (void)
     272              : {
     273      2587795 :   gcc_assert (reg_info_p);
     274      2587795 :   reg_info_p_size = 0;
     275      2587795 :   free (reg_info_p);
     276      2587795 :   reg_info_p = NULL;
     277              : 
     278      2587795 :   BITMAP_FREE (setjmp_crosses);
     279      2587795 : }
     280              : 
     281              : 
     282              : /* Return a bitmap containing the set of registers that cross a setjmp.
     283              :    The client should not change or delete this bitmap.  */
     284              : 
     285              : bitmap
     286      1804209 : regstat_get_setjmp_crosses (void)
     287              : {
     288      1804209 :   return setjmp_crosses;
     289              : }
     290              : 
     291              : /*----------------------------------------------------------------------------
     292              :    Process REG_N_CALLS_CROSSED.
     293              : 
     294              :    This is used by sched_deps.  A good implementation of sched-deps
     295              :    would really process the blocks directly rather than going through
     296              :    lists of insns.  If it did this, it could use the exact regs that
     297              :    cross an individual call rather than using this info that merges
     298              :    the info for all calls.
     299              : 
     300              :    ----------------------------------------------------------------------------*/
     301              : 
     302              : 
     303              : 
     304              : /* Compute calls crossed for BB. Live is a scratch bitvector.  */
     305              : 
     306              : static void
     307     10333538 : regstat_bb_compute_calls_crossed (unsigned int bb_index, bitmap live)
     308              : {
     309     10333538 :   basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
     310     10333538 :   rtx_insn *insn;
     311     10333538 :   df_ref def, use;
     312              : 
     313     10333538 :   bitmap_copy (live, df_get_live_out (bb));
     314              : 
     315              :   /* Process the artificial defs and uses at the bottom of the block
     316              :      to begin processing.  */
     317     21029196 :   FOR_EACH_ARTIFICIAL_DEF (def, bb_index)
     318       362120 :     if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0)
     319            0 :       bitmap_clear_bit (live, DF_REF_REGNO (def));
     320              : 
     321     32396726 :   FOR_EACH_ARTIFICIAL_USE (use, bb_index)
     322     11729650 :     if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == 0)
     323     11729650 :       bitmap_set_bit (live, DF_REF_REGNO (use));
     324              : 
     325    142675418 :   FOR_BB_INSNS_REVERSE (bb, insn)
     326              :     {
     327    132341880 :       if (!NONDEBUG_INSN_P (insn))
     328     72198897 :         continue;
     329              : 
     330     60142983 :       gcc_assert (INSN_UID (insn) < (int) DF_INSN_SIZE ());
     331     60142983 :       struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
     332     60142983 :       unsigned int regno;
     333              : 
     334              :       /* Process the defs.  */
     335     60142983 :       if (CALL_P (insn))
     336              :         {
     337      4465858 :           bitmap_iterator bi;
     338     18750221 :           EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
     339              :             {
     340     14284363 :               REG_N_CALLS_CROSSED (regno)++;
     341              :             }
     342              :         }
     343              : 
     344              :       /* All of the defs except the return value are some sort of
     345              :          clobber.  This code is for the return.  */
     346    471066206 :       FOR_EACH_INSN_INFO_DEF (def, insn_info)
     347              :         {
     348    410923223 :           if ((!CALL_P (insn))
     349    363823881 :               || (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))))
     350              :             {
     351              :               /* Kill this register if it is not a subreg store or conditional store.  */
     352     49239457 :               if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
     353     49194515 :                 bitmap_clear_bit (live, DF_REF_REGNO (def));
     354              :             }
     355              :         }
     356              : 
     357    136808683 :       FOR_EACH_INSN_INFO_USE (use, insn_info)
     358     76665700 :         bitmap_set_bit (live, DF_REF_REGNO (use));
     359              :     }
     360     10333538 : }
     361              : 
     362              : 
     363              : /* Compute register info: lifetime, bb, and number of defs and uses.  */
     364              : void
     365       964480 : regstat_compute_calls_crossed (void)
     366              : {
     367       964480 :   basic_block bb;
     368       964480 :   bitmap live = BITMAP_ALLOC (&df_bitmap_obstack);
     369              : 
     370              :   /* Initialize everything.  */
     371       964480 :   gcc_assert (!reg_info_p);
     372              : 
     373       964480 :   timevar_push (TV_REG_STATS);
     374       964480 :   max_regno = max_reg_num ();
     375       964480 :   reg_info_p_size = max_regno;
     376       964480 :   reg_info_p = XCNEWVEC (struct reg_info_t, max_regno);
     377              : 
     378     11298018 :   FOR_EACH_BB_FN (bb, cfun)
     379              :     {
     380     10333538 :       regstat_bb_compute_calls_crossed (bb->index, live);
     381              :     }
     382              : 
     383       964480 :   BITMAP_FREE (live);
     384       964480 :   timevar_pop (TV_REG_STATS);
     385       964480 : }
     386              : 
     387              : 
     388              : /* Free all storage associated with the problem.  */
     389              : 
     390              : void
     391       964480 : regstat_free_calls_crossed (void)
     392              : {
     393       964480 :   gcc_assert (reg_info_p);
     394       964480 :   reg_info_p_size = 0;
     395       964480 :   free (reg_info_p);
     396       964480 :   reg_info_p = NULL;
     397       964480 : }
     398              : 
     399              : /* Dump the register info to FILE.  */
     400              : 
     401              : void
     402          119 : dump_reg_info (FILE *file)
     403              : {
     404          119 :   unsigned int i, max = max_reg_num ();
     405          119 :   if (reload_completed)
     406              :     return;
     407              : 
     408           85 :   if (reg_info_p_size < max)
     409           85 :     max = reg_info_p_size;
     410              : 
     411           85 :   fprintf (file, "%d registers.\n", max);
     412           85 :   for (i = FIRST_PSEUDO_REGISTER; i < max; i++)
     413              :     {
     414            0 :       enum reg_class rclass, altclass;
     415              : 
     416            0 :       if (regstat_n_sets_and_refs)
     417            0 :         fprintf (file, "\nRegister %d used %d times",
     418              :                  i, REG_N_REFS (i));
     419            0 :       else if (df)
     420            0 :         fprintf (file, "\nRegister %d used %d times",
     421            0 :                  i, DF_REG_USE_COUNT (i) + DF_REG_DEF_COUNT (i));
     422              : 
     423            0 :       if (REG_BASIC_BLOCK (i) >= NUM_FIXED_BLOCKS)
     424            0 :         fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
     425            0 :       if (regstat_n_sets_and_refs)
     426            0 :         fprintf (file, "; set %d time%s", REG_N_SETS (i),
     427            0 :                  (REG_N_SETS (i) == 1) ? "" : "s");
     428            0 :       else if (df)
     429            0 :         fprintf (file, "; set %d time%s", DF_REG_DEF_COUNT (i),
     430            0 :                  (DF_REG_DEF_COUNT (i) == 1) ? "" : "s");
     431            0 :       if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i]))
     432            0 :         fputs ("; user var", file);
     433            0 :       if (REG_N_DEATHS (i) != 1)
     434            0 :         fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
     435            0 :       if (REG_N_CALLS_CROSSED (i) == 1)
     436            0 :         fputs ("; crosses 1 call", file);
     437            0 :       else if (REG_N_CALLS_CROSSED (i))
     438            0 :         fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
     439            0 :       if (regno_reg_rtx[i] != NULL
     440            0 :           && maybe_ne (PSEUDO_REGNO_BYTES (i), UNITS_PER_WORD))
     441              :         {
     442            0 :           fprintf (file, "; ");
     443            0 :           print_dec (PSEUDO_REGNO_BYTES (i), file, SIGNED);
     444            0 :           fprintf (file, " bytes");
     445              :         }
     446              : 
     447            0 :       rclass = reg_preferred_class (i);
     448            0 :       altclass = reg_alternate_class (i);
     449            0 :       if (rclass != GENERAL_REGS || altclass != ALL_REGS)
     450              :         {
     451            0 :           if (altclass == ALL_REGS || rclass == ALL_REGS)
     452            0 :             fprintf (file, "; pref %s", reg_class_names[(int) rclass]);
     453            0 :           else if (altclass == NO_REGS)
     454            0 :             fprintf (file, "; %s or none", reg_class_names[(int) rclass]);
     455              :           else
     456            0 :             fprintf (file, "; pref %s, else %s",
     457            0 :                      reg_class_names[(int) rclass],
     458            0 :                      reg_class_names[(int) altclass]);
     459              :         }
     460              : 
     461            0 :       if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i]))
     462            0 :         fputs ("; pointer", file);
     463            0 :       fputs (".\n", file);
     464              :     }
     465              : }
     466              : 
        

Generated by: LCOV version 2.4-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.