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: 2026-02-28 14:20:25 Functions: 80.8 % 26 21
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.