LCOV - code coverage report
Current view: top level - gcc/rtl-ssa - changes.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 78.0 % 636 496
Test Date: 2025-08-30 13:27:53 Functions: 80.8 % 26 21
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // RTL SSA routines for changing instructions                       -*- C++ -*-
       2                 :             : // Copyright (C) 2020-2025 Free Software Foundation, Inc.
       3                 :             : //
       4                 :             : // This file is part of GCC.
       5                 :             : //
       6                 :             : // GCC is free software; you can redistribute it and/or modify it under
       7                 :             : // the terms of the GNU General Public License as published by the Free
       8                 :             : // Software Foundation; either version 3, or (at your option) any later
       9                 :             : // version.
      10                 :             : //
      11                 :             : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12                 :             : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13                 :             : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14                 :             : // for more details.
      15                 :             : //
      16                 :             : // You should have received a copy of the GNU General Public License
      17                 :             : // along with GCC; see the file COPYING3.  If not see
      18                 :             : // <http://www.gnu.org/licenses/>.
      19                 :             : 
      20                 :             : #define INCLUDE_ALGORITHM
      21                 :             : #define INCLUDE_FUNCTIONAL
      22                 :             : #define INCLUDE_ARRAY
      23                 :             : #include "config.h"
      24                 :             : #include "system.h"
      25                 :             : #include "coretypes.h"
      26                 :             : #include "backend.h"
      27                 :             : #include "rtl.h"
      28                 :             : #include "df.h"
      29                 :             : #include "rtl-ssa.h"
      30                 :             : #include "rtl-ssa/internals.h"
      31                 :             : #include "rtl-ssa/internals.inl"
      32                 :             : #include "target.h"
      33                 :             : #include "predict.h"
      34                 :             : #include "memmodel.h" // Needed by emit-rtl.h
      35                 :             : #include "emit-rtl.h"
      36                 :             : #include "cfghooks.h"
      37                 :             : #include "cfgrtl.h"
      38                 :             : #include "sreal.h"
      39                 :             : 
      40                 :             : using namespace rtl_ssa;
      41                 :             : 
      42                 :             : // See the comment above the declaration.
      43                 :             : void
      44                 :           0 : insn_change::print (pretty_printer *pp) const
      45                 :             : {
      46                 :           0 :   if (m_is_deletion)
      47                 :             :     {
      48                 :           0 :       pp_string (pp, "deletion of ");
      49                 :           0 :       pp_insn (pp, m_insn);
      50                 :             :     }
      51                 :             :   else
      52                 :             :     {
      53                 :           0 :       pp_string (pp, "change to ");
      54                 :           0 :       pp_insn (pp, m_insn);
      55                 :           0 :       pp_newline_and_indent (pp, 2);
      56                 :           0 :       pp_string (pp, "~~~~~~~");
      57                 :             : 
      58                 :           0 :       pp_newline_and_indent (pp, 0);
      59                 :           0 :       pp_string (pp, "new cost: ");
      60                 :           0 :       pp_decimal_int (pp, new_cost);
      61                 :             : 
      62                 :           0 :       pp_newline_and_indent (pp, 0);
      63                 :           0 :       pp_string (pp, "new uses:");
      64                 :           0 :       pp_newline_and_indent (pp, 2);
      65                 :           0 :       pp_accesses (pp, new_uses);
      66                 :           0 :       pp_indentation (pp) -= 2;
      67                 :             : 
      68                 :           0 :       pp_newline_and_indent (pp, 0);
      69                 :           0 :       pp_string (pp, "new defs:");
      70                 :           0 :       pp_newline_and_indent (pp, 2);
      71                 :           0 :       pp_accesses (pp, new_defs);
      72                 :           0 :       pp_indentation (pp) -= 2;
      73                 :             : 
      74                 :           0 :       pp_newline_and_indent (pp, 0);
      75                 :           0 :       pp_string (pp, "first insert-after candidate: ");
      76                 :           0 :       move_range.first->print_identifier_and_location (pp);
      77                 :             : 
      78                 :           0 :       pp_newline_and_indent (pp, 0);
      79                 :           0 :       pp_string (pp, "last insert-after candidate: ");
      80                 :           0 :       move_range.last->print_identifier_and_location (pp);
      81                 :             :     }
      82                 :           0 : }
      83                 :             : 
      84                 :             : // Return a copy of access_array ACCESSES, allocating it on the
      85                 :             : // temporary obstack.
      86                 :             : access_array
      87                 :    20218504 : function_info::temp_access_array (access_array accesses)
      88                 :             : {
      89                 :    20218504 :   if (accesses.empty ())
      90                 :     2037410 :     return accesses;
      91                 :             : 
      92                 :    18181094 :   gcc_assert (obstack_object_size (&m_temp_obstack) == 0);
      93                 :    18181094 :   obstack_grow (&m_temp_obstack, accesses.begin (), accesses.size_bytes ());
      94                 :    18181094 :   return { static_cast<access_info **> (obstack_finish (&m_temp_obstack)),
      95                 :    18181094 :            accesses.size () };
      96                 :             : }
      97                 :             : 
      98                 :             : // See the comment above the declaration.
      99                 :             : bool
     100                 :     2153721 : function_info::verify_insn_changes (array_slice<insn_change *const> changes)
     101                 :             : {
     102                 :     2153721 :   HARD_REG_SET defined_hard_regs, clobbered_hard_regs;
     103                 :     8614884 :   CLEAR_HARD_REG_SET (defined_hard_regs);
     104                 :     2153721 :   CLEAR_HARD_REG_SET (clobbered_hard_regs);
     105                 :             : 
     106                 :     2153721 :   insn_info *min_insn = m_first_insn;
     107                 :     9955543 :   for (insn_change *change : changes)
     108                 :     7806303 :     if (!change->is_deletion ())
     109                 :             :       {
     110                 :             :         // Make sure that the changes can be kept in their current order
     111                 :             :         // while honoring all of the move ranges.
     112                 :     5652582 :         min_insn = later_insn (min_insn, change->move_range.first);
     113                 :     5652590 :         while (min_insn != change->insn () && !can_insert_after (min_insn))
     114                 :           8 :           min_insn = min_insn->next_nondebug_insn ();
     115                 :     5652582 :         if (*min_insn > *change->move_range.last)
     116                 :             :           {
     117                 :        4442 :             if (dump_file && (dump_flags & TDF_DETAILS))
     118                 :           0 :               fprintf (dump_file, "no viable insn position assignment\n");
     119                 :        4442 :             return false;
     120                 :             :           }
     121                 :             : 
     122                 :             :         // If recog introduced new clobbers of a register as part of
     123                 :             :         // the matching process, make sure that they don't conflict
     124                 :             :         // with any other new definitions or uses of the register.
     125                 :             :         // (We have already checked that they don't conflict with
     126                 :             :         // unchanging definitions and uses.)
     127                 :    15283200 :         for (use_info *use : change->new_uses)
     128                 :             :           {
     129                 :     9635060 :             unsigned int regno = use->regno ();
     130                 :     9635060 :             if (HARD_REGISTER_NUM_P (regno)
     131                 :     9635060 :                 && TEST_HARD_REG_BIT (clobbered_hard_regs, regno))
     132                 :             :               {
     133                 :           0 :                 if (dump_file && (dump_flags & TDF_DETAILS))
     134                 :           0 :                   fprintf (dump_file, "register %d would be clobbered"
     135                 :             :                            " while it is still live\n", regno);
     136                 :           0 :                 return false;
     137                 :             :               }
     138                 :             :           }
     139                 :    11913945 :         for (def_info *def : change->new_defs)
     140                 :             :           {
     141                 :     6265844 :             unsigned int regno = def->regno ();
     142                 :     6265844 :             if (HARD_REGISTER_NUM_P (regno))
     143                 :             :               {
     144                 :     3004739 :                 if (def->m_is_temp)
     145                 :             :                   {
     146                 :             :                     // This is a clobber introduced by recog.
     147                 :       29118 :                     gcc_checking_assert (is_a<clobber_info *> (def));
     148                 :       29118 :                     if (TEST_HARD_REG_BIT (defined_hard_regs, regno))
     149                 :             :                       {
     150                 :          39 :                         if (dump_file && (dump_flags & TDF_DETAILS))
     151                 :           0 :                           fprintf (dump_file, "conflicting definitions of"
     152                 :             :                                    " register %d\n", regno);
     153                 :          39 :                         return false;
     154                 :             :                       }
     155                 :       29079 :                     SET_HARD_REG_BIT (clobbered_hard_regs, regno);
     156                 :             :                   }
     157                 :     9241426 :                 else if (is_a<set_info *> (def))
     158                 :             :                   {
     159                 :             :                     // REGNO now has a defined value.
     160                 :     2446725 :                     SET_HARD_REG_BIT (defined_hard_regs, regno);
     161                 :     2446725 :                     CLEAR_HARD_REG_BIT (clobbered_hard_regs, regno);
     162                 :             :                   }
     163                 :             :               }
     164                 :             :           }
     165                 :             :       }
     166                 :             :   return true;
     167                 :             : }
     168                 :             : 
     169                 :             : // See the comment above the declaration.
     170                 :             : bool
     171                 :     8438416 : rtl_ssa::changes_are_worthwhile (array_slice<insn_change *const> changes,
     172                 :             :                                  bool strict_p)
     173                 :             : {
     174                 :     8438416 :   unsigned int old_cost = 0;
     175                 :     8438416 :   sreal weighted_old_cost = 0;
     176                 :     8438416 :   auto entry_count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
     177                 :     8438416 :   {
     178                 :     8438416 :     undo_recog_changes undo (0);
     179                 :    23011430 :     for (insn_change *change : changes)
     180                 :             :       {
     181                 :             :         // Count zero for the old cost if the old instruction was a no-op
     182                 :             :         // move or had an unknown cost.  This should reduce the chances of
     183                 :             :         // making an unprofitable change.
     184                 :    14573014 :         old_cost += change->old_cost ();
     185                 :    14573014 :         basic_block cfg_bb = change->bb ()->cfg_bb ();
     186                 :    14573014 :         if (optimize_bb_for_speed_p (cfg_bb))
     187                 :    12885015 :           weighted_old_cost += (cfg_bb->count.to_sreal_scale (entry_count)
     188                 :    12885015 :                                 * change->old_cost ());
     189                 :             : 
     190                 :             :       }
     191                 :     8438416 :   }
     192                 :     8438416 :   unsigned int new_cost = 0;
     193                 :     8438416 :   sreal weighted_new_cost = 0;
     194                 :    22948104 :   for (insn_change *change : changes)
     195                 :             :     {
     196                 :    14530534 :       basic_block cfg_bb = change->bb ()->cfg_bb ();
     197                 :    14530534 :       bool for_speed = optimize_bb_for_speed_p (cfg_bb);
     198                 :    14530534 :       if (!change->is_deletion ()
     199                 :    14530534 :           && INSN_CODE (change->rtl ()) != NOOP_MOVE_INSN_CODE)
     200                 :             :         {
     201                 :    12191504 :           change->new_cost = insn_cost (change->rtl (), for_speed);
     202                 :             :           /* If the cost is unknown, replacement is not worthwhile.  */
     203                 :    12191504 :           if (!change->new_cost)
     204                 :             :             {
     205                 :       20846 :               if (dump_file && (dump_flags & TDF_DETAILS))
     206                 :           0 :                 fprintf (dump_file,
     207                 :             :                          "Reject replacement due to unknown insn cost.\n");
     208                 :       20846 :               return false;
     209                 :             :             }
     210                 :    12170658 :           new_cost += change->new_cost;
     211                 :    12170658 :           if (for_speed)
     212                 :    32279964 :             weighted_new_cost += (cfg_bb->count.to_sreal_scale (entry_count)
     213                 :    10759988 :                                   * change->new_cost);
     214                 :             :         }
     215                 :             :     }
     216                 :     8417570 :   bool ok_p;
     217                 :     8417570 :   if (weighted_new_cost != weighted_old_cost)
     218                 :     3225140 :     ok_p = weighted_new_cost < weighted_old_cost;
     219                 :     5192430 :   else if (strict_p)
     220                 :     3606492 :     ok_p = new_cost < old_cost;
     221                 :             :   else
     222                 :     1585938 :     ok_p = new_cost <= old_cost;
     223                 :     8417570 :   if (dump_file && (dump_flags & TDF_DETAILS))
     224                 :             :     {
     225                 :           0 :       fprintf (dump_file, "original cost");
     226                 :           0 :       char sep = '=';
     227                 :           0 :       for (const insn_change *change : changes)
     228                 :             :         {
     229                 :           0 :           fprintf (dump_file, " %c %d", sep, change->old_cost ());
     230                 :           0 :           sep = '+';
     231                 :             :         }
     232                 :           0 :       if (weighted_old_cost != 0)
     233                 :           0 :         fprintf (dump_file, " (weighted: %f)", weighted_old_cost.to_double ());
     234                 :           0 :       fprintf (dump_file, ", replacement cost");
     235                 :           0 :       sep = '=';
     236                 :           0 :       for (const insn_change *change : changes)
     237                 :           0 :         if (!change->is_deletion ())
     238                 :             :           {
     239                 :           0 :             if (INSN_CODE (change->rtl ()) == NOOP_MOVE_INSN_CODE)
     240                 :           0 :               fprintf (dump_file, " %c nop", sep);
     241                 :             :             else
     242                 :           0 :               fprintf (dump_file, " %c %d", sep, change->new_cost);
     243                 :             :             sep = '+';
     244                 :             :           }
     245                 :           0 :       if (weighted_new_cost != 0)
     246                 :           0 :         fprintf (dump_file, " (weighted: %f)", weighted_new_cost.to_double ());
     247                 :           0 :       fprintf (dump_file, "; %s\n",
     248                 :             :                ok_p ? "keeping replacement" : "rejecting replacement");
     249                 :             :     }
     250                 :     8417570 :   if (!ok_p)
     251                 :             :     return false;
     252                 :             : 
     253                 :             :   return true;
     254                 :             : }
     255                 :             : 
     256                 :             : // SET has been deleted.  Clean up all remaining uses.  Such uses are
     257                 :             : // either dead phis or now-redundant live-out uses.
     258                 :             : void
     259                 :      683547 : function_info::process_uses_of_deleted_def (set_info *set)
     260                 :             : {
     261                 :             :   // Each member of the worklist is either SET or a dead phi.
     262                 :      683547 :   auto_vec<set_info *, 16> worklist;
     263                 :      683547 :   worklist.quick_push (set);
     264                 :     2686212 :   while (!worklist.is_empty ())
     265                 :             :     {
     266                 :     1319118 :       auto *this_set = worklist.pop ();
     267                 :     1319118 :       auto *use = this_set->first_use ();
     268                 :     1319118 :       if (!use)
     269                 :             :         {
     270                 :       23835 :           if (this_set != set)
     271                 :       23835 :             delete_phi (as_a<phi_info *> (this_set));
     272                 :       23835 :           continue;
     273                 :             :         }
     274                 :     1295283 :       if (use->is_in_phi ())
     275                 :             :         {
     276                 :             :           // Removing all uses from the phi ensures that we'll only add
     277                 :             :           // the phi to the worklist once.
     278                 :       23835 :           auto *phi = use->phi ();
     279                 :       71505 :           for (auto *input : phi->inputs ())
     280                 :             :             {
     281                 :       23835 :               remove_use (input);
     282                 :       23835 :               input->set_def (nullptr);
     283                 :             :             }
     284                 :       23835 :           worklist.safe_push (phi);
     285                 :             :         }
     286                 :             :       else
     287                 :             :         {
     288                 :     1271448 :           gcc_assert (use->is_live_out_use ());
     289                 :     1271448 :           remove_use (use);
     290                 :             :         }
     291                 :             :       // The phi handling above might have removed multiple uses of THIS_SET.
     292                 :     1295283 :       if (this_set->has_any_uses ())
     293                 :      611736 :         worklist.safe_push (this_set);
     294                 :             :     }
     295                 :      683547 : }
     296                 :             : 
     297                 :             : // Update the REG_NOTES of INSN, whose pattern has just been changed.
     298                 :             : static void
     299                 :    10109252 : update_notes (rtx_insn *insn)
     300                 :             : {
     301                 :    16239243 :   for (rtx *note_ptr = &REG_NOTES (insn); *note_ptr; )
     302                 :             :     {
     303                 :     6129991 :       rtx note = *note_ptr;
     304                 :     6129991 :       bool keep_p = true;
     305                 :     6129991 :       switch (REG_NOTE_KIND (note))
     306                 :             :         {
     307                 :      225893 :         case REG_EQUAL:
     308                 :      225893 :         case REG_EQUIV:
     309                 :      225893 :         case REG_NOALIAS:
     310                 :      225893 :           keep_p = (single_set (insn) != nullptr);
     311                 :      225893 :           break;
     312                 :             : 
     313                 :             :         case REG_UNUSED:
     314                 :             :         case REG_DEAD:
     315                 :             :           // These notes are stale.  We'll recompute REG_UNUSED notes
     316                 :             :           // after the update.
     317                 :             :           keep_p = false;
     318                 :             :           break;
     319                 :             : 
     320                 :             :         default:
     321                 :             :           break;
     322                 :             :         }
     323                 :      225893 :       if (keep_p)
     324                 :      282805 :         note_ptr = &XEXP (*note_ptr, 1);
     325                 :             :       else
     326                 :             :         {
     327                 :     5847186 :           *note_ptr = XEXP (*note_ptr, 1);
     328                 :     5847186 :           free_EXPR_LIST_node (note);
     329                 :             :         }
     330                 :             :     }
     331                 :    10109252 : }
     332                 :             : 
     333                 :             : // Pick a location for CHANGE's instruction and return the instruction
     334                 :             : // after which it should be placed.
     335                 :             : static insn_info *
     336                 :    10109252 : choose_insn_placement (insn_change &change)
     337                 :             : {
     338                 :    10109252 :   gcc_checking_assert (change.move_range);
     339                 :             : 
     340                 :    10109252 :   insn_info *insn = change.insn ();
     341                 :    10109252 :   insn_info *first = change.move_range.first;
     342                 :    10109252 :   insn_info *last = change.move_range.last;
     343                 :             : 
     344                 :             :   // Quick(ish) exit if there is only one possible choice.
     345                 :    10109252 :   if (first == last)
     346                 :             :     return first;
     347                 :      570419 :   if (first == insn->prev_nondebug_insn () && last == insn)
     348                 :             :     return insn;
     349                 :             : 
     350                 :             :   // For now just use the closest valid choice to the original instruction.
     351                 :             :   // If the register usage has changed significantly, it might instead be
     352                 :             :   // better to try to take register pressure into account.
     353                 :      488697 :   insn_info *closest = change.move_range.clamp_insn_to_range (insn);
     354                 :      977394 :   while (closest != insn && !can_insert_after (closest))
     355                 :           0 :     closest = closest->next_nondebug_insn ();
     356                 :             :   return closest;
     357                 :             : }
     358                 :             : 
     359                 :             : // Record any changes related to CHANGE that need to be queued for later.
     360                 :             : void
     361                 :    12258492 : function_info::possibly_queue_changes (insn_change &change)
     362                 :             : {
     363                 :    12258492 :   insn_info *insn = change.insn ();
     364                 :    12258492 :   rtx_insn *rtl = insn->rtl ();
     365                 :             : 
     366                 :             :   // If the instruction could previously throw, we eventually need to call
     367                 :             :   // purge_dead_edges to check whether things have changed.
     368                 :    12258492 :   if (find_reg_note (rtl, REG_EH_REGION, nullptr))
     369                 :       49432 :     bitmap_set_bit (m_need_to_purge_dead_edges, insn->bb ()->index ());
     370                 :             : 
     371                 :    24516984 :   auto needs_pending_update = [&]()
     372                 :             :     {
     373                 :             :       // If an instruction became a no-op without the pass explicitly
     374                 :             :       // deleting it, queue the deletion for later.  Removing the
     375                 :             :       // instruction on the fly would require an update to all instructions
     376                 :             :       // that use the result of the move, which would be a potential source
     377                 :             :       // of quadraticness.  Also, definitions shouldn't disappear under
     378                 :             :       // the pass's feet.
     379                 :    12258492 :       if (INSN_CODE (rtl) == NOOP_MOVE_INSN_CODE)
     380                 :             :         return true;
     381                 :             : 
     382                 :             :       // If any jumps got turned into unconditional jumps or nops, we need
     383                 :             :       // to update the CFG accordingly.
     384                 :    12252513 :       if (JUMP_P (rtl)
     385                 :        1377 :           && (returnjump_p (rtl) || any_uncondjump_p (rtl))
     386                 :    12258510 :           && !single_succ_p (insn->bb ()->cfg_bb ()))
     387                 :             :         return true;
     388                 :             : 
     389                 :             :       // If a previously conditional trap now always fires, execution
     390                 :             :       // terminates at that point.
     391                 :    12252495 :       rtx pattern = PATTERN (rtl);
     392                 :    12252495 :       if (GET_CODE (pattern) == TRAP_IF
     393                 :           0 :           && XEXP (pattern, 0) == const1_rtx)
     394                 :             :         return true;
     395                 :             : 
     396                 :             :       return false;
     397                 :    12258492 :     };
     398                 :             : 
     399                 :    12258492 :   if (needs_pending_update ()
     400                 :    12258492 :       && bitmap_set_bit (m_queued_insn_update_uids, insn->uid ()))
     401                 :             :     {
     402                 :        5812 :       gcc_assert (!change.is_deletion ());
     403                 :        5812 :       m_queued_insn_updates.safe_push (insn);
     404                 :             :     }
     405                 :    12258492 : }
     406                 :             : 
     407                 :             : // Remove the instruction described by CHANGE from the underlying RTL
     408                 :             : // and from the insn_info list.
     409                 :             : static void
     410                 :     2149240 : delete_insn (insn_change &change)
     411                 :             : {
     412                 :     2149240 :   insn_info *insn = change.insn ();
     413                 :     2149240 :   rtx_insn *rtl = change.rtl ();
     414                 :     2149240 :   if (dump_file && (dump_flags & TDF_DETAILS))
     415                 :           0 :     fprintf (dump_file, "deleting insn %d\n", insn->uid ());
     416                 :     2149240 :   set_insn_deleted (rtl);
     417                 :     2149240 : }
     418                 :             : 
     419                 :             : // Move the RTL instruction associated with CHANGE so that it comes
     420                 :             : // immediately after AFTER.
     421                 :             : static void
     422                 :       25060 : move_insn (insn_change &change, insn_info *after)
     423                 :             : {
     424                 :       25060 :   rtx_insn *rtl = change.rtl ();
     425                 :       25060 :   rtx_insn *after_rtl = after->rtl ();
     426                 :       25060 :   if (dump_file && (dump_flags & TDF_DETAILS))
     427                 :           0 :     fprintf (dump_file, "moving insn %d after insn %d\n",
     428                 :           0 :              INSN_UID (rtl), INSN_UID (after_rtl));
     429                 :             : 
     430                 :             :   // At the moment we don't support moving instructions between EBBs,
     431                 :             :   // but this would be worth adding if it's useful.
     432                 :       25060 :   insn_info *insn = change.insn ();
     433                 :             : 
     434                 :       25060 :   bb_info *bb = after->bb ();
     435                 :       25060 :   basic_block cfg_bb = bb->cfg_bb ();
     436                 :             : 
     437                 :       25060 :   if (!insn->is_temporary ())
     438                 :             :     {
     439                 :       25060 :       gcc_assert (after->ebb () == insn->ebb ());
     440                 :             : 
     441                 :       25060 :       if (insn->bb () != bb)
     442                 :             :         // Force DF to mark the old block as dirty.
     443                 :          18 :         df_insn_delete (rtl);
     444                 :       25060 :       ::remove_insn (rtl);
     445                 :             :     }
     446                 :             : 
     447                 :       25060 :   ::add_insn_after (rtl, after_rtl, cfg_bb);
     448                 :       25060 : }
     449                 :             : 
     450                 :             : // The instruction associated with CHANGE is being changed in-place.
     451                 :             : // Update the DF information for its new pattern.
     452                 :             : static void
     453                 :    10084192 : update_insn_in_place (insn_change &change)
     454                 :             : {
     455                 :    10084192 :   insn_info *insn = change.insn ();
     456                 :    10084192 :   if (dump_file && (dump_flags & TDF_DETAILS))
     457                 :           0 :     fprintf (dump_file, "updating insn %d in-place\n", insn->uid ());
     458                 :    10084192 :   df_insn_rescan (change.rtl ());
     459                 :    10084192 : }
     460                 :             : 
     461                 :             : // Finalize the new list of definitions and uses in CHANGE, removing
     462                 :             : // any uses and definitions that are no longer needed, and converting
     463                 :             : // pending clobbers into actual definitions.
     464                 :             : //
     465                 :             : // POS gives the final position of INSN, which hasn't yet been moved into
     466                 :             : // place.  Keep track of any newly-created set_infos being added with this
     467                 :             : // change by adding them to NEW_SETS.
     468                 :             : void
     469                 :    10109252 : function_info::finalize_new_accesses (insn_change &change, insn_info *pos,
     470                 :             :                                       hash_set<def_info *> &new_sets)
     471                 :             : {
     472                 :    10109252 :   insn_info *insn = change.insn ();
     473                 :             : 
     474                 :             :   // Get a list of all the things that the instruction now references.
     475                 :    10109252 :   vec_rtx_properties properties;
     476                 :    10109252 :   properties.add_insn (insn->rtl (), true);
     477                 :             : 
     478                 :             :   // Build up the new list of definitions.
     479                 :    35161701 :   for (rtx_obj_reference ref : properties.refs ())
     480                 :    25052449 :     if (ref.is_write ())
     481                 :             :       {
     482                 :     9362436 :         def_info *def = find_access (change.new_defs, ref.regno);
     483                 :     9362436 :         gcc_assert (def);
     484                 :             : 
     485                 :     9362436 :         if (def->m_is_temp && is_a<set_info *> (def) && def->last_def ())
     486                 :             :           {
     487                 :             :             // For temporary sets being added with this change, we keep track of
     488                 :             :             // the corresponding permanent def using the last_def link.
     489                 :             :             //
     490                 :             :             // So if we have one of these, follow it to get the permanent def.
     491                 :           0 :             def = def->last_def ();
     492                 :           0 :             gcc_assert (!def->m_is_temp && !def->m_has_been_superceded);
     493                 :             :           }
     494                 :             : 
     495                 :     9362436 :         if (def->m_is_temp)
     496                 :             :           {
     497                 :       30205 :             if (is_a<clobber_info *> (def))
     498                 :       30205 :               def = allocate<clobber_info> (change.insn (), ref.regno);
     499                 :           0 :             else if (is_a<set_info *> (def))
     500                 :             :               {
     501                 :             :                 // Install the permanent set in the last_def link of the
     502                 :             :                 // temporary def.  This allows us to find the permanent def
     503                 :             :                 // later in case we see a second write to the same resource.
     504                 :           0 :                 def_info *perm_def = allocate<set_info> (change.insn (),
     505                 :           0 :                                                          def->resource ());
     506                 :             : 
     507                 :             :                 // Keep track of the new set so we remember to add it to the
     508                 :             :                 // def chain later.
     509                 :           0 :                 if (new_sets.add (perm_def))
     510                 :           0 :                   gcc_unreachable (); // We shouldn't see duplicates here.
     511                 :             : 
     512                 :           0 :                 def->set_last_def (perm_def);
     513                 :           0 :                 def = perm_def;
     514                 :             :               }
     515                 :             :             else
     516                 :           0 :               gcc_unreachable ();
     517                 :             :           }
     518                 :     9332231 :         else if (!def->m_has_been_superceded)
     519                 :             :           {
     520                 :             :             // This is a second or subsequent definition.
     521                 :             :             // See function_info::record_def for a discussion of when
     522                 :             :             // this can happen.
     523                 :         692 :             def->record_reference (ref, false);
     524                 :         692 :             continue;
     525                 :             :           }
     526                 :             :         else
     527                 :             :           {
     528                 :     9331539 :             def->m_has_been_superceded = false;
     529                 :             : 
     530                 :             :             // Clobbers can move around, so remove them from their current
     531                 :             :             // position and them back in their final position.
     532                 :             :             //
     533                 :             :             // At the moment, we don't allow sets to move relative to other
     534                 :             :             // definitions of the same resource, so we can leave those where
     535                 :             :             // they are.  It might be useful to relax this in future.
     536                 :             :             // The main complication is that removing a set would potentially
     537                 :             :             // fuse two adjoining clobber_groups, and adding the set back
     538                 :             :             // would require the group to be split again.
     539                 :     9331539 :             if (is_a<clobber_info *> (def))
     540                 :      927166 :               remove_def (def);
     541                 :     8404373 :             else if (ref.is_reg ())
     542                 :     6409004 :               def->set_mode (ref.mode);
     543                 :     9331539 :             def->set_insn (insn);
     544                 :             :           }
     545                 :     9361744 :         def->record_reference (ref, true);
     546                 :     9361744 :         m_temp_defs.safe_push (def);
     547                 :             :       }
     548                 :             : 
     549                 :             :   // Also keep any explicitly-recorded call clobbers, which are deliberately
     550                 :             :   // excluded from the vec_rtx_properties.  Calls shouldn't move, so we can
     551                 :             :   // keep the definitions in their current position.
     552                 :             :   //
     553                 :             :   // If the change describes a set of memory, but the pattern doesn't
     554                 :             :   // reference memory, keep the set anyway.  This can happen if the
     555                 :             :   // old pattern was a parallel that contained a memory clobber, and if
     556                 :             :   // the new pattern was recognized without that clobber.  Keeping the
     557                 :             :   // set avoids a linear-complexity update to the set's users.
     558                 :             :   //
     559                 :             :   // ??? We could queue an update so that these bogus clobbers are
     560                 :             :   // removed later.
     561                 :    19506741 :   for (def_info *def : change.new_defs)
     562                 :     9397489 :     if (def->m_has_been_superceded
     563                 :     9397489 :         && (def->is_call_clobber () || def->is_mem ()))
     564                 :             :       {
     565                 :           0 :         def->m_has_been_superceded = false;
     566                 :           0 :         def->set_insn (insn);
     567                 :           0 :         m_temp_defs.safe_push (def);
     568                 :             :       }
     569                 :             : 
     570                 :             :   // Install the new list of definitions in CHANGE.
     571                 :    10109252 :   sort_accesses (m_temp_defs);
     572                 :    20218504 :   access_array accesses = temp_access_array (m_temp_defs);
     573                 :    10109252 :   change.new_defs = def_array (accesses);
     574                 :    10109252 :   m_temp_defs.truncate (0);
     575                 :             : 
     576                 :             :   // Create temporary copies of use_infos that are already attached to
     577                 :             :   // other insns, which could happen if the uses come from unchanging
     578                 :             :   // insns or if they have been used by earlier changes.  Doing this
     579                 :             :   // makes it easier to detect multiple reads below.
     580                 :    10109252 :   auto *unshared_uses_base = XOBNEWVEC (&m_temp_obstack, access_info *,
     581                 :             :                                         change.new_uses.size ());
     582                 :    10109252 :   unsigned int i = 0;
     583                 :    28629912 :   for (use_info *use : change.new_uses)
     584                 :             :     {
     585                 :    18520660 :       if (!use->m_has_been_superceded)
     586                 :             :         {
     587                 :     7058860 :           use = allocate_temp<use_info> (insn, use->resource (), use->def ());
     588                 :     7058860 :           use->m_has_been_superceded = true;
     589                 :     7058860 :           use->m_is_temp = true;
     590                 :             :         }
     591                 :    18520660 :       unshared_uses_base[i++] = use;
     592                 :             :     }
     593                 :    10109252 :   auto unshared_uses = use_array (unshared_uses_base, change.new_uses.size ());
     594                 :             : 
     595                 :             :   // Add (possibly temporary) uses to m_temp_uses for each resource.
     596                 :             :   // If there are multiple references to the same resource, aggregate
     597                 :             :   // information in the modes and flags.
     598                 :    10109252 :   use_info *mem_use = nullptr;
     599                 :    35161701 :   for (rtx_obj_reference ref : properties.refs ())
     600                 :    25052449 :     if (ref.is_read ())
     601                 :             :       {
     602                 :    15704807 :         unsigned int regno = ref.regno;
     603                 :    15704807 :         machine_mode mode = ref.is_reg () ? ref.mode : BLKmode;
     604                 :    15704807 :         use_info *use = find_access (unshared_uses, ref.regno);
     605                 :    15704807 :         if (!use)
     606                 :             :           {
     607                 :             :             // For now, we only support inferring uses of mem.
     608                 :           0 :             gcc_assert (regno == MEM_REGNO);
     609                 :             : 
     610                 :           0 :             if (mem_use)
     611                 :             :               {
     612                 :           0 :                 mem_use->record_reference (ref, false);
     613                 :           0 :                 continue;
     614                 :             :               }
     615                 :             : 
     616                 :           0 :             resource_info resource { mode, regno };
     617                 :           0 :             auto def = find_def (resource, pos).prev_def (pos);
     618                 :           0 :             auto set = safe_dyn_cast <set_info *> (def);
     619                 :           0 :             gcc_assert (set);
     620                 :           0 :             mem_use = allocate<use_info> (insn, resource, set);
     621                 :           0 :             mem_use->record_reference (ref, true);
     622                 :           0 :             m_temp_uses.safe_push (mem_use);
     623                 :           0 :             continue;
     624                 :           0 :           }
     625                 :             : 
     626                 :    15704807 :         if (use->m_has_been_superceded)
     627                 :             :           {
     628                 :             :             // This is the first reference to the resource.
     629                 :    15278993 :             bool is_temp = use->m_is_temp;
     630                 :    15278993 :             *use = use_info (insn, resource_info { mode, regno }, use->def ());
     631                 :    15278993 :             use->m_is_temp = is_temp;
     632                 :    15278993 :             use->record_reference (ref, true);
     633                 :    15278993 :             m_temp_uses.safe_push (use);
     634                 :             :           }
     635                 :             :         else
     636                 :             :           {
     637                 :             :             // Record the mode of the largest use.  The choice is arbitrary if
     638                 :             :             // the instruction (unusually) references the same register in two
     639                 :             :             // different but equal-sized modes.
     640                 :      425814 :             if (HARD_REGISTER_NUM_P (regno)
     641                 :      425814 :                 && partial_subreg_p (use->mode (), mode))
     642                 :          23 :               use->set_mode (mode);
     643                 :      425814 :             use->record_reference (ref, false);
     644                 :             :           }
     645                 :             :       }
     646                 :             : 
     647                 :             :   // Replace any temporary uses and definitions with real ones.
     648                 :    25388245 :   for (unsigned int i = 0; i < m_temp_uses.length (); ++i)
     649                 :             :     {
     650                 :    15278993 :       auto *use = as_a<use_info *> (m_temp_uses[i]);
     651                 :    15278993 :       if (use->m_is_temp)
     652                 :             :         {
     653                 :     6967947 :           m_temp_uses[i] = use = allocate<use_info> (*use);
     654                 :     6967947 :           use->m_is_temp = false;
     655                 :     6967947 :           set_info *def = use->def ();
     656                 :     6967947 :           if (!def || !def->m_is_temp)
     657                 :     6955061 :             continue;
     658                 :             : 
     659                 :       12886 :           if (auto phi = dyn_cast<phi_info *> (def))
     660                 :             :             {
     661                 :             :               // Handle cases in which the value was previously not used
     662                 :             :               // within the block.
     663                 :       12886 :               gcc_assert (phi->is_degenerate ());
     664                 :       12886 :               phi = create_degenerate_phi (phi->ebb (), phi->input_value (0));
     665                 :       12886 :               use->set_def (phi);
     666                 :             :             }
     667                 :             :           else
     668                 :             :             {
     669                 :             :               // The temporary def may also be a set added with this change, in
     670                 :             :               // which case the permanent set is stored in the last_def link,
     671                 :             :               // and we need to update the use to refer to the permanent set.
     672                 :           0 :               gcc_assert (is_a<set_info *> (def));
     673                 :           0 :               auto perm_set = as_a<set_info *> (def->last_def ());
     674                 :           0 :               gcc_assert (!perm_set->is_temporary ());
     675                 :           0 :               use->set_def (perm_set);
     676                 :             :             }
     677                 :             :         }
     678                 :             :     }
     679                 :             : 
     680                 :             :   // Install the new list of uses in CHANGE.
     681                 :    10109252 :   sort_accesses (m_temp_uses);
     682                 :    20218504 :   change.new_uses = use_array (temp_access_array (m_temp_uses));
     683                 :    10109252 :   m_temp_uses.truncate (0);
     684                 :             : 
     685                 :             :   // Record the new instruction-wide properties.
     686                 :    10109252 :   insn->set_properties (properties);
     687                 :    10109252 : }
     688                 :             : 
     689                 :             : // Copy information from CHANGE to its underlying insn_info, given that
     690                 :             : // the insn_info has already been placed appropriately.  NEW_SETS contains the
     691                 :             : // new set_infos that are being added as part of this change (as opposed to
     692                 :             : // being moved or repurposed from existing instructions).
     693                 :             : void
     694                 :    12258492 : function_info::apply_changes_to_insn (insn_change &change,
     695                 :             :                                       hash_set<def_info *> &new_sets)
     696                 :             : {
     697                 :    12258492 :   insn_info *insn = change.insn ();
     698                 :    12258492 :   if (change.is_deletion ())
     699                 :             :     {
     700                 :     2149240 :       insn->set_accesses (nullptr, 0, 0);
     701                 :     2149240 :       return;
     702                 :             :     }
     703                 :             : 
     704                 :             :   // Copy the cost.
     705                 :    10109252 :   insn->set_cost (change.new_cost);
     706                 :             : 
     707                 :             :   // Add all clobbers and newly-created sets.  Existing sets and call
     708                 :             :   // clobbers never move relative to other definitions, so are OK as-is.
     709                 :    19470996 :   for (def_info *def : change.new_defs)
     710                 :     9361744 :     if ((is_a<clobber_info *> (def) && !def->is_call_clobber ())
     711                 :    10319115 :         || (is_a<set_info *> (def) && new_sets.contains (def)))
     712                 :      957371 :       add_def (def);
     713                 :             : 
     714                 :             :   // Add all uses, now that their position is final.
     715                 :    25388245 :   for (use_info *use : change.new_uses)
     716                 :             :     {
     717                 :    15278993 :       if (use->def ())
     718                 :    15241472 :         commit_make_use_available (use);
     719                 :    15278993 :       add_use (use);
     720                 :             :     }
     721                 :             : 
     722                 :             :   // Copy the uses and definitions.
     723                 :    10109252 :   unsigned int num_defs = change.new_defs.size ();
     724                 :    10109252 :   unsigned int num_uses = change.new_uses.size ();
     725                 :    10109252 :   if (num_defs + num_uses <= insn->num_defs () + insn->num_uses ())
     726                 :     9825711 :     insn->copy_accesses (change.new_defs, change.new_uses);
     727                 :             :   else
     728                 :             :     {
     729                 :      283541 :       access_array_builder builder (&m_obstack);
     730                 :      283541 :       builder.reserve (num_defs + num_uses);
     731                 :             : 
     732                 :      636934 :       for (def_info *def : change.new_defs)
     733                 :      353393 :         builder.quick_push (def);
     734                 :     1007977 :       for (use_info *use : change.new_uses)
     735                 :      724436 :         builder.quick_push (use);
     736                 :             : 
     737                 :      283541 :       insn->set_accesses (builder.finish ().begin (), num_defs, num_uses);
     738                 :      283541 :     }
     739                 :             : 
     740                 :    10109252 :   insn->m_is_temp = false;
     741                 :             : }
     742                 :             : 
     743                 :             : // Add a temporary placeholder instruction after AFTER.
     744                 :             : insn_info *
     745                 :       25060 : function_info::add_placeholder_after (insn_info *after)
     746                 :             : {
     747                 :       25060 :   insn_info *insn = allocate_temp<insn_info> (after->bb (), nullptr, -1);
     748                 :       25060 :   add_insn_after (insn, after);
     749                 :       25060 :   return insn;
     750                 :             : }
     751                 :             : 
     752                 :             : // See the comment above the declaration.
     753                 :             : void
     754                 :     6624692 : function_info::change_insns (array_slice<insn_change *> changes)
     755                 :             : {
     756                 :     6624692 :   auto watermark = temp_watermark ();
     757                 :             : 
     758                 :     6624692 :   insn_info *min_insn = m_first_insn;
     759                 :    18883184 :   for (insn_change *change : changes)
     760                 :             :     {
     761                 :             :       // Tentatively mark all the old uses and definitions for deletion.
     762                 :    30861145 :       for (use_info *use : change->old_uses ())
     763                 :             :         {
     764                 :    18602653 :           use->m_has_been_superceded = true;
     765                 :    18602653 :           remove_use (use);
     766                 :             :         }
     767                 :    23881441 :       for (def_info *def : change->old_defs ())
     768                 :    11622949 :         def->m_has_been_superceded = true;
     769                 :             : 
     770                 :    12258492 :       if (!change->is_deletion ())
     771                 :             :         {
     772                 :             :           // Remove any notes that are no longer relevant.
     773                 :    10109252 :           if (!change->insn ()->m_is_temp)
     774                 :    10109252 :             update_notes (change->rtl ());
     775                 :             : 
     776                 :             :           // Make sure that the placement of this instruction would still
     777                 :             :           // leave room for previous instructions.
     778                 :    10109252 :           change->move_range = move_later_than (change->move_range, min_insn);
     779                 :    10109252 :           if (!canonicalize_move_range (change->move_range, change->insn ()))
     780                 :             :             // verify_insn_changes is supposed to make sure that this holds.
     781                 :           0 :             gcc_unreachable ();
     782                 :    10109252 :           min_insn = later_insn (min_insn, change->move_range.first);
     783                 :             : 
     784                 :    10109252 :           if (change->insn ()->m_is_temp)
     785                 :             :             {
     786                 :           0 :               change->m_insn = allocate<insn_info> (change->insn ()->bb (),
     787                 :             :                                                     change->rtl (),
     788                 :             :                                                     change->insn_uid ());
     789                 :             : 
     790                 :             :               // Set the flag again so subsequent logic is aware.
     791                 :             :               // It will be cleared later on.
     792                 :           0 :               change->m_insn->m_is_temp = true;
     793                 :             :             }
     794                 :             :         }
     795                 :             :     }
     796                 :             : 
     797                 :             :   // Walk backwards through the changes, allocating specific positions
     798                 :             :   // to each one.  Update the underlying RTL and its associated DF
     799                 :             :   // information.
     800                 :     6624692 :   insn_info *following_insn = nullptr;
     801                 :     6624692 :   auto_vec<insn_info *, 16> placeholders;
     802                 :     6624692 :   placeholders.safe_grow_cleared (changes.size ());
     803                 :    18883184 :   for (unsigned int i = changes.size (); i-- > 0;)
     804                 :             :     {
     805                 :    12258492 :       insn_change &change = *changes[i];
     806                 :    12258492 :       insn_info *placeholder = nullptr;
     807                 :    12258492 :       possibly_queue_changes (change);
     808                 :    12258492 :       if (change.is_deletion ())
     809                 :     2149240 :         delete_insn (change);
     810                 :             :       else
     811                 :             :         {
     812                 :             :           // Make sure that this instruction comes before later ones.
     813                 :    10109252 :           if (following_insn)
     814                 :             :             {
     815                 :     3519852 :               change.move_range = move_earlier_than (change.move_range,
     816                 :             :                                                      following_insn);
     817                 :     3519852 :               if (!canonicalize_move_range (change.move_range,
     818                 :             :                                             change.insn ()))
     819                 :             :                 // verify_insn_changes is supposed to make sure that this
     820                 :             :                 // holds.
     821                 :           0 :                 gcc_unreachable ();
     822                 :             :             }
     823                 :             : 
     824                 :             :           // Decide which instruction INSN should go after.
     825                 :    10109252 :           insn_info *after = choose_insn_placement (change);
     826                 :             : 
     827                 :             :           // If INSN is moving, insert a placeholder insn_info at the
     828                 :             :           // new location.  We can't move INSN itself yet because it
     829                 :             :           // might still be referenced by earlier move ranges.
     830                 :    10109252 :           insn_info *insn = change.insn ();
     831                 :    10109252 :           if (after == insn || after == insn->prev_nondebug_insn ())
     832                 :             :             {
     833                 :    10084192 :               update_insn_in_place (change);
     834                 :    10084192 :               following_insn = insn;
     835                 :             :             }
     836                 :             :           else
     837                 :             :             {
     838                 :       25060 :               move_insn (change, after);
     839                 :       25060 :               placeholder = add_placeholder_after (after);
     840                 :       25060 :               following_insn = placeholder;
     841                 :             :             }
     842                 :             :         }
     843                 :    12258492 :       placeholders[i] = placeholder;
     844                 :             :     }
     845                 :             : 
     846                 :             :   // We need to keep track of newly-added sets as these need adding to
     847                 :             :   // the def chain later.
     848                 :     6624692 :   hash_set<def_info *> new_sets;
     849                 :             : 
     850                 :             :   // Finalize the new list of accesses for each change.  Don't install them yet,
     851                 :             :   // so that we still have access to the old lists below.
     852                 :             :   //
     853                 :             :   // Note that we do this forwards instead of in the backwards loop above so
     854                 :             :   // that any new defs being inserted are processed before new uses of those
     855                 :             :   // defs, so that the (initially) temporary uses referring to temporary defs
     856                 :             :   // can be easily updated to become permanent uses referring to permanent defs.
     857                 :    18883184 :   for (unsigned i = 0; i < changes.size (); i++)
     858                 :             :     {
     859                 :    12258492 :       insn_change &change = *changes[i];
     860                 :    12258492 :       insn_info *placeholder = placeholders[i];
     861                 :    12258492 :       if (!change.is_deletion ())
     862                 :    20193444 :         finalize_new_accesses (change,
     863                 :    10084192 :                                placeholder ? placeholder : change.insn (),
     864                 :             :                                new_sets);
     865                 :             :     }
     866                 :             : 
     867                 :             :   // Remove all definitions that are no longer needed.  After the above,
     868                 :             :   // the only uses of such definitions should be dead phis and now-redundant
     869                 :             :   // live-out uses.
     870                 :             :   //
     871                 :             :   // In particular, this means that consumers must handle debug
     872                 :             :   // instructions before removing a set.
     873                 :    18883184 :   for (insn_change *change : changes)
     874                 :    23881441 :     for (def_info *def : change->old_defs ())
     875                 :    11622949 :       if (def->m_has_been_superceded)
     876                 :             :         {
     877                 :     2291410 :           auto *set = dyn_cast<set_info *> (def);
     878                 :     2133898 :           if (set && set->has_any_uses ())
     879                 :      683547 :             process_uses_of_deleted_def (set);
     880                 :     2291410 :           remove_def (def);
     881                 :             :         }
     882                 :             : 
     883                 :             :   // Move the insn_infos to their new locations.
     884                 :    18883184 :   for (unsigned int i = 0; i < changes.size (); ++i)
     885                 :             :     {
     886                 :    12258492 :       insn_change &change = *changes[i];
     887                 :    12258492 :       insn_info *insn = change.insn ();
     888                 :    12258492 :       if (change.is_deletion ())
     889                 :             :         {
     890                 :     2149240 :           if (rtx_insn *rtl = insn->rtl ())
     891                 :     2149240 :             ::remove_insn (rtl); // Remove the underlying RTL insn.
     892                 :     2149240 :           remove_insn (insn);
     893                 :             :         }
     894                 :    10109252 :       else if (insn_info *placeholder = placeholders[i])
     895                 :             :         {
     896                 :             :           // Check if earlier movements turned a move into a no-op.
     897                 :       25060 :           if (placeholder->prev_nondebug_insn () == insn
     898                 :       25060 :               || placeholder->next_nondebug_insn () == insn)
     899                 :             :             {
     900                 :           0 :               remove_insn (placeholder);
     901                 :           0 :               placeholders[i] = nullptr;
     902                 :             :             }
     903                 :             :           else
     904                 :             :             {
     905                 :       25060 :               insn_info *after = placeholder->prev_any_insn ();
     906                 :       25060 :               if (!insn->is_temporary ())
     907                 :       25060 :                 remove_insn (insn);
     908                 :       25060 :               replace_nondebug_insn (placeholder, insn);
     909                 :       25060 :               insn->set_bb (after->bb ());
     910                 :             :             }
     911                 :             :         }
     912                 :             :     }
     913                 :             : 
     914                 :             :   // Apply the changes to the underlying insn_infos.
     915                 :    18883184 :   for (insn_change *change : changes)
     916                 :    12258492 :     apply_changes_to_insn (*change, new_sets);
     917                 :             : 
     918                 :             :   // Now that the insns and accesses are up to date, add any REG_UNUSED notes.
     919                 :    18883184 :   for (insn_change *change : changes)
     920                 :    12258492 :     if (!change->is_deletion ())
     921                 :    10109252 :       add_reg_unused_notes (change->insn ());
     922                 :     6624692 : }
     923                 :             : 
     924                 :             : // See the comment above the declaration.
     925                 :             : void
     926                 :     3034491 : function_info::change_insn (insn_change &change)
     927                 :             : {
     928                 :     3034491 :   insn_change *changes[] = { &change };
     929                 :     3034491 :   return change_insns (changes);
     930                 :             : }
     931                 :             : 
     932                 :             : // Try to adjust CHANGE so that its pattern can include clobber rtx CLOBBER.
     933                 :             : // Return true on success.
     934                 :             : //
     935                 :             : // ADD_REGNO_CLOBBER is a specialization of function_info::add_regno_clobber
     936                 :             : // for a specific caller-provided predicate.
     937                 :             : static bool
     938                 :     2641709 : add_clobber (insn_change &change, add_regno_clobber_fn add_regno_clobber,
     939                 :             :              rtx clobber)
     940                 :             : {
     941                 :     2641709 :   rtx pat = PATTERN (change.rtl ());
     942                 :     2641709 :   gcc_assert (GET_CODE (clobber) == CLOBBER);
     943                 :     2641709 :   rtx dest = XEXP (clobber, 0);
     944                 :     2641709 :   if (GET_CODE (dest) == SCRATCH)
     945                 :             :     {
     946                 :      109290 :       if (reload_completed)
     947                 :             :         {
     948                 :       41224 :           if (dump_file && (dump_flags & TDF_DETAILS))
     949                 :             :             {
     950                 :             :               // ??? Maybe we could try to do some RA here?
     951                 :           0 :               fprintf (dump_file, "instruction requires a scratch"
     952                 :             :                        " after reload:\n");
     953                 :           0 :               print_rtl_single (dump_file, pat);
     954                 :             :             }
     955                 :       41224 :           return false;
     956                 :             :         }
     957                 :             :       return true;
     958                 :             :     }
     959                 :             : 
     960                 :     2532419 :   gcc_assert (REG_P (dest));
     961                 :     5061830 :   for (unsigned int regno = REGNO (dest); regno != END_REGNO (dest); ++regno)
     962                 :     2532419 :     if (!add_regno_clobber (change, regno))
     963                 :             :       {
     964                 :        3008 :         if (dump_file && (dump_flags & TDF_DETAILS))
     965                 :             :           {
     966                 :           0 :             fprintf (dump_file, "cannot clobber live register %d in:\n",
     967                 :             :                      regno);
     968                 :           0 :             print_rtl_single (dump_file, pat);
     969                 :             :           }
     970                 :        3008 :         return false;
     971                 :             :       }
     972                 :             :   return true;
     973                 :             : }
     974                 :             : 
     975                 :             : // See if PARALLEL pattern PAT clobbers any of the registers in ACCESSES.
     976                 :             : // Return one such access if so, otherwise return null.
     977                 :             : static access_info *
     978                 :     4274058 : find_clobbered_access (access_array accesses, rtx pat)
     979                 :             : {
     980                 :     4274058 :   rtx subpat;
     981                 :    13348680 :   for (int i = 0; i < XVECLEN (pat, 0); ++i)
     982                 :     9088335 :     if (GET_CODE (subpat = XVECEXP (pat, 0, i)) == CLOBBER)
     983                 :             :       {
     984                 :     4691962 :         rtx x = XEXP (subpat, 0);
     985                 :     4691962 :         if (REG_P (x))
     986                 :    13616510 :           for (auto *access : accesses)
     987                 :     9165254 :             if (access->regno () >= REGNO (x)
     988                 :     9165254 :                 && access->regno () < END_REGNO (x))
     989                 :             :               return access;
     990                 :             :       }
     991                 :             :   return nullptr;
     992                 :             : }
     993                 :             : 
     994                 :             : // Try to recognize the new form of the insn associated with CHANGE,
     995                 :             : // adding any clobbers that are necessary to make the instruction match
     996                 :             : // an .md pattern.  Return true on success.
     997                 :             : //
     998                 :             : // ADD_REGNO_CLOBBER is a specialization of function_info::add_regno_clobber
     999                 :             : // for a specific caller-provided predicate.
    1000                 :             : static bool
    1001                 :    49149684 : recog_level2 (insn_change &change, add_regno_clobber_fn add_regno_clobber)
    1002                 :             : {
    1003                 :    49149684 :   insn_change_watermark insn_watermark;
    1004                 :    49149684 :   rtx_insn *rtl = change.rtl ();
    1005                 :    49149684 :   rtx pat = PATTERN (rtl);
    1006                 :    49149684 :   int num_clobbers = 0;
    1007                 :    49149684 :   int icode = -1;
    1008                 :    49149684 :   bool asm_p = asm_noperands (pat) >= 0;
    1009                 :    49149684 :   if (asm_p)
    1010                 :             :     {
    1011                 :       62772 :       if (!check_asm_operands (pat))
    1012                 :             :         {
    1013                 :       59608 :           if (dump_file && (dump_flags & TDF_DETAILS))
    1014                 :             :             {
    1015                 :           0 :               fprintf (dump_file, "failed to match this asm instruction:\n");
    1016                 :           0 :               print_rtl_single (dump_file, pat);
    1017                 :             :             }
    1018                 :       59608 :           return false;
    1019                 :             :         }
    1020                 :             :     }
    1021                 :    49086912 :   else if (noop_move_p (rtl))
    1022                 :             :     {
    1023                 :        9843 :       INSN_CODE (rtl) = NOOP_MOVE_INSN_CODE;
    1024                 :        9843 :       if (dump_file && (dump_flags & TDF_DETAILS))
    1025                 :             :         {
    1026                 :           0 :           fprintf (dump_file, "instruction becomes a no-op:\n");
    1027                 :           0 :           print_rtl_single (dump_file, pat);
    1028                 :             :         }
    1029                 :        9843 :       insn_watermark.keep ();
    1030                 :        9843 :       return true;
    1031                 :             :     }
    1032                 :             :   else
    1033                 :             :     {
    1034                 :    49077069 :       icode = ::recog (pat, rtl, &num_clobbers);
    1035                 :    49077069 :       if (icode < 0)
    1036                 :             :         {
    1037                 :    32240945 :           if (dump_file && (dump_flags & TDF_DETAILS))
    1038                 :             :             {
    1039                 :           0 :               fprintf (dump_file, "failed to match this instruction:\n");
    1040                 :           0 :               print_rtl_single (dump_file, pat);
    1041                 :             :             }
    1042                 :    32240945 :           return false;
    1043                 :             :         }
    1044                 :             :     }
    1045                 :             : 
    1046                 :    16839288 :   auto prev_new_defs = change.new_defs;
    1047                 :    16839288 :   auto prev_move_range = change.move_range;
    1048                 :    16839288 :   if (num_clobbers > 0)
    1049                 :             :     {
    1050                 :             :       // ??? It would be good to have a way of recycling the rtxes on failure,
    1051                 :             :       // but any attempt to cache old PARALLELs would at best be a half
    1052                 :             :       // measure, since add_clobbers would still generate fresh clobbers
    1053                 :             :       // each time.  It would be better to have a more general recycling
    1054                 :             :       // mechanism that all rtx passes can use.
    1055                 :     2633698 :       rtvec newvec;
    1056                 :     2633698 :       int oldlen;
    1057                 :     2633698 :       if (GET_CODE (pat) == PARALLEL)
    1058                 :             :         {
    1059                 :       19429 :           oldlen = XVECLEN (pat, 0);
    1060                 :       19429 :           newvec = rtvec_alloc (num_clobbers + oldlen);
    1061                 :       58311 :           for (int i = 0; i < oldlen; ++i)
    1062                 :       38882 :             RTVEC_ELT (newvec, i) = XVECEXP (pat, 0, i);
    1063                 :             :         }
    1064                 :             :       else
    1065                 :             :         {
    1066                 :     2614269 :           oldlen = 1;
    1067                 :     2614269 :           newvec = rtvec_alloc (num_clobbers + oldlen);
    1068                 :     2614269 :           RTVEC_ELT (newvec, 0) = pat;
    1069                 :             :         }
    1070                 :     2633698 :       rtx newpat = gen_rtx_PARALLEL (VOIDmode, newvec);
    1071                 :     2633698 :       add_clobbers (newpat, icode);
    1072                 :     2633698 :       validate_change (rtl, &PATTERN (rtl), newpat, true);
    1073                 :     5231175 :       for (int i = 0; i < num_clobbers; ++i)
    1074                 :     2641709 :         if (!add_clobber (change, add_regno_clobber,
    1075                 :     2641709 :                           XVECEXP (newpat, 0, oldlen + i)))
    1076                 :             :           {
    1077                 :       44232 :             change.new_defs = prev_new_defs;
    1078                 :       44232 :             change.move_range = prev_move_range;
    1079                 :       44232 :             return false;
    1080                 :             :           }
    1081                 :             : 
    1082                 :             :       pat = newpat;
    1083                 :             :     }
    1084                 :             : 
    1085                 :    16795056 :   INSN_CODE (rtl) = icode;
    1086                 :    16795056 :   if (recog_data.insn == rtl)
    1087                 :           0 :     recog_data.insn = nullptr;
    1088                 :             : 
    1089                 :             :   // See if the pattern contains any hard-coded clobbers of registers
    1090                 :             :   // that are also inputs to the instruction.  The standard rtl semantics
    1091                 :             :   // treat such clobbers as earlyclobbers, since there is no way of proving
    1092                 :             :   // which clobbers conflict with the inputs and which don't.
    1093                 :             :   //
    1094                 :             :   // (Non-hard-coded clobbers are handled by constraint satisfaction instead.)
    1095                 :    16795056 :   rtx subpat;
    1096                 :    16795056 :   if (GET_CODE (pat) == PARALLEL)
    1097                 :    13255644 :     for (int i = 0; i < XVECLEN (pat, 0); ++i)
    1098                 :     8919788 :       if (GET_CODE (subpat = XVECEXP (pat, 0, i)) == CLOBBER
    1099                 :     8919788 :           && REG_P (XEXP (subpat, 0)))
    1100                 :             :         {
    1101                 :             :           // Stub out all operands, so that we can tell which registers
    1102                 :             :           // are hard-coded.
    1103                 :     4274058 :           extract_insn (rtl);
    1104                 :    17260091 :           for (int j = 0; j < recog_data.n_operands; ++j)
    1105                 :    12986033 :             *recog_data.operand_loc[j] = pc_rtx;
    1106                 :             : 
    1107                 :     4274058 :           auto *use = find_clobbered_access (change.new_uses, pat);
    1108                 :             : 
    1109                 :             :           // Restore the operands.
    1110                 :    17260091 :           for (int j = 0; j < recog_data.n_operands; ++j)
    1111                 :    12986033 :             *recog_data.operand_loc[j] = recog_data.operand[j];
    1112                 :             : 
    1113                 :     4274058 :           if (use)
    1114                 :             :             {
    1115                 :       13713 :               if (dump_file && (dump_flags & TDF_DETAILS))
    1116                 :             :                 {
    1117                 :           0 :                   fprintf (dump_file, "register %d is both clobbered"
    1118                 :             :                            " and used as an input:\n", use->regno ());
    1119                 :           0 :                   print_rtl_single (dump_file, pat);
    1120                 :             :                 }
    1121                 :       13713 :               return false;
    1122                 :             :             }
    1123                 :             :         }
    1124                 :             : 
    1125                 :             :   // Per rtl.texi, registers that are modified using RTX_AUTOINC operations
    1126                 :             :   // cannot also appear outside an address.
    1127                 :    16781343 :   vec_rtx_properties properties;
    1128                 :    16781343 :   properties.add_pattern (pat);
    1129                 :    64236749 :   for (rtx_obj_reference def : properties.refs ())
    1130                 :    47633168 :     if (def.is_pre_post_modify ())
    1131                 :      177762 :       for (rtx_obj_reference use : properties.refs ())
    1132                 :      177762 :         if (def.regno == use.regno && !use.in_address ())
    1133                 :             :           {
    1134                 :      177762 :             if (dump_file && (dump_flags & TDF_DETAILS))
    1135                 :             :               {
    1136                 :           0 :                 fprintf (dump_file, "register %d is both auto-modified"
    1137                 :             :                          " and used outside an address:\n", def.regno);
    1138                 :           0 :                 print_rtl_single (dump_file, pat);
    1139                 :             :               }
    1140                 :      177762 :             return false;
    1141                 :             :           }
    1142                 :             : 
    1143                 :             :   // check_asm_operands checks the constraints after RA, so we don't
    1144                 :             :   // need to do it again.
    1145                 :    16603581 :   if (reload_completed && !asm_p)
    1146                 :             :     {
    1147                 :     3502367 :       extract_insn (rtl);
    1148                 :     3502367 :       if (!constrain_operands (1, get_preferred_alternatives (rtl)))
    1149                 :             :         {
    1150                 :     1928357 :           if (dump_file && (dump_flags & TDF_DETAILS))
    1151                 :             :             {
    1152                 :           0 :               if (asm_p)
    1153                 :             :                 fprintf (dump_file, "asm does not match its constraints:\n");
    1154                 :           0 :               else if (const char *name = get_insn_name (icode))
    1155                 :           0 :                 fprintf (dump_file, "instruction does not match the"
    1156                 :             :                          " constraints for %s:\n", name);
    1157                 :             :               else
    1158                 :           0 :                 fprintf (dump_file, "instruction does not match its"
    1159                 :             :                          " constraints:\n");
    1160                 :           0 :               print_rtl_single (dump_file, pat);
    1161                 :             :             }
    1162                 :     1928357 :           change.new_defs = prev_new_defs;
    1163                 :     1928357 :           change.move_range = prev_move_range;
    1164                 :     1928357 :           return false;
    1165                 :             :         }
    1166                 :             :     }
    1167                 :             : 
    1168                 :    14675224 :   if (dump_file && (dump_flags & TDF_DETAILS))
    1169                 :             :     {
    1170                 :           0 :       const char *name;
    1171                 :           0 :       if (!asm_p && (name = get_insn_name (icode)))
    1172                 :           0 :         fprintf (dump_file, "successfully matched this instruction "
    1173                 :             :                  "to %s:\n", name);
    1174                 :             :       else
    1175                 :           0 :         fprintf (dump_file, "successfully matched this instruction:\n");
    1176                 :           0 :       print_rtl_single (dump_file, pat);
    1177                 :             :     }
    1178                 :             : 
    1179                 :    14675224 :   insn_watermark.keep ();
    1180                 :    14675224 :   return true;
    1181                 :    49149684 : }
    1182                 :             : 
    1183                 :             : // Try to recognize the new form of the insn associated with CHANGE,
    1184                 :             : // adding and removing clobbers as necessary to make the instruction
    1185                 :             : // match an .md pattern.  Return true on success, otherwise leave
    1186                 :             : // CHANGE as it was on entry.
    1187                 :             : //
    1188                 :             : // ADD_REGNO_CLOBBER is a specialization of function_info::add_regno_clobber
    1189                 :             : // for a specific caller-provided predicate.
    1190                 :             : bool
    1191                 :    43105933 : rtl_ssa::recog_internal (insn_change &change,
    1192                 :             :                          add_regno_clobber_fn add_regno_clobber)
    1193                 :             : {
    1194                 :             :   // Accept all changes to debug instructions.
    1195                 :    43105933 :   insn_info *insn = change.insn ();
    1196                 :    43105933 :   if (insn->is_debug_insn ())
    1197                 :             :     return true;
    1198                 :             : 
    1199                 :    42731240 :   rtx_insn *rtl = insn->rtl ();
    1200                 :    42731240 :   rtx pat = PATTERN (rtl);
    1201                 :    42731240 :   if (GET_CODE (pat) == PARALLEL && asm_noperands (pat) < 0)
    1202                 :             :     {
    1203                 :             :       // Try to remove trailing (clobber (scratch)) rtxes, since the new form
    1204                 :             :       // of the instruction might not need those scratches.  recog will add
    1205                 :             :       // back any that are needed.
    1206                 :    11210604 :       int len = XVECLEN (pat, 0);
    1207                 :    11210604 :       int new_len = len;
    1208                 :    11210604 :       while (new_len > 0
    1209                 :    11336270 :              && GET_CODE (XVECEXP (pat, 0, new_len - 1)) == CLOBBER
    1210                 :    18828813 :              && GET_CODE (XEXP (XVECEXP (pat, 0, new_len - 1), 0)) == SCRATCH)
    1211                 :             :         new_len -= 1;
    1212                 :             : 
    1213                 :    11210604 :       int old_num_changes = num_validated_changes ();
    1214                 :    11210604 :       validate_change_xveclen (rtl, &PATTERN (rtl), new_len, true);
    1215                 :    11210604 :       if (recog_level2 (change, add_regno_clobber))
    1216                 :             :         return true;
    1217                 :    10069793 :       cancel_changes (old_num_changes);
    1218                 :             : 
    1219                 :             :       // Try to remove all trailing clobbers.  For example, a pattern that
    1220                 :             :       // used to clobber the flags might no longer need to do so.
    1221                 :    10069793 :       int prev_len = new_len;
    1222                 :    10069793 :       while (new_len > 0
    1223                 :    16671648 :              && GET_CODE (XVECEXP (pat, 0, new_len - 1)) == CLOBBER)
    1224                 :             :         new_len -= 1;
    1225                 :    10069793 :       if (new_len != prev_len)
    1226                 :             :         {
    1227                 :     6418444 :           validate_change_xveclen (rtl, &PATTERN (rtl), new_len, true);
    1228                 :     6418444 :           if (recog_level2 (change, add_regno_clobber))
    1229                 :             :             return true;
    1230                 :     5766845 :           cancel_changes (old_num_changes);
    1231                 :             :         }
    1232                 :     9418194 :       return false;
    1233                 :             :     }
    1234                 :             : 
    1235                 :    31520636 :   return recog_level2 (change, add_regno_clobber);
    1236                 :             : }
    1237                 :             : 
    1238                 :             : // See the comment above the declaration.
    1239                 :             : bool
    1240                 :     3966710 : function_info::perform_pending_updates ()
    1241                 :             : {
    1242                 :     3966710 :   bool changed_cfg = false;
    1243                 :     3966710 :   bool changed_jumps = false;
    1244                 :     3979230 :   for (insn_info *insn : m_queued_insn_updates)
    1245                 :             :     {
    1246                 :        5812 :       rtx_insn *rtl = insn->rtl ();
    1247                 :        5812 :       if (NOTE_P (rtl))
    1248                 :             :         // The insn was later optimized away, typically to a NOTE_INSN_DELETED.
    1249                 :             :         ;
    1250                 :        5628 :       else if (JUMP_P (rtl))
    1251                 :             :         {
    1252                 :         198 :           if (INSN_CODE (rtl) == NOOP_MOVE_INSN_CODE)
    1253                 :             :             {
    1254                 :         180 :               ::delete_insn (rtl);
    1255                 :         180 :               bitmap_set_bit (m_need_to_purge_dead_edges,
    1256                 :         180 :                               insn->bb ()->index ());
    1257                 :             :             }
    1258                 :          18 :           else if (returnjump_p (rtl) || any_uncondjump_p (rtl))
    1259                 :             :             {
    1260                 :          18 :               mark_jump_label (PATTERN (rtl), rtl, 0);
    1261                 :          18 :               update_cfg_for_uncondjump (rtl);
    1262                 :          18 :               changed_cfg = true;
    1263                 :          18 :               changed_jumps = true;
    1264                 :             :             }
    1265                 :             :         }
    1266                 :        5430 :       else if (INSN_CODE (rtl) == NOOP_MOVE_INSN_CODE)
    1267                 :        5429 :         ::delete_insn (rtl);
    1268                 :             :       else
    1269                 :             :         {
    1270                 :           1 :           rtx pattern = PATTERN (rtl);
    1271                 :           1 :           if (GET_CODE (pattern) == TRAP_IF
    1272                 :           0 :               && XEXP (pattern, 0) == const1_rtx)
    1273                 :             :             {
    1274                 :           0 :               remove_edge (split_block (BLOCK_FOR_INSN (rtl), rtl));
    1275                 :           0 :               emit_barrier_after_bb (BLOCK_FOR_INSN (rtl));
    1276                 :           0 :               changed_cfg = true;
    1277                 :             :             }
    1278                 :             :         }
    1279                 :             :     }
    1280                 :             : 
    1281                 :     3966710 :   unsigned int index;
    1282                 :     3966710 :   bitmap_iterator bi;
    1283                 :     4014710 :   EXECUTE_IF_SET_IN_BITMAP (m_need_to_purge_dead_edges, 0, index, bi)
    1284                 :       48000 :     if (purge_dead_edges (BASIC_BLOCK_FOR_FN (m_fn, index)))
    1285                 :        2006 :       changed_cfg = true;
    1286                 :             : 
    1287                 :     3966710 :   if (changed_jumps)
    1288                 :             :     // This uses its own timevar internally, so we don't need to push
    1289                 :             :     // one ourselves.
    1290                 :          18 :     rebuild_jump_labels (get_insns ());
    1291                 :             : 
    1292                 :     3966710 :   bitmap_clear (m_need_to_purge_dead_edges);
    1293                 :     3966710 :   bitmap_clear (m_queued_insn_update_uids);
    1294                 :     3966710 :   m_queued_insn_updates.truncate (0);
    1295                 :             : 
    1296                 :     3966710 :   if (changed_cfg)
    1297                 :             :     {
    1298                 :         524 :       free_dominance_info (CDI_DOMINATORS);
    1299                 :         524 :       free_dominance_info (CDI_POST_DOMINATORS);
    1300                 :             :     }
    1301                 :             : 
    1302                 :     3966710 :   return changed_cfg;
    1303                 :             : }
    1304                 :             : 
    1305                 :             : insn_info *
    1306                 :           0 : function_info::create_insn (obstack_watermark &watermark,
    1307                 :             :                             rtx_code insn_code,
    1308                 :             :                             rtx pat)
    1309                 :             : {
    1310                 :           0 :   rtx_insn *rti = nullptr;
    1311                 :             : 
    1312                 :             :   // TODO: extend, move in to emit-rtl.cc.
    1313                 :           0 :   switch (insn_code)
    1314                 :             :     {
    1315                 :           0 :     case INSN:
    1316                 :           0 :       rti = make_insn_raw (pat);
    1317                 :           0 :       break;
    1318                 :           0 :     default:
    1319                 :           0 :       gcc_unreachable ();
    1320                 :             :     }
    1321                 :             : 
    1322                 :           0 :   auto insn = change_alloc<insn_info> (watermark, nullptr, rti, INSN_UID (rti));
    1323                 :           0 :   insn->m_is_temp = true;
    1324                 :           0 :   return insn;
    1325                 :             : }
    1326                 :             : 
    1327                 :             : // Print a description of CHANGE to PP.
    1328                 :             : void
    1329                 :           0 : rtl_ssa::pp_insn_change (pretty_printer *pp, const insn_change &change)
    1330                 :             : {
    1331                 :           0 :   change.print (pp);
    1332                 :           0 : }
    1333                 :             : 
    1334                 :             : // Print a description of CHANGE to FILE.
    1335                 :             : void
    1336                 :           0 : dump (FILE *file, const insn_change &change)
    1337                 :             : {
    1338                 :           0 :   dump_using (file, pp_insn_change, change);
    1339                 :           0 : }
    1340                 :             : 
    1341                 :             : // Debug interface to the dump routine above.
    1342                 :           0 : void debug (const insn_change &x) { dump (stderr, x); }
        

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.