LCOV - code coverage report
Current view: top level - gcc - valtrack.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.9 % 351 326
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 16 16
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Infrastructure for tracking user variable locations and values
       2              :    throughout compilation.
       3              :    Copyright (C) 2010-2026 Free Software Foundation, Inc.
       4              :    Contributed by Alexandre Oliva <aoliva@redhat.com>.
       5              : 
       6              : This file is part of GCC.
       7              : 
       8              : GCC is free software; you can redistribute it and/or modify it under
       9              : the terms of the GNU General Public License as published by the Free
      10              : Software Foundation; either version 3, or (at your option) any later
      11              : version.
      12              : 
      13              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      14              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      15              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      16              : for more details.
      17              : 
      18              : You should have received a copy of the GNU General Public License
      19              : along with GCC; see the file COPYING3.  If not see
      20              : <http://www.gnu.org/licenses/>.  */
      21              : 
      22              : #include "config.h"
      23              : #include "system.h"
      24              : #include "coretypes.h"
      25              : #include "backend.h"
      26              : #include "rtl.h"
      27              : #include "df.h"
      28              : #include "valtrack.h"
      29              : #include "regs.h"
      30              : #include "memmodel.h"
      31              : #include "emit-rtl.h"
      32              : #include "rtl-iter.h"
      33              : 
      34              : /* gen_lowpart_no_emit hook implementation for DEBUG_INSNs.  In DEBUG_INSNs,
      35              :    all lowpart SUBREGs are valid, despite what the machine requires for
      36              :    instructions.  */
      37              : 
      38              : static rtx
      39          239 : gen_lowpart_for_debug (machine_mode mode, rtx x)
      40              : {
      41          239 :   rtx result = gen_lowpart_if_possible (mode, x);
      42          239 :   if (result)
      43              :     return result;
      44              : 
      45            5 :   if (GET_MODE (x) != VOIDmode)
      46            5 :     return gen_rtx_raw_SUBREG (mode, x,
      47              :                                subreg_lowpart_offset (mode, GET_MODE (x)));
      48              : 
      49              :   return NULL_RTX;
      50              : }
      51              : 
      52              : /* Replace auto-increment addressing modes with explicit operations to access
      53              :    the same addresses without modifying the corresponding registers.  */
      54              : 
      55              : static rtx
      56       976596 : cleanup_auto_inc_dec (rtx src, machine_mode mem_mode ATTRIBUTE_UNUSED)
      57              : {
      58       976596 :   rtx x = src;
      59              : 
      60       976596 :   const RTX_CODE code = GET_CODE (x);
      61       976596 :   int i;
      62       976596 :   const char *fmt;
      63              : 
      64       976596 :   switch (code)
      65              :     {
      66              :     case REG:
      67              :     CASE_CONST_ANY:
      68              :     case SYMBOL_REF:
      69              :     case CODE_LABEL:
      70              :     case PC:
      71              :     case SCRATCH:
      72              :       /* SCRATCH must be shared because they represent distinct values.  */
      73              :       return x;
      74            0 :     case CLOBBER:
      75              :       /* Share clobbers of hard registers, but do not share pseudo reg
      76              :          clobbers or clobbers of hard registers that originated as pseudos.
      77              :          This is needed to allow safe register renaming.  */
      78            0 :       if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
      79            0 :           && ORIGINAL_REGNO (XEXP (x, 0)) == REGNO (XEXP (x, 0)))
      80              :         return x;
      81              :       break;
      82              : 
      83         1658 :     case CONST:
      84         1658 :       if (shared_const_p (x))
      85              :         return x;
      86              :       break;
      87              : 
      88       100259 :     case MEM:
      89       100259 :       mem_mode = GET_MODE (x);
      90       100259 :       break;
      91              : 
      92            0 :     case PRE_INC:
      93            0 :     case PRE_DEC:
      94            0 :       {
      95            0 :         gcc_assert (mem_mode != VOIDmode && mem_mode != BLKmode);
      96            0 :         poly_int64 offset = GET_MODE_SIZE (mem_mode);
      97            0 :         if (code == PRE_DEC)
      98            0 :           offset = -offset;
      99            0 :         return gen_rtx_PLUS (GET_MODE (x),
     100              :                              cleanup_auto_inc_dec (XEXP (x, 0), mem_mode),
     101              :                              gen_int_mode (offset, GET_MODE (x)));
     102              :       }
     103              : 
     104            0 :     case POST_INC:
     105            0 :     case POST_DEC:
     106            0 :     case PRE_MODIFY:
     107            0 :     case POST_MODIFY:
     108            0 :       return cleanup_auto_inc_dec (code == PRE_MODIFY
     109              :                                    ? XEXP (x, 1) : XEXP (x, 0),
     110            0 :                                    mem_mode);
     111              : 
     112              :     default:
     113              :       break;
     114              :     }
     115              : 
     116              :   /* Copy the various flags, fields, and other information.  We assume
     117              :      that all fields need copying, and then clear the fields that should
     118              :      not be copied.  That is the sensible default behavior, and forces
     119              :      us to explicitly document why we are *not* copying a flag.  */
     120       325488 :   x = shallow_copy_rtx (x);
     121              : 
     122              :   /* We do not copy FRAME_RELATED for INSNs.  */
     123       325488 :   if (INSN_P (x))
     124            0 :     RTX_FLAG (x, frame_related) = 0;
     125              : 
     126       325488 :   fmt = GET_RTX_FORMAT (code);
     127       969601 :   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     128       644113 :     if (fmt[i] == 'e')
     129       532690 :       XEXP (x, i) = cleanup_auto_inc_dec (XEXP (x, i), mem_mode);
     130       111423 :     else if (fmt[i] == 'E' || fmt[i] == 'V')
     131              :       {
     132          438 :         int j;
     133          438 :         XVEC (x, i) = rtvec_alloc (XVECLEN (x, i));
     134          881 :         for (j = 0; j < XVECLEN (x, i); j++)
     135          443 :           XVECEXP (x, i, j)
     136          443 :             = cleanup_auto_inc_dec (XVECEXP (src, i, j), mem_mode);
     137              :       }
     138              : 
     139              :   return x;
     140              : }
     141              : 
     142              : /* Auxiliary data structure for propagate_for_debug_stmt.  */
     143              : 
     144              : struct rtx_subst_pair
     145              : {
     146              :   rtx to;
     147              :   bool adjusted;
     148              :   rtx_insn *insn;
     149              : };
     150              : 
     151              : /* DATA points to an rtx_subst_pair.  Return the value that should be
     152              :    substituted.  */
     153              : 
     154              : static rtx
     155      2916782 : propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
     156              : {
     157      2916782 :   struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data;
     158              : 
     159      2916782 :   if (!rtx_equal_p (from, old_rtx))
     160              :     return NULL_RTX;
     161       226691 :   if (!pair->adjusted)
     162              :     {
     163       182574 :       pair->adjusted = true;
     164       182574 :       pair->to = cleanup_auto_inc_dec (pair->to, VOIDmode);
     165       182574 :       pair->to = make_compound_operation (pair->to, SET);
     166              :       /* Avoid propagation from growing DEBUG_INSN expressions too much.  */
     167       182574 :       int cnt = 0;
     168       182574 :       subrtx_iterator::array_type array;
     169       569516 :       FOR_EACH_SUBRTX (iter, array, pair->to, ALL)
     170       407331 :         if (REG_P (*iter) && ++cnt > 1)
     171              :           {
     172        20389 :             rtx dval = make_debug_expr_from_rtl (old_rtx);
     173        20389 :             rtx to = pair->to;
     174        20389 :             if (volatile_insn_p (to))
     175            0 :               to = gen_rtx_UNKNOWN_VAR_LOC ();
     176              :             /* Emit a debug bind insn.  */
     177        20389 :             rtx bind
     178        20389 :               = gen_rtx_VAR_LOCATION (GET_MODE (old_rtx),
     179              :                                       DEBUG_EXPR_TREE_DECL (dval), to,
     180              :                                       VAR_INIT_STATUS_INITIALIZED);
     181        20389 :             rtx_insn *bind_insn = emit_debug_insn_before (bind, pair->insn);
     182        20389 :             df_insn_rescan (bind_insn);
     183        20389 :             pair->to = dval;
     184        20389 :             break;
     185              :           }
     186       182574 :       return pair->to;
     187       182574 :     }
     188        44117 :   return copy_rtx (pair->to);
     189              : }
     190              : 
     191              : /* Replace all the occurrences of DEST with SRC in DEBUG_INSNs between INSN
     192              :    and LAST, not including INSN, but including LAST.  Also stop at the end
     193              :    of THIS_BASIC_BLOCK.  */
     194              : 
     195              : void
     196      2187924 : propagate_for_debug (rtx_insn *insn, rtx_insn *last, rtx dest, rtx src,
     197              :                      basic_block this_basic_block)
     198              : {
     199      2187924 :   rtx_insn *next, *end = NEXT_INSN (BB_END (this_basic_block));
     200      2187924 :   rtx loc;
     201      2187924 :   rtx (*saved_rtl_hook_no_emit) (machine_mode, rtx);
     202              : 
     203      2187924 :   struct rtx_subst_pair p;
     204      2187924 :   p.to = src;
     205      2187924 :   p.adjusted = false;
     206      2187924 :   p.insn = NEXT_INSN (insn);
     207              : 
     208      2187924 :   next = NEXT_INSN (insn);
     209      2187924 :   last = NEXT_INSN (last);
     210      2187924 :   saved_rtl_hook_no_emit = rtl_hooks.gen_lowpart_no_emit;
     211      2187924 :   rtl_hooks.gen_lowpart_no_emit = gen_lowpart_for_debug;
     212      8477535 :   while (next != last && next != end)
     213              :     {
     214      6289611 :       insn = next;
     215      6289611 :       next = NEXT_INSN (insn);
     216      6289611 :       if (DEBUG_BIND_INSN_P (insn))
     217              :         {
     218      1642903 :           loc = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
     219              :                                          dest, propagate_for_debug_subst, &p);
     220      1642903 :           if (loc == INSN_VAR_LOCATION_LOC (insn))
     221      1416532 :             continue;
     222       226371 :           if (volatile_insn_p (loc))
     223            1 :             loc = gen_rtx_UNKNOWN_VAR_LOC ();
     224       226371 :           INSN_VAR_LOCATION_LOC (insn) = loc;
     225       226371 :           df_insn_rescan (insn);
     226              :         }
     227              :     }
     228      2187924 :   rtl_hooks.gen_lowpart_no_emit = saved_rtl_hook_no_emit;
     229      2187924 : }
     230              : 
     231              : /* Initialize DEBUG to an empty list, and clear USED, if given.  */
     232              : 
     233              : void
     234      9997933 : dead_debug_global_init (struct dead_debug_global *debug, bitmap used)
     235              : {
     236      9997933 :   debug->used = used;
     237      9997933 :   debug->htab = NULL;
     238      9997933 :   if (used)
     239            0 :     bitmap_clear (used);
     240      9997933 : }
     241              : 
     242              : /* Initialize DEBUG to an empty list, and clear USED, if given.  Link
     243              :    back to GLOBAL, if given, and bring in used bits from it.  */
     244              : 
     245              : void
     246    388133926 : dead_debug_local_init (struct dead_debug_local *debug, bitmap used,
     247              :                        struct dead_debug_global *global)
     248              : {
     249    388133926 :   if (!used && global && global->used)
     250      2738290 :     used = BITMAP_ALLOC (NULL);
     251              : 
     252    388133926 :   debug->head = NULL;
     253    388133926 :   debug->global = global;
     254    388133926 :   debug->used = used;
     255    388133926 :   debug->to_rescan = NULL;
     256              : 
     257    388133926 :   if (used)
     258              :     {
     259      2738290 :       if (global && global->used)
     260      2738290 :         bitmap_copy (used, global->used);
     261              :       else
     262            0 :         bitmap_clear (used);
     263              :     }
     264    388133926 : }
     265              : 
     266              : /* Locate the entry for REG in GLOBAL->htab.  */
     267              : 
     268              : static dead_debug_global_entry *
     269      1318955 : dead_debug_global_find (struct dead_debug_global *global, rtx reg)
     270              : {
     271      1318955 :   dead_debug_global_entry temp_entry;
     272      1318955 :   temp_entry.reg = reg;
     273              : 
     274      1318955 :   dead_debug_global_entry *entry = global->htab->find (&temp_entry);
     275      1318955 :   gcc_checking_assert (entry && entry->reg == temp_entry.reg);
     276              : 
     277      1318955 :   return entry;
     278              : }
     279              : 
     280              : /* Insert an entry mapping REG to DTEMP in GLOBAL->htab.  */
     281              : 
     282              : static dead_debug_global_entry *
     283       117484 : dead_debug_global_insert (struct dead_debug_global *global, rtx reg, rtx dtemp)
     284              : {
     285       117484 :   dead_debug_global_entry temp_entry;
     286       117484 :   temp_entry.reg = reg;
     287       117484 :   temp_entry.dtemp = dtemp;
     288              : 
     289       117484 :   if (!global->htab)
     290        64287 :     global->htab = new hash_table<dead_debug_hash_descr> (31);
     291              : 
     292       117484 :   dead_debug_global_entry **slot = global->htab->find_slot (&temp_entry,
     293              :                                                             INSERT);
     294       117484 :   gcc_checking_assert (!*slot);
     295       117484 :   *slot = XNEW (dead_debug_global_entry);
     296       117484 :   **slot = temp_entry;
     297       117484 :   return *slot;
     298              : }
     299              : 
     300              : /* If UREGNO, referenced by USE, is a pseudo marked as used in GLOBAL,
     301              :    replace it with a USE of the debug temp recorded for it, and
     302              :    return TRUE.  Otherwise, just return FALSE.
     303              : 
     304              :    If PTO_RESCAN is given, instead of rescanning modified INSNs right
     305              :    away, add their UIDs to the bitmap, allocating one of *PTO_RESCAN
     306              :    is NULL.  */
     307              : 
     308              : static bool
     309      1349471 : dead_debug_global_replace_temp (struct dead_debug_global *global,
     310              :                                 df_ref use, unsigned int uregno,
     311              :                                 bitmap *pto_rescan)
     312              : {
     313      1349471 :   if (!global || uregno < FIRST_PSEUDO_REGISTER
     314      1108390 :       || !global->used
     315       930589 :       || !REG_P (*DF_REF_REAL_LOC (use))
     316       930582 :       || REGNO (*DF_REF_REAL_LOC (use)) != uregno
     317      2280053 :       || !bitmap_bit_p (global->used, uregno))
     318       496962 :     return false;
     319              : 
     320       852509 :   dead_debug_global_entry *entry
     321       852509 :     = dead_debug_global_find (global, *DF_REF_REAL_LOC (use));
     322       852509 :   gcc_checking_assert (GET_CODE (entry->reg) == REG
     323              :                        && REGNO (entry->reg) == uregno);
     324              : 
     325       852509 :   if (!entry->dtemp)
     326              :     return true;
     327              : 
     328       852504 :   *DF_REF_REAL_LOC (use) = entry->dtemp;
     329       852504 :   if (!pto_rescan)
     330            0 :     df_insn_rescan (DF_REF_INSN (use));
     331              :   else
     332              :     {
     333       852504 :       if (!*pto_rescan)
     334            0 :         *pto_rescan = BITMAP_ALLOC (NULL);
     335       852504 :       bitmap_set_bit (*pto_rescan, INSN_UID (DF_REF_INSN (use)));
     336              :     }
     337              : 
     338              :   return true;
     339              : }
     340              : 
     341              : /* Reset all debug uses in HEAD, and clear DEBUG->to_rescan bits of
     342              :    each reset insn.  DEBUG is not otherwise modified.  If HEAD is
     343              :    DEBUG->head, DEBUG->head will be set to NULL at the end.
     344              :    Otherwise, entries from DEBUG->head that pertain to reset insns
     345              :    will be removed, and only then rescanned.  */
     346              : 
     347              : static void
     348    388138904 : dead_debug_reset_uses (struct dead_debug_local *debug,
     349              :                        struct dead_debug_use *head)
     350              : {
     351    388138904 :   bool got_head = (debug->head == head);
     352    388138904 :   bitmap rescan;
     353    388138904 :   struct dead_debug_use **tailp = &debug->head;
     354    388138904 :   struct dead_debug_use *cur;
     355    388138904 :   bitmap_iterator bi;
     356    388138904 :   unsigned int uid;
     357              : 
     358    388138904 :   if (got_head)
     359    388138904 :     rescan = NULL;
     360              :   else
     361         1366 :     rescan = BITMAP_ALLOC (NULL);
     362              : 
     363    388277066 :   while (head)
     364              :     {
     365       138162 :       struct dead_debug_use *next = head->next;
     366       138162 :       rtx_insn *insn;
     367              : 
     368       138162 :       insn = DF_REF_INSN (head->use);
     369       138162 :       if (!next || DF_REF_INSN (next->use) != insn)
     370              :         {
     371       135636 :           INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
     372       135636 :           if (got_head)
     373       134341 :             df_insn_rescan_debug_internal (insn);
     374              :           else
     375         1295 :             bitmap_set_bit (rescan, INSN_UID (insn));
     376       135636 :           if (debug->to_rescan)
     377         3165 :             bitmap_clear_bit (debug->to_rescan, INSN_UID (insn));
     378              :         }
     379       138162 :       XDELETE (head);
     380       138162 :       head = next;
     381              :     }
     382              : 
     383    388138904 :   if (got_head)
     384              :     {
     385    388137538 :       debug->head = NULL;
     386    388137538 :       return;
     387              :     }
     388              : 
     389         1811 :   while ((cur = *tailp))
     390          445 :     if (bitmap_bit_p (rescan, INSN_UID (DF_REF_INSN (cur->use))))
     391              :       {
     392           24 :         *tailp = cur->next;
     393           24 :         XDELETE (cur);
     394              :       }
     395              :     else
     396          421 :       tailp = &cur->next;
     397              : 
     398         2661 :   EXECUTE_IF_SET_IN_BITMAP (rescan, 0, uid, bi)
     399              :     {
     400         1295 :       struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid);
     401         1295 :       if (insn_info)
     402         1295 :         df_insn_rescan_debug_internal (insn_info->insn);
     403              :     }
     404              : 
     405         1366 :   BITMAP_FREE (rescan);
     406              : }
     407              : 
     408              : /* Promote pending local uses of pseudos in DEBUG to global
     409              :    substitutions.  Uses of non-pseudos are left alone for
     410              :    resetting.  */
     411              : 
     412              : static void
     413    175595205 : dead_debug_promote_uses (struct dead_debug_local *debug)
     414              : {
     415    175595205 :   for (struct dead_debug_use *head = debug->head, **headp = &debug->head;
     416    175715757 :        head; head = *headp)
     417              :     {
     418       120552 :       rtx reg = *DF_REF_REAL_LOC (head->use);
     419       120552 :       df_ref ref;
     420       120552 :       dead_debug_global_entry *entry;
     421              : 
     422       123620 :       if (GET_CODE (reg) != REG
     423       120552 :           || REGNO (reg) < FIRST_PSEUDO_REGISTER)
     424              :         {
     425         3068 :           headp = &head->next;
     426         3068 :           continue;
     427              :         }
     428              : 
     429       117484 :       if (!debug->global->used)
     430        64287 :         debug->global->used = BITMAP_ALLOC (NULL);
     431              : 
     432       117484 :       bool added = bitmap_set_bit (debug->global->used, REGNO (reg));
     433       117484 :       gcc_checking_assert (added);
     434              : 
     435       117484 :       entry = dead_debug_global_insert (debug->global, reg,
     436              :                                         make_debug_expr_from_rtl (reg));
     437              : 
     438       117484 :       gcc_checking_assert (entry->dtemp);
     439              : 
     440              :       /* Tentatively remove the USE from the list.  */
     441       117484 :       *headp = head->next;
     442              : 
     443       117484 :       if (!debug->to_rescan)
     444       100958 :         debug->to_rescan = BITMAP_ALLOC (NULL);
     445              : 
     446      1640052 :       for (ref = DF_REG_USE_CHAIN (REGNO (reg)); ref;
     447      1522568 :            ref = DF_REF_NEXT_REG (ref))
     448      1522568 :         if (DEBUG_INSN_P (DF_REF_INSN (ref)))
     449              :           {
     450       852511 :             if (!dead_debug_global_replace_temp (debug->global, ref,
     451              :                                                  REGNO (reg),
     452              :                                                  &debug->to_rescan))
     453              :               {
     454            7 :                 rtx_insn *insn = DF_REF_INSN (ref);
     455            7 :                 INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
     456            7 :                 bitmap_set_bit (debug->to_rescan, INSN_UID (insn));
     457              :               }
     458              :           }
     459              : 
     460       361881 :       for (ref = DF_REG_DEF_CHAIN (REGNO (reg)); ref;
     461       244397 :            ref = DF_REF_NEXT_REG (ref))
     462       244397 :         if (!dead_debug_insert_temp (debug, REGNO (reg), DF_REF_INSN (ref),
     463              :                                      DEBUG_TEMP_BEFORE_WITH_VALUE))
     464              :           {
     465         3777 :             rtx bind;
     466         3777 :             bind = gen_rtx_VAR_LOCATION (GET_MODE (reg),
     467         3777 :                                          DEBUG_EXPR_TREE_DECL (entry->dtemp),
     468              :                                          gen_rtx_UNKNOWN_VAR_LOC (),
     469              :                                          VAR_INIT_STATUS_INITIALIZED);
     470         3777 :             rtx_insn *insn = emit_debug_insn_before (bind, DF_REF_INSN (ref));
     471         3777 :             bitmap_set_bit (debug->to_rescan, INSN_UID (insn));
     472              :           }
     473              : 
     474       117484 :       entry->dtemp = NULL;
     475       117484 :       XDELETE (head);
     476              :     }
     477    175595205 : }
     478              : 
     479              : /* Reset all debug insns with pending uses.  Release the bitmap in it,
     480              :    unless it is USED.  USED must be the same bitmap passed to
     481              :    dead_debug_local_init.  */
     482              : 
     483              : void
     484    388133926 : dead_debug_local_finish (struct dead_debug_local *debug, bitmap used)
     485              : {
     486    388133926 :   if (debug->global)
     487    175595205 :     dead_debug_promote_uses (debug);
     488              : 
     489    388133926 :   if (debug->used != used)
     490      2984882 :     BITMAP_FREE (debug->used);
     491              : 
     492    388133926 :   dead_debug_reset_uses (debug, debug->head);
     493              : 
     494    388133926 :   if (debug->to_rescan)
     495              :     {
     496       191562 :       bitmap_iterator bi;
     497       191562 :       unsigned int uid;
     498              : 
     499      1550439 :       EXECUTE_IF_SET_IN_BITMAP (debug->to_rescan, 0, uid, bi)
     500              :         {
     501      1358877 :           struct df_insn_info *insn_info = DF_INSN_UID_SAFE_GET (uid);
     502      1358877 :           if (insn_info)
     503      1358877 :             df_insn_rescan (insn_info->insn);
     504              :         }
     505       191562 :       BITMAP_FREE (debug->to_rescan);
     506              :     }
     507    388133926 : }
     508              : 
     509              : /* Release GLOBAL->used unless it is the same as USED.  Release the
     510              :    mapping hash table if it was initialized.  */
     511              : 
     512              : void
     513      9997933 : dead_debug_global_finish (struct dead_debug_global *global, bitmap used)
     514              : {
     515      9997933 :   if (global->used != used)
     516        64287 :     BITMAP_FREE (global->used);
     517              : 
     518      9997933 :   delete global->htab;
     519      9997933 :   global->htab = NULL;
     520      9997933 : }
     521              : 
     522              : /* Add USE to DEBUG, or substitute it right away if it's a pseudo in
     523              :    the global substitution list.  USE must be a dead reference to
     524              :    UREGNO in a debug insn.  Create a bitmap for DEBUG as needed.  */
     525              : 
     526              : void
     527       496960 : dead_debug_add (struct dead_debug_local *debug, df_ref use, unsigned int uregno)
     528              : {
     529       496960 :   if (dead_debug_global_replace_temp (debug->global, use, uregno,
     530              :                                       &debug->to_rescan))
     531              :     return;
     532              : 
     533       496955 :   struct dead_debug_use *newddu = XNEW (struct dead_debug_use);
     534              : 
     535       496955 :   newddu->use = use;
     536       496955 :   newddu->next = debug->head;
     537       496955 :   debug->head = newddu;
     538              : 
     539       496955 :   if (!debug->used)
     540       246592 :     debug->used = BITMAP_ALLOC (NULL);
     541              : 
     542              :   /* ??? If we dealt with split multi-registers below, we should set
     543              :      all registers for the used mode in case of hardware
     544              :      registers.  */
     545       496955 :   bitmap_set_bit (debug->used, uregno);
     546              : }
     547              : 
     548              : /* Like lowpart_subreg, but if a subreg is not valid for machine, force
     549              :    it anyway - for use in debug insns.  */
     550              : 
     551              : static rtx
     552         1566 : debug_lowpart_subreg (machine_mode outer_mode, rtx expr,
     553              :                       machine_mode inner_mode)
     554              : {
     555         1566 :   if (inner_mode == VOIDmode)
     556            0 :     inner_mode = GET_MODE (expr);
     557         1566 :   poly_int64 offset = subreg_lowpart_offset (outer_mode, inner_mode);
     558         1566 :   rtx ret = simplify_gen_subreg (outer_mode, expr, inner_mode, offset);
     559         1566 :   if (ret)
     560              :     return ret;
     561            5 :   if (GET_MODE (expr) != VOIDmode)
     562            3 :     return gen_rtx_raw_SUBREG (outer_mode, expr, offset);
     563              :   return NULL_RTX;
     564              : }
     565              : 
     566              : /* If UREGNO is referenced by any entry in DEBUG, emit a debug insn
     567              :    before or after INSN (depending on WHERE), that binds a (possibly
     568              :    global) debug temp to the widest-mode use of UREGNO, if WHERE is
     569              :    *_WITH_REG, or the value stored in UREGNO by INSN otherwise, and
     570              :    replace all uses of UREGNO in DEBUG with uses of the debug temp.
     571              :    INSN must be where UREGNO dies, if WHERE is *_BEFORE_*, or where it
     572              :    is set otherwise.  Return the number of debug insns emitted.  */
     573              : 
     574              : int
     575    910279516 : dead_debug_insert_temp (struct dead_debug_local *debug, unsigned int uregno,
     576              :                         rtx_insn *insn, enum debug_temp_where where)
     577              : {
     578    910279516 :   struct dead_debug_use **tailp = &debug->head;
     579    910279516 :   struct dead_debug_use *cur;
     580    910279516 :   struct dead_debug_use *uses = NULL;
     581    910279516 :   struct dead_debug_use **usesp = &uses;
     582    910279516 :   rtx reg = NULL_RTX;
     583    910279516 :   rtx breg;
     584    910279516 :   rtx dval = NULL_RTX;
     585    910279516 :   rtx bind;
     586    910279516 :   bool global;
     587              : 
     588    910279516 :   if (!debug->used)
     589              :     return 0;
     590              : 
     591     69042459 :   global = (debug->global && debug->global->used
     592    135020131 :             && bitmap_bit_p (debug->global->used, uregno));
     593              : 
     594     68494400 :   if (!global && !bitmap_clear_bit (debug->used, uregno))
     595              :     return 0;
     596              : 
     597              :   /* Move all uses of uregno from debug->head to uses, setting mode to
     598              :      the widest referenced mode.  */
     599      1052534 :   while ((cur = *tailp))
     600              :     {
     601       445525 :       if (DF_REF_REGNO (cur->use) == uregno)
     602              :         {
     603              :           /* If this loc has been changed e.g. to debug_expr already
     604              :              as part of a multi-register use, just drop it.  */
     605       242586 :           if (!REG_P (*DF_REF_REAL_LOC (cur->use)))
     606              :             {
     607        49660 :               *tailp = cur->next;
     608        49660 :               XDELETE (cur);
     609        49660 :               continue;
     610              :             }
     611       192926 :           *usesp = cur;
     612       192926 :           usesp = &cur->next;
     613       192926 :           *tailp = cur->next;
     614       192926 :           cur->next = NULL;
     615              :           /* "may" rather than "must" because we want (for example)
     616              :              N V4SFs to win over plain V4SF even though N might be 1.  */
     617       192926 :           rtx candidate = *DF_REF_REAL_LOC (cur->use);
     618       192926 :           if (!reg
     619       245372 :               || maybe_lt (GET_MODE_BITSIZE (GET_MODE (reg)),
     620       104892 :                            GET_MODE_BITSIZE (GET_MODE (candidate))))
     621              :             reg = candidate;
     622              :         }
     623              :       else
     624       202939 :         tailp = &(*tailp)->next;
     625              :     }
     626              : 
     627              :   /* We may have dangling bits in debug->used for registers that were part
     628              :      of a multi-register use, one component of which has been reset.  */
     629       607009 :   if (reg == NULL)
     630              :     {
     631       466529 :       gcc_checking_assert (!uses);
     632       466529 :       if (!global)
     633              :         return 0;
     634              :     }
     635              : 
     636       140480 :   if (global)
     637              :     {
     638       466446 :       if (!reg)
     639       466446 :         reg = regno_reg_rtx[uregno];
     640       466446 :       dead_debug_global_entry *entry
     641       466446 :         = dead_debug_global_find (debug->global, reg);
     642       466446 :       gcc_checking_assert (entry->reg == reg);
     643       466446 :       dval = entry->dtemp;
     644       466446 :       if (!dval)
     645              :         return 0;
     646              :     }
     647              : 
     648       384877 :   gcc_checking_assert (uses || global);
     649              : 
     650       384877 :   breg = reg;
     651              :   /* Recover the expression INSN stores in REG.  */
     652       384877 :   if (where == DEBUG_TEMP_BEFORE_WITH_VALUE)
     653              :     {
     654       265865 :       rtx set = single_set (insn);
     655       265865 :       rtx dest, src;
     656              : 
     657       265865 :       if (set)
     658              :         {
     659       262476 :           dest = SET_DEST (set);
     660       262476 :           src = SET_SRC (set);
     661              :           /* Reset uses if the REG-setting insn is a CALL.  Asm in
     662              :              DEBUG_INSN is never useful, we can't emit debug info for
     663              :              that.  And for volatile_insn_p, it is actually harmful -
     664              :              DEBUG_INSNs shouldn't have any side-effects.  */
     665       262475 :           if (GET_CODE (src) == CALL || GET_CODE (src) == ASM_OPERANDS
     666       524905 :               || volatile_insn_p (src))
     667              :             set = NULL_RTX;
     668              :         }
     669              : 
     670              :       /* ??? Should we try to extract it from a PARALLEL?  */
     671       262429 :       if (!set)
     672              :         breg = NULL;
     673              :       /* Cool, it's the same REG, we can use SRC.  */
     674       262429 :       else if (dest == reg)
     675       259457 :         breg = cleanup_auto_inc_dec (src, VOIDmode);
     676         2972 :       else if (REG_P (dest))
     677              :         {
     678              :           /* Hmm...  Something's fishy, we should be setting REG here.  */
     679         1836 :           if (REGNO (dest) != REGNO (reg))
     680              :             breg = NULL;
     681              :           /* If we're not overwriting all the hardware registers that
     682              :              setting REG in its mode would, we won't know what to bind
     683              :              the debug temp to.  ??? We could bind the debug_expr to a
     684              :              CONCAT or PARALLEL with the split multi-registers, and
     685              :              replace them as we found the corresponding sets.  */
     686          984 :           else if (REG_NREGS (reg) != REG_NREGS (dest))
     687              :             breg = NULL;
     688              :           /* Ok, it's the same (hardware) REG, but with a different
     689              :              mode, so SUBREG it.  */
     690              :           else
     691          802 :             breg = debug_lowpart_subreg (GET_MODE (reg),
     692              :                                          cleanup_auto_inc_dec (src, VOIDmode),
     693          802 :                                          GET_MODE (dest));
     694              :         }
     695         1136 :       else if (GET_CODE (dest) == SUBREG)
     696              :         {
     697              :           /* We should be setting REG here.  Lose.  */
     698         1136 :           if (REGNO (SUBREG_REG (dest)) != REGNO (reg))
     699              :             breg = NULL;
     700              :           /* Lose if we're setting something other than the lowpart of
     701              :              REG.  */
     702         1136 :           else if (!subreg_lowpart_p (dest))
     703              :             breg = NULL;
     704              :           /* If we're not overwriting all the hardware registers that
     705              :              setting REG in its mode would, we won't know what to bind
     706              :              the debug temp to.  */
     707          630 :           else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
     708          630 :                    && (REG_NREGS (reg)
     709            0 :                        != hard_regno_nregs (REGNO (reg), GET_MODE (dest))))
     710              :             breg = NULL;
     711              :           /* Yay, we can use SRC, just adjust its mode.  */
     712              :           else
     713          630 :             breg = debug_lowpart_subreg (GET_MODE (reg),
     714              :                                          cleanup_auto_inc_dec (src, VOIDmode),
     715          630 :                                          GET_MODE (dest));
     716              :         }
     717              :       /* Oh well, we're out of luck.  */
     718              :       else
     719              :         breg = NULL;
     720              : 
     721              :       /* We couldn't figure out the value stored in REG, so reset all
     722              :          of its pending debug uses.  */
     723       260889 :       if (!breg)
     724              :         {
     725         4978 :           dead_debug_reset_uses (debug, uses);
     726         4978 :           return 0;
     727              :         }
     728              :     }
     729              : 
     730              :   /* If there's a single (debug) use of an otherwise unused REG, and
     731              :      the debug use is not part of a larger expression, then it
     732              :      probably doesn't make sense to introduce a new debug temp.  */
     733       379899 :   if (where == DEBUG_TEMP_AFTER_WITH_REG && !uses->next)
     734              :     {
     735        29900 :       rtx_insn *next = DF_REF_INSN (uses->use);
     736              : 
     737        29900 :       if (DEBUG_INSN_P (next) && reg == INSN_VAR_LOCATION_LOC (next))
     738              :         {
     739        27758 :           XDELETE (uses);
     740        27758 :           return 0;
     741              :         }
     742              :     }
     743              : 
     744       352141 :   if (!global)
     745              :     /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL).  */
     746       111521 :     dval = make_debug_expr_from_rtl (reg);
     747              : 
     748              :   /* Emit a debug bind insn before the insn in which reg dies.  */
     749       352141 :   bind = gen_rtx_VAR_LOCATION (GET_MODE (reg),
     750              :                                DEBUG_EXPR_TREE_DECL (dval), breg,
     751              :                                VAR_INIT_STATUS_INITIALIZED);
     752              : 
     753       352141 :   if (where == DEBUG_TEMP_AFTER_WITH_REG
     754       352141 :       || where == DEBUG_TEMP_AFTER_WITH_REG_FORCE)
     755        74559 :     bind = emit_debug_insn_after (bind, insn);
     756              :   else
     757       277582 :     bind = emit_debug_insn_before (bind, insn);
     758       352141 :   if (debug->to_rescan == NULL)
     759        90604 :     debug->to_rescan = BITMAP_ALLOC (NULL);
     760       352141 :   bitmap_set_bit (debug->to_rescan, INSN_UID (bind));
     761              : 
     762              :   /* Adjust all uses.  */
     763       868149 :   while ((cur = uses))
     764              :     {
     765       163867 :       if (GET_MODE (*DF_REF_REAL_LOC (cur->use)) == GET_MODE (reg))
     766       163733 :         *DF_REF_REAL_LOC (cur->use) = dval;
     767              :       else
     768          134 :         *DF_REF_REAL_LOC (cur->use)
     769          134 :           = debug_lowpart_subreg (GET_MODE (*DF_REF_REAL_LOC (cur->use)), dval,
     770          134 :                                   GET_MODE (dval));
     771              :       /* ??? Should we simplify subreg of subreg?  */
     772       163867 :       bitmap_set_bit (debug->to_rescan, INSN_UID (DF_REF_INSN (cur->use)));
     773       163867 :       uses = cur->next;
     774       163867 :       XDELETE (cur);
     775              :     }
     776              : 
     777              :   return 1;
     778              : }
        

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.