LCOV - code coverage report
Current view: top level - gcc/rtl-ssa - changes.cc (source / functions) Hit Total Coverage
Test: gcc.info Lines: 284 488 58.2 %
Date: 2021-05-08 12:53:43 Functions: 14 23 60.9 %
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-2021 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                 :            : #include "config.h"
      23                 :            : #include "system.h"
      24                 :            : #include "coretypes.h"
      25                 :            : #include "backend.h"
      26                 :            : #include "rtl.h"
      27                 :            : #include "df.h"
      28                 :            : #include "rtl-ssa.h"
      29                 :            : #include "rtl-ssa/internals.h"
      30                 :            : #include "rtl-ssa/internals.inl"
      31                 :            : #include "target.h"
      32                 :            : #include "predict.h"
      33                 :            : #include "memmodel.h" // Needed by emit-rtl.h
      34                 :            : #include "emit-rtl.h"
      35                 :            : #include "cfghooks.h"
      36                 :            : #include "cfgrtl.h"
      37                 :            : 
      38                 :            : using namespace rtl_ssa;
      39                 :            : 
      40                 :            : // See the comment above the declaration.
      41                 :            : void
      42                 :          0 : insn_change::print (pretty_printer *pp) const
      43                 :            : {
      44                 :          0 :   if (m_is_deletion)
      45                 :            :     {
      46                 :          0 :       pp_string (pp, "deletion of ");
      47                 :          0 :       pp_insn (pp, m_insn);
      48                 :            :     }
      49                 :            :   else
      50                 :            :     {
      51                 :          0 :       pp_string (pp, "change to ");
      52                 :          0 :       pp_insn (pp, m_insn);
      53                 :          0 :       pp_newline_and_indent (pp, 2);
      54                 :          0 :       pp_string (pp, "~~~~~~~");
      55                 :            : 
      56                 :          0 :       pp_newline_and_indent (pp, 0);
      57                 :          0 :       pp_string (pp, "new cost: ");
      58                 :          0 :       pp_decimal_int (pp, new_cost);
      59                 :            : 
      60                 :          0 :       pp_newline_and_indent (pp, 0);
      61                 :          0 :       pp_string (pp, "new uses:");
      62                 :          0 :       pp_newline_and_indent (pp, 2);
      63                 :          0 :       pp_accesses (pp, new_uses);
      64                 :          0 :       pp_indentation (pp) -= 2;
      65                 :            : 
      66                 :          0 :       pp_newline_and_indent (pp, 0);
      67                 :          0 :       pp_string (pp, "new defs:");
      68                 :          0 :       pp_newline_and_indent (pp, 2);
      69                 :          0 :       pp_accesses (pp, new_defs);
      70                 :          0 :       pp_indentation (pp) -= 2;
      71                 :            : 
      72                 :          0 :       pp_newline_and_indent (pp, 0);
      73                 :          0 :       pp_string (pp, "first insert-after candidate: ");
      74                 :          0 :       move_range.first->print_identifier_and_location (pp);
      75                 :            : 
      76                 :          0 :       pp_newline_and_indent (pp, 0);
      77                 :          0 :       pp_string (pp, "last insert-after candidate: ");
      78                 :          0 :       move_range.last->print_identifier_and_location (pp);
      79                 :            :     }
      80                 :          0 : }
      81                 :            : 
      82                 :            : // Return a copy of access_array ACCESSES, allocating it on the
      83                 :            : // temporary obstack.
      84                 :            : access_array
      85                 :    4347210 : function_info::temp_access_array (access_array accesses)
      86                 :            : {
      87                 :    4347210 :   if (accesses.empty ())
      88                 :     463788 :     return accesses;
      89                 :            : 
      90                 :    3883422 :   gcc_assert (obstack_object_size (&m_temp_obstack) == 0);
      91                 :    3883422 :   obstack_grow (&m_temp_obstack, accesses.begin (), accesses.size_bytes ());
      92                 :    3883422 :   return { static_cast<access_info **> (obstack_finish (&m_temp_obstack)),
      93                 :    3883422 :            accesses.size () };
      94                 :            : }
      95                 :            : 
      96                 :            : // See the comment above the declaration.
      97                 :            : bool
      98                 :          0 : function_info::verify_insn_changes (array_slice<insn_change *const> changes)
      99                 :            : {
     100                 :          0 :   HARD_REG_SET defined_hard_regs, clobbered_hard_regs;
     101                 :          0 :   CLEAR_HARD_REG_SET (defined_hard_regs);
     102                 :          0 :   CLEAR_HARD_REG_SET (clobbered_hard_regs);
     103                 :            : 
     104                 :          0 :   insn_info *min_insn = m_first_insn;
     105                 :          0 :   for (insn_change *change : changes)
     106                 :          0 :     if (!change->is_deletion ())
     107                 :            :       {
     108                 :            :         // Make sure that the changes can be kept in their current order
     109                 :            :         // while honoring all of the move ranges.
     110                 :          0 :         min_insn = later_insn (min_insn, change->move_range.first);
     111                 :          0 :         while (min_insn != change->insn () && !can_insert_after (min_insn))
     112                 :          0 :           min_insn = min_insn->next_nondebug_insn ();
     113                 :          0 :         if (*min_insn > *change->move_range.last)
     114                 :            :           {
     115                 :          0 :             if (dump_file && (dump_flags & TDF_DETAILS))
     116                 :          0 :               fprintf (dump_file, "no viable insn position assignment\n");
     117                 :          0 :             return false;
     118                 :            :           }
     119                 :            : 
     120                 :            :         // If recog introduced new clobbers of a register as part of
     121                 :            :         // the matching process, make sure that they don't conflict
     122                 :            :         // with any other new definitions or uses of the register.
     123                 :            :         // (We have already checked that they don't conflict with
     124                 :            :         // unchanging definitions and uses.)
     125                 :          0 :         for (use_info *use : change->new_uses)
     126                 :            :           {
     127                 :          0 :             unsigned int regno = use->regno ();
     128                 :          0 :             if (HARD_REGISTER_NUM_P (regno)
     129                 :          0 :                 && TEST_HARD_REG_BIT (clobbered_hard_regs, regno))
     130                 :            :               {
     131                 :          0 :                 if (dump_file && (dump_flags & TDF_DETAILS))
     132                 :          0 :                   fprintf (dump_file, "register %d would be clobbered"
     133                 :            :                            " while it is still live\n", regno);
     134                 :          0 :                 return false;
     135                 :            :               }
     136                 :            :           }
     137                 :          0 :         for (def_info *def : change->new_defs)
     138                 :            :           {
     139                 :          0 :             unsigned int regno = def->regno ();
     140                 :          0 :             if (HARD_REGISTER_NUM_P (regno))
     141                 :            :               {
     142                 :          0 :                 if (def->m_is_temp)
     143                 :            :                   {
     144                 :            :                     // This is a clobber introduced by recog.
     145                 :          0 :                     gcc_checking_assert (is_a<clobber_info *> (def));
     146                 :          0 :                     if (TEST_HARD_REG_BIT (defined_hard_regs, regno))
     147                 :            :                       {
     148                 :          0 :                         if (dump_file && (dump_flags & TDF_DETAILS))
     149                 :          0 :                           fprintf (dump_file, "conflicting definitions of"
     150                 :            :                                    " register %d\n", regno);
     151                 :          0 :                         return false;
     152                 :            :                       }
     153                 :          0 :                     SET_HARD_REG_BIT (clobbered_hard_regs, regno);
     154                 :            :                   }
     155                 :          0 :                 else if (is_a<set_info *> (def))
     156                 :            :                   {
     157                 :            :                     // REGNO now has a defined value.
     158                 :          0 :                     SET_HARD_REG_BIT (defined_hard_regs, regno);
     159                 :          0 :                     CLEAR_HARD_REG_BIT (clobbered_hard_regs, regno);
     160                 :            :                   }
     161                 :            :               }
     162                 :            :           }
     163                 :            :       }
     164                 :            :   return true;
     165                 :            : }
     166                 :            : 
     167                 :            : // See the comment above the declaration.
     168                 :            : bool
     169                 :          0 : rtl_ssa::changes_are_worthwhile (array_slice<insn_change *const> changes,
     170                 :            :                                  bool strict_p)
     171                 :            : {
     172                 :          0 :   unsigned int old_cost = 0;
     173                 :          0 :   unsigned int new_cost = 0;
     174                 :          0 :   for (insn_change *change : changes)
     175                 :            :     {
     176                 :          0 :       old_cost += change->old_cost ();
     177                 :          0 :       if (!change->is_deletion ())
     178                 :            :         {
     179                 :          0 :           basic_block cfg_bb = change->bb ()->cfg_bb ();
     180                 :          0 :           change->new_cost = insn_cost (change->rtl (),
     181                 :          0 :                                         optimize_bb_for_speed_p (cfg_bb));
     182                 :          0 :           new_cost += change->new_cost;
     183                 :            :         }
     184                 :            :     }
     185                 :          0 :   bool ok_p = (strict_p ? new_cost < old_cost : new_cost <= old_cost);
     186                 :          0 :   if (dump_file && (dump_flags & TDF_DETAILS))
     187                 :            :     {
     188                 :          0 :       fprintf (dump_file, "original cost");
     189                 :          0 :       char sep = '=';
     190                 :          0 :       for (const insn_change *change : changes)
     191                 :            :         {
     192                 :          0 :           fprintf (dump_file, " %c %d", sep, change->old_cost ());
     193                 :          0 :           sep = '+';
     194                 :            :         }
     195                 :          0 :       fprintf (dump_file, ", replacement cost");
     196                 :          0 :       sep = '=';
     197                 :          0 :       for (const insn_change *change : changes)
     198                 :          0 :         if (!change->is_deletion ())
     199                 :            :           {
     200                 :          0 :             fprintf (dump_file, " %c %d", sep, change->new_cost);
     201                 :          0 :             sep = '+';
     202                 :            :           }
     203                 :          0 :       fprintf (dump_file, "; %s\n",
     204                 :            :                ok_p ? "keeping replacement" : "rejecting replacement");
     205                 :            :     }
     206                 :          0 :   if (!ok_p)
     207                 :          0 :     return false;
     208                 :            : 
     209                 :            :   return true;
     210                 :            : }
     211                 :            : 
     212                 :            : // Update the REG_NOTES of INSN, whose pattern has just been changed.
     213                 :            : static void
     214                 :    2173605 : update_notes (rtx_insn *insn)
     215                 :            : {
     216                 :    4168863 :   for (rtx *note_ptr = &REG_NOTES (insn); *note_ptr; )
     217                 :            :     {
     218                 :    1995258 :       rtx note = *note_ptr;
     219                 :    1995258 :       bool keep_p = true;
     220                 :    1995258 :       switch (REG_NOTE_KIND (note))
     221                 :            :         {
     222                 :      16150 :         case REG_EQUAL:
     223                 :      16150 :         case REG_EQUIV:
     224                 :      16150 :         case REG_NOALIAS:
     225                 :      16150 :           keep_p = (single_set (insn) != nullptr);
     226                 :      16150 :           break;
     227                 :            : 
     228                 :            :         case REG_UNUSED:
     229                 :            :         case REG_DEAD:
     230                 :            :           // These notes are stale.  We'll recompute REG_UNUSED notes
     231                 :            :           // after the update.
     232                 :            :           keep_p = false;
     233                 :            :           break;
     234                 :            : 
     235                 :            :         default:
     236                 :            :           break;
     237                 :            :         }
     238                 :      16150 :       if (keep_p)
     239                 :      74122 :         note_ptr = &XEXP (*note_ptr, 1);
     240                 :            :       else
     241                 :            :         {
     242                 :    1921136 :           *note_ptr = XEXP (*note_ptr, 1);
     243                 :    1921136 :           free_EXPR_LIST_node (note);
     244                 :            :         }
     245                 :            :     }
     246                 :    2173605 : }
     247                 :            : 
     248                 :            : // Pick a location for CHANGE's instruction and return the instruction
     249                 :            : // after which it should be placed.
     250                 :            : static insn_info *
     251                 :    2173605 : choose_insn_placement (insn_change &change)
     252                 :            : {
     253                 :    2173605 :   gcc_checking_assert (change.move_range);
     254                 :            : 
     255                 :    2173605 :   insn_info *insn = change.insn ();
     256                 :    2173605 :   insn_info *first = change.move_range.first;
     257                 :    2173605 :   insn_info *last = change.move_range.last;
     258                 :            : 
     259                 :            :   // Quick(ish) exit if there is only one possible choice.
     260                 :    2173605 :   if (first == last)
     261                 :            :     return first;
     262                 :          0 :   if (first == insn->prev_nondebug_insn () && last == insn)
     263                 :            :     return insn;
     264                 :            : 
     265                 :            :   // For now just use the closest valid choice to the original instruction.
     266                 :            :   // If the register usage has changed significantly, it might instead be
     267                 :            :   // better to try to take register pressure into account.
     268                 :          0 :   insn_info *closest = change.move_range.clamp_insn_to_range (insn);
     269                 :          0 :   while (closest != insn && !can_insert_after (closest))
     270                 :          0 :     closest = closest->next_nondebug_insn ();
     271                 :            :   return closest;
     272                 :            : }
     273                 :            : 
     274                 :            : // Record any changes related to CHANGE that need to be queued for later.
     275                 :            : void
     276                 :    2173605 : function_info::possibly_queue_changes (insn_change &change)
     277                 :            : {
     278                 :    2173605 :   insn_info *insn = change.insn ();
     279                 :    2173605 :   rtx_insn *rtl = insn->rtl ();
     280                 :            : 
     281                 :            :   // If the instruction could previously throw, we eventually need to call
     282                 :            :   // purge_dead_edges to check whether things have changed.
     283                 :    2173605 :   if (find_reg_note (rtl, REG_EH_REGION, nullptr))
     284                 :      16810 :     bitmap_set_bit (m_need_to_purge_dead_edges, insn->bb ()->index ());
     285                 :            : 
     286                 :    4347210 :   auto needs_pending_update = [&]()
     287                 :            :     {
     288                 :            :       // If an instruction became a no-op without the pass explicitly
     289                 :            :       // deleting it, queue the deletion for later.  Removing the
     290                 :            :       // instruction on the fly would require an update to all instructions
     291                 :            :       // that use the result of the move, which would be a potential source
     292                 :            :       // of quadraticness.  Also, definitions shouldn't disappear under
     293                 :            :       // the pass's feet.
     294                 :    2173605 :       if (INSN_CODE (rtl) == NOOP_MOVE_INSN_CODE)
     295                 :            :         return true;
     296                 :            : 
     297                 :            :       // If any jumps got turned into unconditional jumps or nops, we need
     298                 :            :       // to update the CFG accordingly.
     299                 :    2173583 :       if (JUMP_P (rtl)
     300                 :          0 :           && (returnjump_p (rtl) || any_uncondjump_p (rtl))
     301                 :    2173583 :           && !single_succ_p (insn->bb ()->cfg_bb ()))
     302                 :            :         return true;
     303                 :            : 
     304                 :            :       // If a previously conditional trap now always fires, execution
     305                 :            :       // terminates at that point.
     306                 :    2173583 :       rtx pattern = PATTERN (rtl);
     307                 :    2173583 :       if (GET_CODE (pattern) == TRAP_IF
     308                 :          0 :           && XEXP (pattern, 0) == const1_rtx)
     309                 :          0 :         return true;
     310                 :            : 
     311                 :            :       return false;
     312                 :    2173605 :     };
     313                 :            : 
     314                 :    2173605 :   if (needs_pending_update ()
     315                 :    2173605 :       && bitmap_set_bit (m_queued_insn_update_uids, insn->uid ()))
     316                 :            :     {
     317                 :         22 :       gcc_assert (!change.is_deletion ());
     318                 :         22 :       m_queued_insn_updates.safe_push (insn);
     319                 :            :     }
     320                 :    2173605 : }
     321                 :            : 
     322                 :            : // Remove the instruction described by CHANGE from the underlying RTL
     323                 :            : // and from the insn_info list.
     324                 :            : static void
     325                 :          0 : delete_insn (insn_change &change)
     326                 :            : {
     327                 :          0 :   insn_info *insn = change.insn ();
     328                 :          0 :   rtx_insn *rtl = change.rtl ();
     329                 :          0 :   if (dump_file && (dump_flags & TDF_DETAILS))
     330                 :          0 :     fprintf (dump_file, "deleting insn %d\n", insn->uid ());
     331                 :          0 :   set_insn_deleted (rtl);
     332                 :          0 : }
     333                 :            : 
     334                 :            : // Move the RTL instruction associated with CHANGE so that it comes
     335                 :            : // immediately after AFTER.
     336                 :            : static void
     337                 :          0 : move_insn (insn_change &change, insn_info *after)
     338                 :            : {
     339                 :          0 :   rtx_insn *rtl = change.rtl ();
     340                 :          0 :   rtx_insn *after_rtl = after->rtl ();
     341                 :          0 :   if (dump_file && (dump_flags & TDF_DETAILS))
     342                 :          0 :     fprintf (dump_file, "moving insn %d after insn %d\n",
     343                 :          0 :              INSN_UID (rtl), INSN_UID (after_rtl));
     344                 :            : 
     345                 :            :   // At the moment we don't support moving instructions between EBBs,
     346                 :            :   // but this would be worth adding if it's useful.
     347                 :          0 :   insn_info *insn = change.insn ();
     348                 :          0 :   gcc_assert (after->ebb () == insn->ebb ());
     349                 :          0 :   bb_info *bb = after->bb ();
     350                 :          0 :   basic_block cfg_bb = bb->cfg_bb ();
     351                 :            : 
     352                 :          0 :   if (insn->bb () != bb)
     353                 :            :     // Force DF to mark the old block as dirty.
     354                 :          0 :     df_insn_delete (rtl);
     355                 :          0 :   ::remove_insn (rtl);
     356                 :          0 :   ::add_insn_after (rtl, after_rtl, cfg_bb);
     357                 :          0 : }
     358                 :            : 
     359                 :            : // The instruction associated with CHANGE is being changed in-place.
     360                 :            : // Update the DF information for its new pattern.
     361                 :            : static void
     362                 :    2173605 : update_insn_in_place (insn_change &change)
     363                 :            : {
     364                 :    2173605 :   insn_info *insn = change.insn ();
     365                 :    2173605 :   if (dump_file && (dump_flags & TDF_DETAILS))
     366                 :          0 :     fprintf (dump_file, "updating insn %d in-place\n", insn->uid ());
     367                 :    2173605 :   df_insn_rescan (change.rtl ());
     368                 :    2173605 : }
     369                 :            : 
     370                 :            : // Finalize the new list of definitions and uses in CHANGE, removing
     371                 :            : // any uses and definitions that are no longer needed, and converting
     372                 :            : // pending clobbers into actual definitions.
     373                 :            : void
     374                 :    2173605 : function_info::finalize_new_accesses (insn_change &change)
     375                 :            : {
     376                 :    2173605 :   insn_info *insn = change.insn ();
     377                 :            : 
     378                 :            :   // Get a list of all the things that the instruction now references.
     379                 :    2173605 :   vec_rtx_properties properties;
     380                 :    2173605 :   properties.add_insn (insn->rtl (), true);
     381                 :            : 
     382                 :            :   // Build up the new list of definitions.
     383                 :    7234441 :   for (rtx_obj_reference ref : properties.refs ())
     384                 :    5060836 :     if (ref.is_write ())
     385                 :            :       {
     386                 :    2165595 :         def_info *def = find_access (change.new_defs, ref.regno);
     387                 :    2165595 :         gcc_assert (def);
     388                 :    2165595 :         if (def->m_is_temp)
     389                 :            :           {
     390                 :            :             // At present, the only temporary instruction definitions we
     391                 :            :             // create are clobbers, such as those added during recog.
     392                 :          0 :             gcc_assert (is_a<clobber_info *> (def));
     393                 :          0 :             def = allocate<clobber_info> (change.insn (), ref.regno);
     394                 :            :           }
     395                 :    2165595 :         else if (!def->m_has_been_superceded)
     396                 :            :           {
     397                 :            :             // This is a second or subsequent definition.
     398                 :            :             // See function_info::record_def for a discussion of when
     399                 :            :             // this can happen.
     400                 :        221 :             def->record_reference (ref, false);
     401                 :        221 :             continue;
     402                 :            :           }
     403                 :            :         else
     404                 :            :           {
     405                 :    2165374 :             def->m_has_been_superceded = false;
     406                 :            : 
     407                 :            :             // Clobbers can move around, so remove them from their current
     408                 :            :             // position and them back in their final position.
     409                 :            :             //
     410                 :            :             // At the moment, we don't allow sets to move relative to other
     411                 :            :             // definitions of the same resource, so we can leave those where
     412                 :            :             // they are.  It might be useful to relax this in future.
     413                 :            :             // The main complication is that removing a set would potentially
     414                 :            :             // fuse two adjoining clobber_groups, and adding the set back
     415                 :            :             // would require the group to be split again.
     416                 :    2165374 :             if (is_a<clobber_info *> (def))
     417                 :     291396 :               remove_def (def);
     418                 :    1873978 :             else if (ref.is_reg ())
     419                 :    1407624 :               def->set_mode (ref.mode);
     420                 :    2165374 :             def->set_insn (insn);
     421                 :            :           }
     422                 :    2165374 :         def->record_reference (ref, true);
     423                 :    2165374 :         m_temp_defs.safe_push (def);
     424                 :            :       }
     425                 :            : 
     426                 :            :   // Also keep any explicitly-recorded call clobbers, which are deliberately
     427                 :            :   // excluded from the vec_rtx_properties.  Calls shouldn't move, so we can
     428                 :            :   // keep the definitions in their current position.
     429                 :    4345677 :   for (def_info *def : change.new_defs)
     430                 :    2172072 :     if (def->m_has_been_superceded && def->is_call_clobber ())
     431                 :            :       {
     432                 :        102 :         def->m_has_been_superceded = false;
     433                 :        102 :         def->set_insn (insn);
     434                 :        102 :         m_temp_defs.safe_push (def);
     435                 :            :       }
     436                 :            : 
     437                 :            :   // Install the new list of definitions in CHANGE.
     438                 :    2173605 :   sort_accesses (m_temp_defs);
     439                 :    4347210 :   access_array accesses = temp_access_array (m_temp_defs);
     440                 :    2173605 :   change.new_defs = def_array (accesses);
     441                 :    2173605 :   m_temp_defs.truncate (0);
     442                 :            : 
     443                 :            :   // Create temporary copies of use_infos that are already attached to
     444                 :            :   // other insns, which could happen if the uses come from unchanging
     445                 :            :   // insns or if they have been used by earlier changes.  Doing this
     446                 :            :   // makes it easier to detect multiple reads below.
     447                 :    2173605 :   auto *unshared_uses_base = XOBNEWVEC (&m_temp_obstack, access_info *,
     448                 :            :                                         change.new_uses.size ());
     449                 :    2173605 :   unsigned int i = 0;
     450                 :    7246008 :   for (use_info *use : change.new_uses)
     451                 :            :     {
     452                 :    5072403 :       if (!use->m_has_been_superceded)
     453                 :            :         {
     454                 :    1449884 :           use = allocate_temp<use_info> (insn, use->resource (), use->def ());
     455                 :    1449884 :           use->m_has_been_superceded = true;
     456                 :    1449884 :           use->m_is_temp = true;
     457                 :            :         }
     458                 :    5072403 :       unshared_uses_base[i++] = use;
     459                 :            :     }
     460                 :    2173605 :   auto unshared_uses = use_array (unshared_uses_base, change.new_uses.size ());
     461                 :            : 
     462                 :            :   // Add (possibly temporary) uses to m_temp_uses for each resource.
     463                 :            :   // If there are multiple references to the same resource, aggregate
     464                 :            :   // information in the modes and flags.
     465                 :    7234441 :   for (rtx_obj_reference ref : properties.refs ())
     466                 :    5060836 :     if (ref.is_read ())
     467                 :            :       {
     468                 :    2944622 :         unsigned int regno = ref.regno;
     469                 :    2944622 :         machine_mode mode = ref.is_reg () ? ref.mode : BLKmode;
     470                 :    2944622 :         use_info *use = find_access (unshared_uses, ref.regno);
     471                 :    2944622 :         gcc_assert (use);
     472                 :    2944622 :         if (use->m_has_been_superceded)
     473                 :            :           {
     474                 :            :             // This is the first reference to the resource.
     475                 :    2894323 :             bool is_temp = use->m_is_temp;
     476                 :    2894323 :             *use = use_info (insn, resource_info { mode, regno }, use->def ());
     477                 :    2894323 :             use->m_is_temp = is_temp;
     478                 :    2894323 :             use->record_reference (ref, true);
     479                 :    2894323 :             m_temp_uses.safe_push (use);
     480                 :            :           }
     481                 :            :         else
     482                 :            :           {
     483                 :            :             // Record the mode of the largest use.  The choice is arbitrary if
     484                 :            :             // the instruction (unusually) references the same register in two
     485                 :            :             // different but equal-sized modes.
     486                 :      50299 :             if (HARD_REGISTER_NUM_P (regno)
     487                 :      50299 :                 && partial_subreg_p (use->mode (), mode))
     488                 :          0 :               use->set_mode (mode);
     489                 :      50299 :             use->record_reference (ref, false);
     490                 :            :           }
     491                 :            :       }
     492                 :            : 
     493                 :            :   // Replace any temporary uses and definitions with real ones.
     494                 :   10135856 :   for (unsigned int i = 0; i < m_temp_uses.length (); ++i)
     495                 :            :     {
     496                 :    2894323 :       auto *use = as_a<use_info *> (m_temp_uses[i]);
     497                 :    2894323 :       if (use->m_is_temp)
     498                 :            :         {
     499                 :    1448420 :           m_temp_uses[i] = use = allocate<use_info> (*use);
     500                 :    1448420 :           use->m_is_temp = false;
     501                 :    1448420 :           set_info *def = use->def ();
     502                 :            :           // Handle cases in which the value was previously not used
     503                 :            :           // within the block.
     504                 :    1448420 :           if (def && def->m_is_temp)
     505                 :            :             {
     506                 :        952 :               phi_info *phi = as_a<phi_info *> (def);
     507                 :        952 :               gcc_assert (phi->is_degenerate ());
     508                 :        952 :               phi = create_degenerate_phi (phi->ebb (), phi->input_value (0));
     509                 :    2894323 :               use->set_def (phi);
     510                 :            :             }
     511                 :            :         }
     512                 :            :     }
     513                 :            : 
     514                 :            :   // Install the new list of definitions in CHANGE.
     515                 :    2173605 :   sort_accesses (m_temp_uses);
     516                 :    4347210 :   change.new_uses = use_array (temp_access_array (m_temp_uses));
     517                 :    2173605 :   m_temp_uses.truncate (0);
     518                 :            : 
     519                 :            :   // Record the new instruction-wide properties.
     520                 :    2173605 :   insn->set_properties (properties);
     521                 :    2173605 : }
     522                 :            : 
     523                 :            : // Copy information from CHANGE to its underlying insn_info, given that
     524                 :            : // the insn_info has already been placed appropriately.
     525                 :            : void
     526                 :    2173605 : function_info::apply_changes_to_insn (insn_change &change)
     527                 :            : {
     528                 :    2173605 :   insn_info *insn = change.insn ();
     529                 :    2173605 :   if (change.is_deletion ())
     530                 :            :     {
     531                 :          0 :       insn->set_accesses (nullptr, 0, 0);
     532                 :          0 :       return;
     533                 :            :     }
     534                 :            : 
     535                 :            :   // Copy the cost.
     536                 :    2173605 :   insn->set_cost (change.new_cost);
     537                 :            : 
     538                 :            :   // Add all clobbers.  Sets and call clobbers never move relative to
     539                 :            :   // other definitions, so are OK as-is.
     540                 :    4339081 :   for (def_info *def : change.new_defs)
     541                 :    2165476 :     if (is_a<clobber_info *> (def) && !def->is_call_clobber ())
     542                 :     291396 :       add_def (def);
     543                 :            : 
     544                 :            :   // Add all uses, now that their position is final.
     545                 :    5067928 :   for (use_info *use : change.new_uses)
     546                 :    2894323 :     add_use (use);
     547                 :            : 
     548                 :            :   // Copy the uses and definitions.
     549                 :    2173605 :   unsigned int num_defs = change.new_defs.size ();
     550                 :    2173605 :   unsigned int num_uses = change.new_uses.size ();
     551                 :    2173605 :   if (num_defs + num_uses <= insn->num_defs () + insn->num_uses ())
     552                 :    2168957 :     insn->copy_accesses (change.new_defs, change.new_uses);
     553                 :            :   else
     554                 :            :     {
     555                 :       9296 :       access_array_builder builder (&m_obstack);
     556                 :       4648 :       builder.reserve (num_defs + num_uses);
     557                 :            : 
     558                 :       8327 :       for (def_info *def : change.new_defs)
     559                 :       3679 :         builder.quick_push (def);
     560                 :      16268 :       for (use_info *use : change.new_uses)
     561                 :      11620 :         builder.quick_push (use);
     562                 :            : 
     563                 :       4648 :       insn->set_accesses (builder.finish ().begin (), num_defs, num_uses);
     564                 :            :     }
     565                 :            : 
     566                 :    2173605 :   add_reg_unused_notes (insn);
     567                 :            : }
     568                 :            : 
     569                 :            : // Add a temporary placeholder instruction after AFTER.
     570                 :            : insn_info *
     571                 :          0 : function_info::add_placeholder_after (insn_info *after)
     572                 :            : {
     573                 :          0 :   insn_info *insn = allocate_temp<insn_info> (after->bb (), nullptr, -1);
     574                 :          0 :   add_insn_after (insn, after);
     575                 :          0 :   return insn;
     576                 :            : }
     577                 :            : 
     578                 :            : // See the comment above the declaration.
     579                 :            : void
     580                 :    2173605 : function_info::change_insns (array_slice<insn_change *> changes)
     581                 :            : {
     582                 :    2173605 :   auto watermark = temp_watermark ();
     583                 :            : 
     584                 :    2173605 :   insn_info *min_insn = m_first_insn;
     585                 :    4347210 :   for (insn_change *change : changes)
     586                 :            :     {
     587                 :            :       // Tentatively mark all the old uses and definitions for deletion.
     588                 :    5796124 :       for (use_info *use : change->old_uses ())
     589                 :            :         {
     590                 :    3622519 :           use->m_has_been_superceded = true;
     591                 :    3622519 :           remove_use (use);
     592                 :            :         }
     593                 :    4345677 :       for (def_info *def : change->old_defs ())
     594                 :    2172072 :         def->m_has_been_superceded = true;
     595                 :            : 
     596                 :    2173605 :       if (!change->is_deletion ())
     597                 :            :         {
     598                 :            :           // Remove any notes that are no longer relevant.
     599                 :    2173605 :           update_notes (change->rtl ());
     600                 :            : 
     601                 :            :           // Make sure that the placement of this instruction would still
     602                 :            :           // leave room for previous instructions.
     603                 :    2173605 :           change->move_range = move_later_than (change->move_range, min_insn);
     604                 :    2173605 :           if (!canonicalize_move_range (change->move_range, change->insn ()))
     605                 :            :             // verify_insn_changes is supposed to make sure that this holds.
     606                 :          0 :             gcc_unreachable ();
     607                 :    4347210 :           min_insn = later_insn (min_insn, change->move_range.first);
     608                 :            :         }
     609                 :            :     }
     610                 :            : 
     611                 :            :   // Walk backwards through the changes, allocating specific positions
     612                 :            :   // to each one.  Update the underlying RTL and its associated DF
     613                 :            :   // information.
     614                 :    2173605 :   insn_info *following_insn = nullptr;
     615                 :    4347210 :   auto_vec<insn_info *, 16> placeholders;
     616                 :    2173605 :   placeholders.safe_grow_cleared (changes.size ());
     617                 :    4347210 :   for (unsigned int i = changes.size (); i-- > 0;)
     618                 :            :     {
     619                 :    2173605 :       insn_change &change = *changes[i];
     620                 :    2173605 :       insn_info *placeholder = nullptr;
     621                 :    2173605 :       possibly_queue_changes (change);
     622                 :    2173605 :       if (change.is_deletion ())
     623                 :          0 :         delete_insn (change);
     624                 :            :       else
     625                 :            :         {
     626                 :            :           // Make sure that this instruction comes before later ones.
     627                 :    2173605 :           if (following_insn)
     628                 :            :             {
     629                 :          0 :               change.move_range = move_earlier_than (change.move_range,
     630                 :          0 :                                                      following_insn);
     631                 :          0 :               if (!canonicalize_move_range (change.move_range,
     632                 :            :                                             change.insn ()))
     633                 :            :                 // verify_insn_changes is supposed to make sure that this
     634                 :            :                 // holds.
     635                 :          0 :                 gcc_unreachable ();
     636                 :            :             }
     637                 :            : 
     638                 :            :           // Decide which instruction INSN should go after.
     639                 :    2173605 :           insn_info *after = choose_insn_placement (change);
     640                 :            : 
     641                 :            :           // If INSN is moving, insert a placeholder insn_info at the
     642                 :            :           // new location.  We can't move INSN itself yet because it
     643                 :            :           // might still be referenced by earlier move ranges.
     644                 :    2173605 :           insn_info *insn = change.insn ();
     645                 :    2173605 :           if (after == insn || after == insn->prev_nondebug_insn ())
     646                 :            :             {
     647                 :    2173605 :               update_insn_in_place (change);
     648                 :    2173605 :               following_insn = insn;
     649                 :            :             }
     650                 :            :           else
     651                 :            :             {
     652                 :          0 :               move_insn (change, after);
     653                 :          0 :               placeholder = add_placeholder_after (after);
     654                 :          0 :               following_insn = placeholder;
     655                 :            :             }
     656                 :            : 
     657                 :            :           // Finalize the new list of accesses for the change.  Don't install
     658                 :            :           // them yet, so that we still have access to the old lists below.
     659                 :    2173605 :           finalize_new_accesses (change);
     660                 :            :         }
     661                 :    2173605 :       placeholders[i] = placeholder;
     662                 :            :     }
     663                 :            : 
     664                 :            :   // Remove all definitions that are no longer needed.  After the above,
     665                 :            :   // such definitions should no longer have any registered users.
     666                 :            :   //
     667                 :            :   // In particular, this means that consumers must handle debug
     668                 :            :   // instructions before removing a set.
     669                 :    4347210 :   for (insn_change *change : changes)
     670                 :    4345677 :     for (def_info *def : change->old_defs ())
     671                 :    2172072 :       if (def->m_has_been_superceded)
     672                 :            :         {
     673                 :       6596 :           auto *set = dyn_cast<set_info *> (def);
     674                 :          0 :           gcc_assert (!set || !set->has_any_uses ());
     675                 :       6596 :           remove_def (def);
     676                 :            :         }
     677                 :            : 
     678                 :            :   // Move the insn_infos to their new locations.
     679                 :    4347210 :   for (unsigned int i = 0; i < changes.size (); ++i)
     680                 :            :     {
     681                 :    2173605 :       insn_change &change = *changes[i];
     682                 :    2173605 :       insn_info *insn = change.insn ();
     683                 :    2173605 :       if (change.is_deletion ())
     684                 :          0 :         remove_insn (insn);
     685                 :    2173605 :       else if (insn_info *placeholder = placeholders[i])
     686                 :            :         {
     687                 :            :           // Check if earlier movements turned a move into a no-op.
     688                 :          0 :           if (placeholder->prev_nondebug_insn () == insn
     689                 :          0 :               || placeholder->next_nondebug_insn () == insn)
     690                 :            :             {
     691                 :          0 :               remove_insn (placeholder);
     692                 :          0 :               placeholders[i] = nullptr;
     693                 :            :             }
     694                 :            :           else
     695                 :            :             {
     696                 :            :               // Remove the placeholder first so that we have a wider range of
     697                 :            :               // program points when inserting INSN.
     698                 :          0 :               insn_info *after = placeholder->prev_any_insn ();
     699                 :          0 :               remove_insn (insn);
     700                 :          0 :               remove_insn (placeholder);
     701                 :          0 :               insn->set_bb (after->bb ());
     702                 :          0 :               add_insn_after (insn, after);
     703                 :            :             }
     704                 :            :         }
     705                 :            :     }
     706                 :            : 
     707                 :            :   // Finally apply the changes to the underlying insn_infos.
     708                 :    4347210 :   for (insn_change *change : changes)
     709                 :    2173605 :     apply_changes_to_insn (*change);
     710                 :    2173605 : }
     711                 :            : 
     712                 :            : // See the comment above the declaration.
     713                 :            : void
     714                 :    2173605 : function_info::change_insn (insn_change &change)
     715                 :            : {
     716                 :    2173605 :   insn_change *changes[] = { &change };
     717                 :    2173605 :   return change_insns (changes);
     718                 :            : }
     719                 :            : 
     720                 :            : // Try to adjust CHANGE so that its pattern can include clobber rtx CLOBBER.
     721                 :            : // Return true on success.
     722                 :            : //
     723                 :            : // ADD_REGNO_CLOBBER is a specialization of function_info::add_regno_clobber
     724                 :            : // for a specific caller-provided predicate.
     725                 :            : static bool
     726                 :       1841 : add_clobber (insn_change &change, add_regno_clobber_fn add_regno_clobber,
     727                 :            :              rtx clobber)
     728                 :            : {
     729                 :       1841 :   rtx pat = PATTERN (change.rtl ());
     730                 :       1841 :   gcc_assert (GET_CODE (clobber) == CLOBBER);
     731                 :       1841 :   rtx dest = XEXP (clobber, 0);
     732                 :       1841 :   if (GET_CODE (dest) == SCRATCH)
     733                 :            :     {
     734                 :       1551 :       if (reload_completed)
     735                 :            :         {
     736                 :          0 :           if (dump_file && (dump_flags & TDF_DETAILS))
     737                 :            :             {
     738                 :            :               // ??? Maybe we could try to do some RA here?
     739                 :          0 :               fprintf (dump_file, "instruction requires a scratch"
     740                 :            :                        " after reload:\n");
     741                 :          0 :               print_rtl_single (dump_file, pat);
     742                 :            :             }
     743                 :          0 :           return false;
     744                 :            :         }
     745                 :            :       return true;
     746                 :            :     }
     747                 :            : 
     748                 :        290 :   gcc_assert (REG_P (dest));
     749                 :        580 :   for (unsigned int regno = REGNO (dest); regno != END_REGNO (dest); ++regno)
     750                 :        290 :     if (!add_regno_clobber (change, regno))
     751                 :            :       {
     752                 :          0 :         if (dump_file && (dump_flags & TDF_DETAILS))
     753                 :            :           {
     754                 :          0 :             fprintf (dump_file, "cannot clobber live register %d in:\n",
     755                 :            :                      regno);
     756                 :          0 :             print_rtl_single (dump_file, pat);
     757                 :            :           }
     758                 :          0 :         return false;
     759                 :            :       }
     760                 :            :   return true;
     761                 :            : }
     762                 :            : 
     763                 :            : // Try to recognize the new form of the insn associated with CHANGE,
     764                 :            : // adding any clobbers that are necessary to make the instruction match
     765                 :            : // an .md pattern.  Return true on success.
     766                 :            : //
     767                 :            : // ADD_REGNO_CLOBBER is a specialization of function_info::add_regno_clobber
     768                 :            : // for a specific caller-provided predicate.
     769                 :            : static bool
     770                 :    3084033 : recog_level2 (insn_change &change, add_regno_clobber_fn add_regno_clobber)
     771                 :            : {
     772                 :    6168066 :   insn_change_watermark insn_watermark;
     773                 :    3084033 :   rtx_insn *rtl = change.rtl ();
     774                 :    3084033 :   rtx pat = PATTERN (rtl);
     775                 :    3084033 :   int num_clobbers = 0;
     776                 :    3084033 :   int icode = -1;
     777                 :    3084033 :   bool asm_p = asm_noperands (pat) >= 0;
     778                 :    3084033 :   if (asm_p)
     779                 :            :     {
     780                 :      22312 :       if (!check_asm_operands (pat))
     781                 :            :         {
     782                 :      21722 :           if (dump_file && (dump_flags & TDF_DETAILS))
     783                 :            :             {
     784                 :          0 :               fprintf (dump_file, "failed to match this asm instruction:\n");
     785                 :          0 :               print_rtl_single (dump_file, pat);
     786                 :            :             }
     787                 :      21722 :           return false;
     788                 :            :         }
     789                 :            :     }
     790                 :    3061721 :   else if (noop_move_p (rtl))
     791                 :            :     {
     792                 :        295 :       INSN_CODE (rtl) = NOOP_MOVE_INSN_CODE;
     793                 :        295 :       if (dump_file && (dump_flags & TDF_DETAILS))
     794                 :            :         {
     795                 :          0 :           fprintf (dump_file, "instruction becomes a no-op:\n");
     796                 :          0 :           print_rtl_single (dump_file, pat);
     797                 :            :         }
     798                 :        295 :       insn_watermark.keep ();
     799                 :        295 :       return true;
     800                 :            :     }
     801                 :            :   else
     802                 :            :     {
     803                 :    3061426 :       icode = ::recog (pat, rtl, &num_clobbers);
     804                 :    3061426 :       if (icode < 0)
     805                 :            :         {
     806                 :     942107 :           if (dump_file && (dump_flags & TDF_DETAILS))
     807                 :            :             {
     808                 :          0 :               fprintf (dump_file, "failed to match this instruction:\n");
     809                 :          0 :               print_rtl_single (dump_file, pat);
     810                 :            :             }
     811                 :     942107 :           return false;
     812                 :            :         }
     813                 :            :     }
     814                 :            : 
     815                 :    2119909 :   auto prev_new_defs = change.new_defs;
     816                 :    2119909 :   auto prev_move_range = change.move_range;
     817                 :    2119909 :   if (num_clobbers > 0)
     818                 :            :     {
     819                 :            :       // ??? It would be good to have a way of recycling the rtxes on failure,
     820                 :            :       // but any attempt to cache old PARALLELs would at best be a half
     821                 :            :       // measure, since add_clobbers would still generate fresh clobbers
     822                 :            :       // each time.  It would be better to have a more general recycling
     823                 :            :       // mechanism that all rtx passes can use.
     824                 :       1551 :       rtvec newvec;
     825                 :       1551 :       int oldlen;
     826                 :       1551 :       if (GET_CODE (pat) == PARALLEL)
     827                 :            :         {
     828                 :         10 :           oldlen = XVECLEN (pat, 0);
     829                 :         10 :           newvec = rtvec_alloc (num_clobbers + oldlen);
     830                 :         30 :           for (int i = 0; i < oldlen; ++i)
     831                 :         20 :             RTVEC_ELT (newvec, i) = XVECEXP (pat, 0, i);
     832                 :            :         }
     833                 :            :       else
     834                 :            :         {
     835                 :       1541 :           oldlen = 1;
     836                 :       1541 :           newvec = rtvec_alloc (num_clobbers + oldlen);
     837                 :       1541 :           RTVEC_ELT (newvec, 0) = pat;
     838                 :            :         }
     839                 :       1551 :       rtx newpat = gen_rtx_PARALLEL (VOIDmode, newvec);
     840                 :       1551 :       add_clobbers (newpat, icode);
     841                 :       1551 :       validate_change (rtl, &PATTERN (rtl), newpat, true);
     842                 :       3392 :       for (int i = 0; i < num_clobbers; ++i)
     843                 :       1841 :         if (!add_clobber (change, add_regno_clobber,
     844                 :       1841 :                           XVECEXP (newpat, 0, oldlen + i)))
     845                 :            :           {
     846                 :          0 :             change.new_defs = prev_new_defs;
     847                 :          0 :             change.move_range = prev_move_range;
     848                 :          0 :             return false;
     849                 :            :           }
     850                 :            : 
     851                 :            :       pat = newpat;
     852                 :            :     }
     853                 :            : 
     854                 :    2119909 :   INSN_CODE (rtl) = icode;
     855                 :    2119909 :   if (reload_completed)
     856                 :            :     {
     857                 :          0 :       extract_insn (rtl);
     858                 :          0 :       if (!constrain_operands (1, get_preferred_alternatives (rtl)))
     859                 :            :         {
     860                 :          0 :           if (dump_file && (dump_flags & TDF_DETAILS))
     861                 :            :             {
     862                 :          0 :               if (asm_p)
     863                 :          0 :                 fprintf (dump_file, "asm does not match its constraints:\n");
     864                 :          0 :               else if (const char *name = get_insn_name (icode))
     865                 :          0 :                 fprintf (dump_file, "instruction does not match the"
     866                 :            :                          " constraints for %s:\n", name);
     867                 :            :               else
     868                 :          0 :                 fprintf (dump_file, "instruction does not match its"
     869                 :            :                          " constraints:\n");
     870                 :          0 :               print_rtl_single (dump_file, pat);
     871                 :            :             }
     872                 :          0 :           change.new_defs = prev_new_defs;
     873                 :          0 :           change.move_range = prev_move_range;
     874                 :          0 :           return false;
     875                 :            :         }
     876                 :            :     }
     877                 :            : 
     878                 :    2119909 :   if (dump_file && (dump_flags & TDF_DETAILS))
     879                 :            :     {
     880                 :          0 :       const char *name;
     881                 :          0 :       if (!asm_p && (name = get_insn_name (icode)))
     882                 :          0 :         fprintf (dump_file, "successfully matched this instruction "
     883                 :            :                  "to %s:\n", name);
     884                 :            :       else
     885                 :          0 :         fprintf (dump_file, "successfully matched this instruction:\n");
     886                 :          0 :       print_rtl_single (dump_file, pat);
     887                 :            :     }
     888                 :            : 
     889                 :    2119909 :   insn_watermark.keep ();
     890                 :    2119909 :   return true;
     891                 :            : }
     892                 :            : 
     893                 :            : // Try to recognize the new form of the insn associated with CHANGE,
     894                 :            : // adding and removing clobbers as necessary to make the instruction
     895                 :            : // match an .md pattern.  Return true on success, otherwise leave
     896                 :            : // CHANGE as it was on entry.
     897                 :            : //
     898                 :            : // ADD_REGNO_CLOBBER is a specialization of function_info::add_regno_clobber
     899                 :            : // for a specific caller-provided predicate.
     900                 :            : bool
     901                 :    3154794 : rtl_ssa::recog_internal (insn_change &change,
     902                 :            :                          add_regno_clobber_fn add_regno_clobber)
     903                 :            : {
     904                 :            :   // Accept all changes to debug instructions.
     905                 :    3154794 :   insn_info *insn = change.insn ();
     906                 :    3154794 :   if (insn->is_debug_insn ())
     907                 :            :     return true;
     908                 :            : 
     909                 :    2811910 :   rtx_insn *rtl = insn->rtl ();
     910                 :    2811910 :   rtx pat = PATTERN (rtl);
     911                 :    2811910 :   if (GET_CODE (pat) == PARALLEL && asm_noperands (pat) < 0)
     912                 :            :     {
     913                 :            :       // Try to remove trailing (clobber (scratch)) rtxes, since the new form
     914                 :            :       // of the instruction might not need those scratches.  recog will add
     915                 :            :       // back any that are needed.
     916                 :     571467 :       int len = XVECLEN (pat, 0);
     917                 :     571467 :       int new_len = len;
     918                 :     584400 :       while (new_len > 0
     919                 :     584400 :              && GET_CODE (XVECEXP (pat, 0, new_len - 1)) == CLOBBER
     920                 :    1104708 :              && GET_CODE (XEXP (XVECEXP (pat, 0, new_len - 1), 0)) == SCRATCH)
     921                 :            :         new_len -= 1;
     922                 :            : 
     923                 :     571467 :       int old_num_changes = num_validated_changes ();
     924                 :     571467 :       validate_change_xveclen (rtl, &PATTERN (rtl), new_len, true);
     925                 :     571467 :       if (recog_level2 (change, add_regno_clobber))
     926                 :            :         return true;
     927                 :     321867 :       cancel_changes (old_num_changes);
     928                 :            : 
     929                 :            :       // Try to remove all trailing clobbers.  For example, a pattern that
     930                 :            :       // used to clobber the flags might no longer need to do so.
     931                 :     321867 :       int prev_len = new_len;
     932                 :     668668 :       while (new_len > 0
     933                 :     668668 :              && GET_CODE (XVECEXP (pat, 0, new_len - 1)) == CLOBBER)
     934                 :            :         new_len -= 1;
     935                 :     321867 :       if (new_len != prev_len)
     936                 :            :         {
     937                 :     272123 :           validate_change_xveclen (rtl, &PATTERN (rtl), new_len, true);
     938                 :     272123 :           if (recog_level2 (change, add_regno_clobber))
     939                 :            :             return true;
     940                 :     260723 :           cancel_changes (old_num_changes);
     941                 :            :         }
     942                 :     310467 :       return false;
     943                 :            :     }
     944                 :            : 
     945                 :    2240443 :   return recog_level2 (change, add_regno_clobber);
     946                 :            : }
     947                 :            : 
     948                 :            : // See the comment above the declaration.
     949                 :            : bool
     950                 :    1528456 : function_info::perform_pending_updates ()
     951                 :            : {
     952                 :    1528456 :   bool changed_cfg = false;
     953                 :    1528456 :   bool changed_jumps = false;
     954                 :    1528510 :   for (insn_info *insn : m_queued_insn_updates)
     955                 :            :     {
     956                 :         22 :       rtx_insn *rtl = insn->rtl ();
     957                 :         22 :       if (JUMP_P (rtl))
     958                 :            :         {
     959                 :          0 :           if (INSN_CODE (rtl) == NOOP_MOVE_INSN_CODE)
     960                 :            :             {
     961                 :          0 :               ::delete_insn (rtl);
     962                 :          0 :               bitmap_set_bit (m_need_to_purge_dead_edges,
     963                 :          0 :                               insn->bb ()->index ());
     964                 :            :             }
     965                 :          0 :           else if (returnjump_p (rtl) || any_uncondjump_p (rtl))
     966                 :            :             {
     967                 :          0 :               mark_jump_label (PATTERN (rtl), rtl, 0);
     968                 :          0 :               update_cfg_for_uncondjump (rtl);
     969                 :          0 :               changed_cfg = true;
     970                 :          0 :               changed_jumps = true;
     971                 :            :             }
     972                 :            :         }
     973                 :         22 :       else if (INSN_CODE (rtl) == NOOP_MOVE_INSN_CODE)
     974                 :         22 :         ::delete_insn (rtl);
     975                 :            :       else
     976                 :            :         {
     977                 :          0 :           rtx pattern = PATTERN (rtl);
     978                 :          0 :           if (GET_CODE (pattern) == TRAP_IF
     979                 :          0 :               && XEXP (pattern, 0) == const1_rtx)
     980                 :            :             {
     981                 :          0 :               remove_edge (split_block (BLOCK_FOR_INSN (rtl), rtl));
     982                 :          0 :               emit_barrier_after_bb (BLOCK_FOR_INSN (rtl));
     983                 :          0 :               changed_cfg = true;
     984                 :            :             }
     985                 :            :         }
     986                 :            :     }
     987                 :            : 
     988                 :    1528456 :   unsigned int index;
     989                 :    1528456 :   bitmap_iterator bi;
     990                 :    1544586 :   EXECUTE_IF_SET_IN_BITMAP (m_need_to_purge_dead_edges, 0, index, bi)
     991                 :      16130 :     if (purge_dead_edges (BASIC_BLOCK_FOR_FN (m_fn, index)))
     992                 :         22 :       changed_cfg = true;
     993                 :            : 
     994                 :    1528456 :   if (changed_jumps)
     995                 :            :     // This uses its own timevar internally, so we don't need to push
     996                 :            :     // one ourselves.
     997                 :          0 :     rebuild_jump_labels (get_insns ());
     998                 :            : 
     999                 :    1528456 :   bitmap_clear (m_need_to_purge_dead_edges);
    1000                 :    1528456 :   bitmap_clear (m_queued_insn_update_uids);
    1001                 :    1528456 :   m_queued_insn_updates.truncate (0);
    1002                 :            : 
    1003                 :    1528456 :   if (changed_cfg)
    1004                 :            :     {
    1005                 :          1 :       free_dominance_info (CDI_DOMINATORS);
    1006                 :          1 :       free_dominance_info (CDI_POST_DOMINATORS);
    1007                 :            :     }
    1008                 :            : 
    1009                 :    1528456 :   return changed_cfg;
    1010                 :            : }
    1011                 :            : 
    1012                 :            : // Print a description of CHANGE to PP.
    1013                 :            : void
    1014                 :          0 : rtl_ssa::pp_insn_change (pretty_printer *pp, const insn_change &change)
    1015                 :            : {
    1016                 :          0 :   change.print (pp);
    1017                 :          0 : }
    1018                 :            : 
    1019                 :            : // Print a description of CHANGE to FILE.
    1020                 :            : void
    1021                 :          0 : dump (FILE *file, const insn_change &change)
    1022                 :            : {
    1023                 :          0 :   dump_using (file, pp_insn_change, change);
    1024                 :          0 : }
    1025                 :            : 
    1026                 :            : // Debug interface to the dump routine above.
    1027                 :          0 : void debug (const insn_change &x) { dump (stderr, x); }

Generated by: LCOV version 1.15+git.20200812.d100e6c

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 --enable-host-shared. GCC test suite is run with the built compiler.