LCOV - code coverage report
Current view: top level - gcc - lra-coalesce.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 90.4 % 167 151
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 8 8
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Coalesce spilled pseudos.
       2              :    Copyright (C) 2010-2026 Free Software Foundation, Inc.
       3              :    Contributed by Vladimir Makarov <vmakarov@redhat.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              : /* This file contains a pass making some simple RTL code
      23              :    transformations by coalescing pseudos to remove some move insns.
      24              : 
      25              :    Spilling pseudos in LRA can create memory-memory moves.  We should
      26              :    remove potential memory-memory moves before the next constraint
      27              :    pass because the constraint pass will generate additional insns for
      28              :    such moves and all these insns will be hard to remove afterwards.
      29              : 
      30              :    Here we coalesce only spilled pseudos.  Coalescing non-spilled
      31              :    pseudos (with different hard regs) might result in spilling
      32              :    additional pseudos because of possible conflicts with other
      33              :    non-spilled pseudos and, as a consequence, in more constraint
      34              :    passes and even LRA infinite cycling.  Trivial the same hard
      35              :    register moves will be removed by subsequent compiler passes.
      36              : 
      37              :    We don't coalesce special reload pseudos.  It complicates LRA code
      38              :    a lot without visible generated code improvement.
      39              : 
      40              :    The pseudo live-ranges are used to find conflicting pseudos during
      41              :    coalescing.
      42              : 
      43              :    Most frequently executed moves is tried to be coalesced first.  */
      44              : 
      45              : #include "config.h"
      46              : #include "system.h"
      47              : #include "coretypes.h"
      48              : #include "backend.h"
      49              : #include "rtl.h"
      50              : #include "predict.h"
      51              : #include "df.h"
      52              : #include "insn-config.h"
      53              : #include "regs.h"
      54              : #include "memmodel.h"
      55              : #include "ira.h"
      56              : #include "recog.h"
      57              : #include "lra-int.h"
      58              : 
      59              : /* Arrays whose elements represent the first and the next pseudo
      60              :    (regno) in the coalesced pseudos group to which given pseudo (its
      61              :    regno is the index) belongs.  The next of the last pseudo in the
      62              :    group refers to the first pseudo in the group, in other words the
      63              :    group is represented by a cyclic list.  */
      64              : static int *first_coalesced_pseudo, *next_coalesced_pseudo;
      65              : 
      66              : /* The function is used to sort moves according to their execution
      67              :    frequencies.  */
      68              : static int
      69        16892 : move_freq_compare_func (const void *v1p, const void *v2p)
      70              : {
      71        16892 :   rtx_insn *mv1 = *(rtx_insn * const *) v1p;
      72        16892 :   rtx_insn *mv2 = *(rtx_insn * const *) v2p;
      73        16892 :   int pri1, pri2;
      74              : 
      75        16892 :   pri1 = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (mv1));
      76        16892 :   pri2 = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (mv2));
      77        16892 :   if (pri2 - pri1)
      78         7606 :     return pri2 - pri1;
      79              : 
      80              :   /* If frequencies are equal, sort by moves, so that the results of
      81              :      qsort leave nothing to chance.  */
      82         9286 :   return (int) INSN_UID (mv1) - (int) INSN_UID (mv2);
      83              : }
      84              : 
      85              : /* Pseudos which go away after coalescing.  */
      86              : static bitmap_head coalesced_pseudos_bitmap;
      87              : 
      88              : /* Merge two sets of coalesced pseudos given correspondingly by
      89              :    pseudos REGNO1 and REGNO2 (more accurately merging REGNO2 group
      90              :    into REGNO1 group).  Set up COALESCED_PSEUDOS_BITMAP.  */
      91              : static void
      92         1255 : merge_pseudos (int regno1, int regno2)
      93              : {
      94         1255 :   int regno, first, first2, last, next;
      95              : 
      96         1255 :   first = first_coalesced_pseudo[regno1];
      97         1255 :   if ((first2 = first_coalesced_pseudo[regno2]) == first)
      98              :     return;
      99         1255 :   for (last = regno2, regno = next_coalesced_pseudo[regno2];;
     100           53 :        regno = next_coalesced_pseudo[regno])
     101              :     {
     102         1308 :       first_coalesced_pseudo[regno] = first;
     103         1308 :       bitmap_set_bit (&coalesced_pseudos_bitmap, regno);
     104         1308 :       if (regno == regno2)
     105              :         break;
     106           53 :       last = regno;
     107              :     }
     108         1255 :   next = next_coalesced_pseudo[first];
     109         1255 :   next_coalesced_pseudo[first] = regno2;
     110         1255 :   next_coalesced_pseudo[last] = next;
     111         1255 :   lra_reg_info[first].live_ranges
     112         1255 :     = (lra_merge_live_ranges
     113         1255 :        (lra_reg_info[first].live_ranges,
     114         1255 :         lra_copy_live_range_list (lra_reg_info[first2].live_ranges)));
     115         1255 :   lra_update_biggest_mode (first, lra_reg_info[first2].biggest_mode);
     116              : }
     117              : 
     118              : /* Change pseudos in *LOC on their coalescing group
     119              :    representatives.  */
     120              : static bool
     121        85894 : substitute (rtx *loc)
     122              : {
     123        85894 :   int i, regno;
     124        85894 :   const char *fmt;
     125        85894 :   enum rtx_code code;
     126        85894 :   bool res;
     127              : 
     128        85894 :   if (*loc == NULL_RTX)
     129              :     return false;
     130        74931 :   code = GET_CODE (*loc);
     131        74931 :   if (code == REG)
     132              :     {
     133        31955 :       regno = REGNO (*loc);
     134        31955 :       if (regno < FIRST_PSEUDO_REGISTER
     135        28678 :           || first_coalesced_pseudo[regno] == regno)
     136              :         return false;
     137         7649 :       *loc = regno_reg_rtx[first_coalesced_pseudo[regno]];
     138         7649 :       return true;
     139              :     }
     140              : 
     141        42976 :   res = false;
     142        42976 :   fmt = GET_RTX_FORMAT (code);
     143       178637 :   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     144              :     {
     145       135661 :       if (fmt[i] == 'e')
     146              :         {
     147        72482 :           if (substitute (&XEXP (*loc, i)))
     148       135661 :             res = true;
     149              :         }
     150        63179 :       else if (fmt[i] == 'E')
     151              :         {
     152         1187 :           int j;
     153              : 
     154         3636 :           for (j = XVECLEN (*loc, i) - 1; j >= 0; j--)
     155         2449 :             if (substitute (&XVECEXP (*loc, i, j)))
     156          420 :               res = true;
     157              :         }
     158              :     }
     159              :   return res;
     160              : }
     161              : 
     162              : /* Specialize "substitute" for use on an insn.  This can't change
     163              :    the insn ptr, just the contents of the insn.  */
     164              : 
     165              : static bool
     166        10963 : substitute_within_insn (rtx_insn *insn)
     167              : {
     168        10963 :   rtx loc = insn;
     169            0 :   return substitute (&loc);
     170              : }
     171              : 
     172              : /* The current iteration (1, 2, ...) of the coalescing pass.  */
     173              : int lra_coalesce_iter;
     174              : 
     175              : /* Return true if the move involving REGNO1 and REGNO2 is a potential
     176              :    memory-memory move.  */
     177              : static bool
     178      3753772 : mem_move_p (int regno1, int regno2)
     179              : {
     180      3753772 :   return reg_renumber[regno1] < 0 && reg_renumber[regno2] < 0;
     181              : }
     182              : 
     183              : /* Pseudos used instead of the coalesced pseudos.  */
     184              : static bitmap_head used_pseudos_bitmap;
     185              : 
     186              : /* Set up USED_PSEUDOS_BITMAP, and update LR_BITMAP (a BB live info
     187              :    bitmap).  */
     188              : static void
     189      3250426 : update_live_info (bitmap lr_bitmap)
     190              : {
     191      3250426 :   unsigned int j;
     192      3250426 :   bitmap_iterator bi;
     193              : 
     194      3250426 :   bitmap_clear (&used_pseudos_bitmap);
     195      3298018 :   EXECUTE_IF_AND_IN_BITMAP (&coalesced_pseudos_bitmap, lr_bitmap,
     196              :                             FIRST_PSEUDO_REGISTER, j, bi)
     197        47592 :     bitmap_set_bit (&used_pseudos_bitmap, first_coalesced_pseudo[j]);
     198      3250426 :   if (! bitmap_empty_p (&used_pseudos_bitmap))
     199              :     {
     200        38094 :       bitmap_and_compl_into (lr_bitmap, &coalesced_pseudos_bitmap);
     201        38094 :       bitmap_ior_into (lr_bitmap, &used_pseudos_bitmap);
     202              :     }
     203      3250426 : }
     204              : 
     205              : /* Return true if pseudo REGNO can be potentially coalesced.  */
     206              : static bool
     207         6781 : coalescable_pseudo_p (int regno)
     208              : {
     209         6781 :   lra_assert (regno >= FIRST_PSEUDO_REGISTER);
     210         6781 :   return (/* We don't want to coalesce regnos with equivalences, at
     211              :              least without updating this info.  */
     212         6781 :           ira_reg_equiv[regno].constant == NULL_RTX
     213         6779 :           && ira_reg_equiv[regno].memory == NULL_RTX
     214        13556 :           && ira_reg_equiv[regno].invariant == NULL_RTX);
     215              : }
     216              : 
     217              : /* The major function for aggressive pseudo coalescing of moves only
     218              :    if the both pseudos were spilled and not special reload pseudos.  */
     219              : bool
     220        26711 : lra_coalesce (void)
     221              : {
     222        26711 :   basic_block bb;
     223        26711 :   rtx_insn *mv, *insn, *next, **sorted_moves;
     224        26711 :   rtx set;
     225        26711 :   int i, mv_num, sregno, dregno;
     226        26711 :   int coalesced_moves;
     227        26711 :   int max_regno = max_reg_num ();
     228        26711 :   bitmap_head involved_insns_bitmap;
     229              : 
     230        26711 :   timevar_push (TV_LRA_COALESCE);
     231              : 
     232        26711 :   if (lra_dump_file != NULL)
     233            0 :     fprintf (lra_dump_file,
     234              :              "\n********** Pseudos coalescing #%d: **********\n\n",
     235              :              ++lra_coalesce_iter);
     236        26711 :   first_coalesced_pseudo = XNEWVEC (int, max_regno);
     237        26711 :   next_coalesced_pseudo = XNEWVEC (int, max_regno);
     238     13920262 :   for (i = 0; i < max_regno; i++)
     239     13893551 :     first_coalesced_pseudo[i] = next_coalesced_pseudo[i] = i;
     240        26711 :   sorted_moves = XNEWVEC (rtx_insn *, get_max_uid ());
     241        26711 :   mv_num = 0;
     242              :   /* Collect moves.  */
     243        26711 :   coalesced_moves = 0;
     244      1651924 :   FOR_EACH_BB_FN (bb, cfun)
     245              :     {
     246     51604254 :       FOR_BB_INSNS_SAFE (bb, insn, next)
     247     24176914 :         if (INSN_P (insn)
     248     20438107 :             && (set = single_set (insn)) != NULL_RTX
     249     13073064 :             && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set))
     250      4304195 :             && (sregno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER
     251      4107615 :             && (dregno = REGNO (SET_DEST (set))) >= FIRST_PSEUDO_REGISTER
     252      3753772 :             && mem_move_p (sregno, dregno)
     253         3394 :             && coalescable_pseudo_p (sregno) && coalescable_pseudo_p (dregno)
     254         3387 :             && ! side_effects_p (set)
     255     24180301 :             && !(lra_intersected_live_ranges_p
     256         3387 :                  (lra_reg_info[sregno].live_ranges,
     257         3387 :                   lra_reg_info[dregno].live_ranges)))
     258         2209 :           sorted_moves[mv_num++] = insn;
     259              :     }
     260        26711 :   qsort (sorted_moves, mv_num, sizeof (rtx), move_freq_compare_func);
     261              :   /* Coalesced copies, most frequently executed first.  */
     262        26711 :   bitmap_initialize (&coalesced_pseudos_bitmap, &reg_obstack);
     263        26711 :   bitmap_initialize (&involved_insns_bitmap, &reg_obstack);
     264        28920 :   for (i = 0; i < mv_num; i++)
     265              :     {
     266         2209 :       mv = sorted_moves[i];
     267         2209 :       set = single_set (mv);
     268         2209 :       lra_assert (set != NULL && REG_P (SET_SRC (set))
     269              :                   && REG_P (SET_DEST (set)));
     270         2209 :       sregno = REGNO (SET_SRC (set));
     271         2209 :       dregno = REGNO (SET_DEST (set));
     272         2209 :       if (first_coalesced_pseudo[sregno] == first_coalesced_pseudo[dregno])
     273              :         {
     274          954 :           coalesced_moves++;
     275          954 :           if (lra_dump_file != NULL)
     276            0 :             fprintf
     277            0 :               (lra_dump_file, "      Coalescing move %i:r%d-r%d (freq=%d)\n",
     278            0 :                INSN_UID (mv), sregno, dregno,
     279            0 :                REG_FREQ_FROM_BB (BLOCK_FOR_INSN (mv)));
     280              :           /* We updated involved_insns_bitmap when doing the merge.  */
     281              :         }
     282         1255 :       else if (!(lra_intersected_live_ranges_p
     283         1255 :                  (lra_reg_info[first_coalesced_pseudo[sregno]].live_ranges,
     284         1255 :                   lra_reg_info[first_coalesced_pseudo[dregno]].live_ranges)))
     285              :         {
     286         1255 :           coalesced_moves++;
     287         1255 :           if (lra_dump_file != NULL)
     288            0 :             fprintf
     289            0 :               (lra_dump_file,
     290              :                "  Coalescing move %i:r%d(%d)-r%d(%d) (freq=%d)\n",
     291            0 :                INSN_UID (mv), sregno, ORIGINAL_REGNO (SET_SRC (set)),
     292            0 :                dregno, ORIGINAL_REGNO (SET_DEST (set)),
     293            0 :                REG_FREQ_FROM_BB (BLOCK_FOR_INSN (mv)));
     294         1255 :           bitmap_ior_into (&involved_insns_bitmap,
     295         1255 :                            &lra_reg_info[sregno].insn_bitmap);
     296         1255 :           bitmap_ior_into (&involved_insns_bitmap,
     297         1255 :                            &lra_reg_info[dregno].insn_bitmap);
     298         1255 :           merge_pseudos (sregno, dregno);
     299              :         }
     300              :     }
     301        26711 :   bitmap_initialize (&used_pseudos_bitmap, &reg_obstack);
     302      1651924 :   FOR_EACH_BB_FN (bb, cfun)
     303              :     {
     304      1625213 :       update_live_info (df_get_live_in (bb));
     305      1625213 :       update_live_info (df_get_live_out (bb));
     306     51604254 :       FOR_BB_INSNS_SAFE (bb, insn, next)
     307     24176914 :         if (INSN_P (insn)
     308     24176914 :             && bitmap_bit_p (&involved_insns_bitmap, INSN_UID (insn)))
     309              :           {
     310        10963 :             if (! substitute_within_insn (insn))
     311         5524 :               continue;
     312         5439 :             lra_update_insn_regno_info (insn);
     313         5439 :             if ((set = single_set (insn)) != NULL_RTX && set_noop_p (set))
     314              :               {
     315              :                 /* Coalesced move.  */
     316         2209 :                 if (lra_dump_file != NULL)
     317            0 :                   fprintf (lra_dump_file, "         Removing move %i (freq=%d)\n",
     318            0 :                            INSN_UID (insn),
     319            0 :                            REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn)));
     320         2209 :                 lra_set_insn_deleted (insn);
     321              :               }
     322              :           }
     323              :     }
     324              :   /* If we have situation after inheritance pass:
     325              : 
     326              :      r1 <- p1   insn originally setting p1
     327              :      i1 <- r1   setting inheritance i1 from reload r1
     328              :        ...
     329              :      ... <- ... p2 ... dead p2
     330              :      ..
     331              :      p1 <- i1
     332              :      r2 <- i1
     333              :      ...<- ... r2 ...
     334              : 
     335              :      And we are coalescing p1 and p2 using p1.  In this case i1 and p1
     336              :      should have different values, otherwise they can get the same
     337              :      hard reg and this is wrong for insn using p2 before coalescing.
     338              :      The situation even can be more complicated when new reload
     339              :      pseudos occur after the inheriatnce.  So invalidate the result
     340              :      pseudos.  */
     341     13920262 :   for (i = 0; i < max_regno; i++)
     342     13893551 :     if (first_coalesced_pseudo[i] == i
     343     13892296 :         && first_coalesced_pseudo[i] != next_coalesced_pseudo[i])
     344              :       {
     345         1065 :         lra_set_regno_unique_value (i);
     346         1065 :         if (lra_dump_file != NULL)
     347            0 :           fprintf (lra_dump_file,
     348              :                    "        Make unique value for coalescing result r%d\n", i);
     349              :       }
     350        26711 :   bitmap_clear (&used_pseudos_bitmap);
     351        26711 :   bitmap_clear (&involved_insns_bitmap);
     352        26711 :   bitmap_clear (&coalesced_pseudos_bitmap);
     353        26711 :   if (lra_dump_file != NULL && coalesced_moves != 0)
     354            0 :     fprintf (lra_dump_file, "Coalesced Moves = %d\n", coalesced_moves);
     355        26711 :   free (sorted_moves);
     356        26711 :   free (next_coalesced_pseudo);
     357        26711 :   free (first_coalesced_pseudo);
     358        26711 :   timevar_pop (TV_LRA_COALESCE);
     359        26711 :   return coalesced_moves != 0;
     360              : }
        

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.