LCOV - code coverage report
Current view: top level - gcc - tree-ssa-threadbackward.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 94.5 % 416 393
Test Date: 2026-10-17 16:30:31 Functions: 88.4 % 43 38
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* SSA Jump Threading
       2              :    Copyright (C) 2005-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
       7              : it under the terms of the GNU General Public License as published by
       8              : the Free Software Foundation; either version 3, or (at your option)
       9              : any later version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful,
      12              : but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : GNU General Public License 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              : #include "config.h"
      21              : #include "system.h"
      22              : #include "coretypes.h"
      23              : #include "backend.h"
      24              : #include "predict.h"
      25              : #include "tree.h"
      26              : #include "gimple.h"
      27              : #include "fold-const.h"
      28              : #include "cfgloop.h"
      29              : #include "gimple-iterator.h"
      30              : #include "tree-cfg.h"
      31              : #include "tree-ssa-threadupdate.h"
      32              : #include "tree-ssa-loop.h"
      33              : #include "cfganal.h"
      34              : #include "tree-pass.h"
      35              : #include "gimple-ssa.h"
      36              : #include "tree-phinodes.h"
      37              : #include "tree-inline.h"
      38              : #include "tree-vectorizer.h"
      39              : #include "value-range.h"
      40              : #include "gimple-range.h"
      41              : #include "tree-ssa-threadedge.h"
      42              : #include "gimple-range-path.h"
      43              : #include "tree-ssa-threadbackward.h"
      44              : #include "ssa.h"
      45              : #include "tree-cfgcleanup.h"
      46              : #include "tree-pretty-print.h"
      47              : #include "cfghooks.h"
      48              : #include "dbgcnt.h"
      49              : 
      50              : // Class to abstract the profitability code for the backwards threader.
      51              : 
      52     44484810 : class back_threader_profitability
      53              : {
      54              : public:
      55              :   back_threader_profitability (bool speed_p, gimple *stmt);
      56              :   void push_bb (const vec<basic_block> &);
      57              :   void pop_bb ();
      58              :   bool possibly_profitable_path_p (const vec<basic_block> &, bool *);
      59              :   bool profitable_path_p (const vec<basic_block> &,
      60              :                           edge taken, bool *irreducible_loop);
      61              : private:
      62              :   int account_bb (basic_block, bool);
      63              :   // Number of insns on the path, less the branch we get to remove.
      64    112955380 :   int net_insns () const { return m_stats.n_insns - m_exit_jump_benefit; }
      65              :   const bool m_speed_p;
      66              :   int m_exit_jump_benefit;
      67              :   bool m_threaded_multiway_branch;
      68              :   // The loop the path starts in, i.e. m_path[0]->loop_father.
      69              :   class loop *m_loop;
      70              :   // The following are accumulated by push_bb as the path grows and
      71              :   // restored by pop_bb as it shrinks.
      72              :   struct path_stats
      73              :   {
      74              :     int n_insns;
      75              :     bool threaded_through_latch;
      76              :     bool multiway_branch_in_path;
      77              :     bool contains_hot_bb;
      78              :     bool unprofitable_bb;
      79              :   };
      80              :   path_stats m_stats;
      81              :   // One entry per push.  These are the stats as they stood before that push,
      82              :   // and the insns of the block.  Basically the entry pushed for m_path[i]
      83              :   // accounts m_path[i - 1].
      84              :   struct unwind_state
      85              :   {
      86              :     path_stats stats;
      87              :     int bb_insns;
      88              :   };
      89              :   auto_vec<unwind_state, 20> m_unwind;
      90              : };
      91              : 
      92     22242405 : back_threader_profitability::back_threader_profitability (bool speed_p,
      93              :                                                           gimple *last)
      94     22242405 :   : m_speed_p (speed_p)
      95              : {
      96     22242405 :   m_threaded_multiway_branch = (gimple_code (last) == GIMPLE_SWITCH
      97     22242405 :                                 || gimple_code (last) == GIMPLE_GOTO);
      98              :   // The forward threader has estimate_threading_killed_stmts, in
      99              :   // particular it estimates further DCE from eliminating the exit
     100              :   // control stmt.
     101     22242405 :   m_exit_jump_benefit = estimate_num_insns (last, &eni_size_weights);
     102     22242405 :   m_loop = NULL;
     103     22242405 :   m_stats = path_stats ();
     104     22242405 : }
     105              : 
     106              : /* Account for BB in the cumulative stats for the path being threaded.
     107              :    CHECK_MULTIWAY is true for all blocks except the block whose branch
     108              :    we are going to eliminate.  Return the number of insns in BB, which
     109              :    PUSH_BB records so the dump can print a per-block count.  */
     110              : 
     111              : int
     112     40956595 : back_threader_profitability::account_bb (basic_block bb, bool check_multiway)
     113              : {
     114     40956595 :   int n_insns = 0;
     115              : 
     116     40956595 :   if (!m_stats.contains_hot_bb && m_speed_p)
     117     13989935 :     m_stats.contains_hot_bb |= optimize_bb_for_speed_p (bb);
     118              : 
     119     40956595 :   for (gimple_stmt_iterator gsi = gsi_after_labels (bb);
     120    187635532 :        !gsi_end_p (gsi);
     121    146678937 :        gsi_next_nondebug (&gsi))
     122              :     {
     123              :       /* Do not allow OpenACC loop markers and __builtin_constant_p on
     124              :          threading paths.  The latter is disallowed, because an
     125              :          expression might be constant on two threading paths, and
     126              :          become non-constant (i.e.: phi) when they merge.  */
     127    146717733 :       gimple *stmt = gsi_stmt (gsi);
     128    146717733 :       if (gimple_call_internal_p (stmt, IFN_UNIQUE)
     129    146717733 :           || gimple_call_builtin_p (stmt, BUILT_IN_CONSTANT_P))
     130              :         {
     131        38796 :           m_stats.unprofitable_bb = true;
     132        38796 :           return n_insns;
     133              :         }
     134              :       /* Do not count empty statements and labels.  */
     135    146678937 :       if (gimple_code (stmt) != GIMPLE_NOP
     136    146678937 :           && !is_gimple_debug (stmt))
     137    126661420 :         n_insns += estimate_num_insns (stmt, &eni_size_weights);
     138              :     }
     139              : 
     140              :   /* We do not look at the block with the threaded branch in this loop.
     141              :      So if any block with a last statement that is a GIMPLE_SWITCH or
     142              :      GIMPLE_GOTO is seen, then we have a multiway branch on our path.  */
     143     40917799 :   if (check_multiway)
     144              :     {
     145     25258817 :       gimple *last = *gsi_last_bb (bb);
     146     25258817 :       if (last
     147     25258817 :           && (gimple_code (last) == GIMPLE_SWITCH
     148     23763909 :               || gimple_code (last) == GIMPLE_GOTO))
     149       285319 :         m_stats.multiway_branch_in_path = true;
     150              :     }
     151              : 
     152              :   return n_insns;
     153              : }
     154              : 
     155              : /* Update the stats after a block has been appended to PATH.  */
     156              : 
     157              : void
     158     63199000 : back_threader_profitability::push_bb (const vec<basic_block> &path)
     159              : {
     160     63199000 :   unwind_state state = { m_stats, /*bb_insns=*/0 };
     161              : 
     162     63199000 :   unsigned n = path.length ();
     163     63199000 :   if (n == 1)
     164     22242405 :     m_loop = path[0]->loop_father;
     165              :   else
     166              :     {
     167              :       /* Appending a block makes the previous entry block part of the copied
     168              :          path, so that's where to account for now.  */
     169     40956595 :       unsigned copied = n - 2;
     170     40956595 :       bool check_multiway = copied > 0;
     171     40956595 :       state.bb_insns = account_bb (path[copied], check_multiway);
     172     40956595 :       m_stats.n_insns += state.bb_insns;
     173              :     }
     174     63199000 :   m_unwind.safe_push (state);
     175              : 
     176              :   /* Note if we thread through the latch, we will want to include the
     177              :      last entry in the array when determining if we thread through the
     178              :      loop latch.  */
     179     63199000 :   if (m_loop->latch == path[n - 1])
     180      3400399 :     m_stats.threaded_through_latch = true;
     181     63199000 : }
     182              : 
     183              : void
     184     63199000 : back_threader_profitability::pop_bb ()
     185              : {
     186     63199000 :   m_stats = m_unwind.pop ().stats;
     187     63199000 : }
     188              : 
     189              : // Used to differentiate unreachable edges, so we may stop the search
     190              : // in a the given direction.
     191              : const edge back_threader::UNREACHABLE_EDGE = (edge) -1;
     192              : 
     193      6523291 : back_threader::back_threader (function *fun, unsigned flags, bool first)
     194      6523291 :   : m_visited_flag (fun), m_first (first)
     195              : {
     196      6523291 :   if (flags & BT_SPEED)
     197      3954356 :     loop_optimizer_init (LOOPS_HAVE_PREHEADERS | LOOPS_HAVE_SIMPLE_LATCHES);
     198              :   else
     199      2568935 :     loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
     200              : 
     201      6523291 :   m_fun = fun;
     202      6523291 :   m_flags = flags;
     203      6523291 :   m_last_stmt = NULL;
     204              : 
     205              :   // The path solver needs EDGE_DFS_BACK in resolving mode.
     206      6523291 :   if (flags & BT_RESOLVE)
     207      1977181 :     mark_dfs_back_edges ();
     208              : 
     209      6523291 :   m_ranger = new gimple_ranger;
     210      6523291 :   m_solver = NULL;
     211      6523291 : }
     212              : 
     213      6523291 : back_threader::~back_threader ()
     214              : {
     215      6523291 :   delete m_ranger;
     216      6523291 :   loop_optimizer_finalize ();
     217      6523291 : }
     218              : 
     219              : // A wrapper for the various debug counters for the threading passes.
     220              : // Returns TRUE if it's OK to register the current threading
     221              : // candidate.
     222              : 
     223              : bool
     224      2546120 : back_threader::debug_counter ()
     225              : {
     226              :   // The ethread pass is mostly harmless ;-).
     227      2546120 :   if ((m_flags & BT_SPEED) == 0)
     228              :     return true;
     229              : 
     230      1727115 :   if (m_flags & BT_RESOLVE)
     231              :     {
     232      1185677 :       if (m_first && !dbg_cnt (back_threadfull1))
     233              :         return false;
     234              : 
     235      1185677 :       if (!m_first && !dbg_cnt (back_threadfull2))
     236              :         return false;
     237              :     }
     238              :   else
     239              :     {
     240       541438 :       if (m_first && !dbg_cnt (back_thread1))
     241              :         return false;
     242              : 
     243       541438 :       if (!m_first && !dbg_cnt (back_thread2))
     244              :         return false;
     245              :     }
     246              :   return true;
     247              : }
     248              : 
     249              : static void
     250          590 : dump_path (FILE *dump_file, const vec<basic_block> &path)
     251              : {
     252         3143 :   for (unsigned i = path.length (); i > 0; --i)
     253              :     {
     254         1963 :       basic_block bb = path[i - 1];
     255         1963 :       fprintf (dump_file, "%d", bb->index);
     256         1963 :       if (i > 1)
     257         1373 :         fprintf (dump_file, "->");
     258              :     }
     259          590 : }
     260              : 
     261              : // Dump details of an attempt to register a path.
     262              : 
     263              : void
     264          590 : back_threader::maybe_register_path_dump (edge taken)
     265              : {
     266          590 :   if (m_path.is_empty ())
     267              :     return;
     268              : 
     269          590 :   fprintf (dump_file, "path: ");
     270          590 :   dump_path (dump_file, m_path);
     271          590 :   fprintf (dump_file, "->");
     272              : 
     273          590 :   if (taken == UNREACHABLE_EDGE)
     274           11 :     fprintf (dump_file, "xx REJECTED (unreachable)\n");
     275          579 :   else if (taken)
     276          113 :     fprintf (dump_file, "%d SUCCESS\n", taken->dest->index);
     277              :   else
     278          466 :     fprintf (dump_file, "xx REJECTED\n");
     279              : }
     280              : 
     281              : // If an outgoing edge can be determined out of the current path,
     282              : // register it for jump threading and return the taken edge.
     283              : //
     284              : // Return NULL if it is unprofitable to thread this path, or the
     285              : // outgoing edge is unknown.  Return UNREACHABLE_EDGE if the path is
     286              : // unreachable.
     287              : 
     288              : edge
     289     28857336 : back_threader::maybe_register_path (back_threader_profitability &profit)
     290              : {
     291     28857336 :   edge taken_edge = find_taken_edge (m_path);
     292              : 
     293     28857336 :   if (taken_edge && taken_edge != UNREACHABLE_EDGE)
     294              :     {
     295      2977367 :       bool irreducible = false;
     296      2977367 :       if (profit.profitable_path_p (m_path, taken_edge, &irreducible)
     297      2546120 :           && debug_counter ()
     298      5523487 :           && m_registry.register_path (m_path, taken_edge))
     299              :         {
     300      1467059 :           if (irreducible)
     301        34863 :             vect_free_loop_info_assumptions (m_path[0]->loop_father);
     302              :         }
     303              :       else
     304              :         taken_edge = NULL;
     305              :     }
     306              : 
     307     28857336 :   if (dump_file && (dump_flags & TDF_DETAILS))
     308          590 :     maybe_register_path_dump (taken_edge);
     309              : 
     310     28857336 :   return taken_edge;
     311              : }
     312              : 
     313              : // Return the known taken edge out of a path.  If the path can be
     314              : // determined to be unreachable, return UNREACHABLE_EDGE.  If no
     315              : // outgoing edge can be calculated, return NULL.
     316              : 
     317              : edge
     318     28857336 : back_threader::find_taken_edge (const vec<basic_block> &path)
     319              : {
     320     28857336 :   gcc_checking_assert (path.length () > 1);
     321     28857336 :   switch (gimple_code (m_last_stmt))
     322              :     {
     323     28761705 :     case GIMPLE_COND:
     324     28761705 :       return find_taken_edge_cond (path, as_a<gcond *> (m_last_stmt));
     325              : 
     326        94182 :     case GIMPLE_SWITCH:
     327        94182 :       return find_taken_edge_switch (path, as_a<gswitch *> (m_last_stmt));
     328              : 
     329         1449 :     case GIMPLE_GOTO:
     330         1449 :       return find_taken_edge_goto (path, as_a<ggoto *> (m_last_stmt));
     331              : 
     332              :     default:
     333              :       return NULL;
     334              :     }
     335              : }
     336              : 
     337              : // Same as find_taken_edge, but for paths ending in a computed goto.
     338              : 
     339              : edge
     340         1449 : back_threader::find_taken_edge_goto (const vec<basic_block> &path,
     341              :                                      ggoto *stmt)
     342              : {
     343         1449 :   tree dest = gimple_goto_dest (stmt);
     344              : 
     345         1449 :   if (TREE_CODE (dest) == SSA_NAME)
     346              :     {
     347         1449 :       prange r;
     348         1449 :       m_solver->reset_path (path, m_imports);
     349         1449 :       if (!m_solver->range_of_expr (r, dest, stmt))
     350              :         return NULL;
     351              : 
     352         1449 :       if (r.undefined_p ())
     353              :         return UNREACHABLE_EDGE;
     354              : 
     355         1417 :       dest = r.pt_invariant ();
     356          186 :       if (!dest)
     357              :         return NULL;
     358         1449 :     }
     359              : 
     360              :   // For a destination that did not resolve to a label,
     361              :   // ::find_taken_edge at most returns the block's single successor,
     362              :   // the only place it could go.
     363          186 :   return ::find_taken_edge (gimple_bb (stmt), dest);
     364              : }
     365              : 
     366              : // Same as find_taken_edge, but for paths ending in a switch.
     367              : 
     368              : edge
     369        94182 : back_threader::find_taken_edge_switch (const vec<basic_block> &path,
     370              :                                        gswitch *sw)
     371              : {
     372        94182 :   tree name = gimple_switch_index (sw);
     373        94182 :   int_range_max r;
     374              : 
     375        94182 :   m_solver->reset_path (path, m_imports);
     376        94182 :   m_solver->range_of_expr (r, name, sw);
     377              : 
     378        94182 :   if (r.undefined_p ())
     379              :     return UNREACHABLE_EDGE;
     380              : 
     381        93726 :   if (r.varying_p ())
     382              :     return NULL;
     383              : 
     384        63399 :   tree label = find_case_label_range (sw, &r);
     385        63399 :   if (!label)
     386              :     return NULL;
     387              : 
     388         6930 :   return find_edge (gimple_bb (sw), label_to_block (cfun, CASE_LABEL (label)));
     389        94182 : }
     390              : 
     391              : // Same as find_taken_edge, but for paths ending in a GIMPLE_COND.
     392              : 
     393              : edge
     394     28761705 : back_threader::find_taken_edge_cond (const vec<basic_block> &path,
     395              :                                      gcond *cond)
     396              : {
     397     28761705 :   int_range_max r;
     398              : 
     399     28761705 :   m_solver->reset_path (path, m_imports);
     400     28761705 :   m_solver->range_of_stmt (r, cond);
     401              : 
     402     28761705 :   if (m_solver->unreachable_path_p ())
     403              :     return UNREACHABLE_EDGE;
     404              : 
     405     28641688 :   int_range<2> true_range = range_true ();
     406     28641688 :   int_range<2> false_range = range_false ();
     407              : 
     408     28641688 :   if (r == true_range || r == false_range)
     409              :     {
     410      2970253 :       edge e_true, e_false;
     411      2970253 :       basic_block bb = gimple_bb (cond);
     412      2970253 :       extract_true_false_edges_from_block (bb, &e_true, &e_false);
     413      2970253 :       return r == true_range ? e_true : e_false;
     414              :     }
     415              :   return NULL;
     416     28761705 : }
     417              : 
     418              : // Find jump threading paths to any of the SSA names in the
     419              : // INTERESTING bitmap, and register any such paths.
     420              : //
     421              : // BB is the current path being processed.
     422              : //
     423              : // OVERALL_PATHS is the search space up to this block
     424              : 
     425              : void
     426     64779631 : back_threader::find_paths_to_names (basic_block bb, bitmap interesting,
     427              :                                     unsigned overall_paths,
     428              :                                     back_threader_profitability &profit)
     429              : {
     430     64779631 :   if (bb->flags & m_visited_flag)
     431      1580631 :     return;
     432              : 
     433     63199000 :   bb->flags |= m_visited_flag;
     434              : 
     435     63199000 :   m_path.safe_push (bb);
     436     63199000 :   profit.push_bb (m_path);
     437              : 
     438              :   // Try to resolve the path without looking back.  Avoid resolving paths
     439              :   // we know are large but are not (yet) recognized as Finite State Machine.
     440              :   // ???  Ideally we'd explore the cheapest path to the loop backedge here,
     441              :   // avoiding the exponential greedy search and only start that from there.
     442              :   // Precomputing a path-size-to-immediate-dominator-of-successor for each
     443              :   // edge might help here.  Alternatively copying divergent control flow
     444              :   // on the way to the backedge could be worthwhile.
     445     63199000 :   bool large_non_fsm;
     446     63199000 :   edge e;
     447     63199000 :   if (m_path.length () > 1
     448     63199000 :       && (!profit.possibly_profitable_path_p (m_path, &large_non_fsm)
     449     28912962 :           || (!large_non_fsm
     450     28857336 :               && maybe_register_path (profit))))
     451              :     ;
     452              : 
     453              :   // The backwards thread copier cannot copy blocks that do not belong
     454              :   // to the same loop, so when the new source of the path entry no
     455              :   // longer belongs to it we don't need to search further.
     456     49567803 :   else if (m_path[0]->loop_father != bb->loop_father
     457     55144596 :            && (!(e = loop_exits_from_bb_p (m_path[0]->loop_father,
     458      5576793 :                                            m_path[0]))
     459      3891874 :                || e->dest->loop_father != bb->loop_father))
     460              :     ;
     461              : 
     462              :   // Continue looking for ways to extend the path but limit the
     463              :   // search space along a branch
     464     47129549 :   else if ((overall_paths = overall_paths * EDGE_COUNT (bb->preds))
     465     47129549 :            <= (unsigned)param_max_jump_thread_paths)
     466              :     {
     467              :       // For further greedy searching we want to remove interesting
     468              :       // names defined in BB but add ones on the PHI edges for the
     469              :       // respective edges and adding imports from those stmts.
     470              :       // We do this by starting with all names
     471              :       // not defined in BB as interesting, collecting a list of
     472              :       // interesting PHIs in BB on the fly.  Then we iterate over
     473              :       // predecessor edges, adding interesting PHI edge defs to
     474              :       // the set of interesting names to consider when processing it.
     475     47006084 :       auto_bitmap new_interesting;
     476     47006084 :       auto_vec<int, 16> new_imports;
     477     47006084 :       auto_vec<gphi *, 4> interesting_phis;
     478     47006084 :       bitmap_iterator bi;
     479     47006084 :       unsigned i;
     480     47006084 :       auto_vec<tree, 16> worklist;
     481              :       // Add NAME to the list of imports.
     482     67785170 :       auto add_import = [&] (tree name)
     483              :         {
     484     20779086 :           if (bitmap_set_bit (m_imports, SSA_NAME_VERSION (name)))
     485              :             {
     486     18235224 :               new_imports.safe_push (SSA_NAME_VERSION (name));
     487     18235224 :               worklist.safe_push (name);
     488              :             }
     489     67785170 :         };
     490    105318101 :       EXECUTE_IF_SET_IN_BITMAP (interesting, 0, i, bi)
     491              :         {
     492     58312017 :           tree name = ssa_name (i);
     493     58312017 :           gimple *def_stmt = SSA_NAME_DEF_STMT (name);
     494              :           /* Imports remain interesting.  */
     495     58312017 :           if (gimple_bb (def_stmt) != bb)
     496              :             {
     497     29038440 :               bitmap_set_bit (new_interesting, i);
     498     29038440 :               continue;
     499              :             }
     500     29273577 :           worklist.quick_push (name);
     501    135329532 :           while (!worklist.is_empty ())
     502              :             {
     503     47508801 :               tree name = worklist.pop ();
     504     47508801 :               gimple *def_stmt = SSA_NAME_DEF_STMT (name);
     505              :               /* Newly discovered imports are interesting.  */
     506     47508801 :               if (gimple_bb (def_stmt) != bb)
     507              :                 {
     508      5827561 :                   bitmap_set_bit (new_interesting, SSA_NAME_VERSION (name));
     509      5827561 :                   continue;
     510              :                 }
     511              :               /* Local PHIs participate in renaming below.  */
     512     77771900 :               if (gphi *phi = dyn_cast<gphi *> (def_stmt))
     513      5590580 :                 interesting_phis.safe_push (phi);
     514              :               /* For other local defs process their uses, amending
     515              :                  imports on the way.  */
     516              :               else
     517              :                 {
     518     36090660 :                   tree ssa[3];
     519     36090660 :                   unsigned lim = gimple_range_ssa_names (ssa, 3, def_stmt);
     520     92960406 :                   for (unsigned j = 0; j < lim; ++j)
     521     20779086 :                     if (ssa[j])
     522     20779086 :                       add_import (ssa[j]);
     523              :                 }
     524              :             }
     525              :         }
     526     47006084 :       if (!bitmap_empty_p (new_interesting)
     527     47006084 :           || !interesting_phis.is_empty ())
     528              :         {
     529     61207434 :           auto_vec<int, 4> unwind (interesting_phis.length ());
     530     61207434 :           auto_vec<int, 4> imports_unwind (interesting_phis.length ());
     531     30603717 :           edge_iterator iter;
     532     30603717 :           edge e;
     533     74393457 :           FOR_EACH_EDGE (e, iter, bb->preds)
     534              :             {
     535     43789740 :               if (e->flags & EDGE_ABNORMAL
     536     43787288 :                   || e->src->index == ENTRY_BLOCK)
     537      1252514 :                 continue;
     538    140034943 :               for (gphi *phi : interesting_phis)
     539              :                 {
     540     12423265 :                   tree def = PHI_ARG_DEF_FROM_EDGE (phi, e);
     541     12423265 :                   if (TREE_CODE (def) == SSA_NAME)
     542              :                     {
     543      8758241 :                       int ver = SSA_NAME_VERSION (def);
     544      8758241 :                       if (bitmap_set_bit (new_interesting, ver))
     545              :                         {
     546      8723108 :                           if (bitmap_set_bit (m_imports, ver))
     547      7167001 :                             imports_unwind.quick_push (ver);
     548      8723108 :                           unwind.quick_push (ver);
     549              :                         }
     550              :                     }
     551              :                 }
     552     42537226 :               find_paths_to_names (e->src, new_interesting, overall_paths,
     553              :                                    profit);
     554              :               // Restore new_interesting.
     555    136334786 :               for (int def : unwind)
     556      8723108 :                 bitmap_clear_bit (new_interesting, def);
     557     42537226 :               unwind.truncate (0);
     558              :               // Restore and m_imports.
     559    134778679 :               for (int def : imports_unwind)
     560      7167001 :                 bitmap_clear_bit (m_imports, def);
     561     42537226 :               imports_unwind.truncate (0);
     562              :             }
     563     30603717 :         }
     564              :       /* m_imports tracks all interesting names on the path, so when
     565              :          backtracking we have to restore it.  */
     566    159253476 :       for (int j : new_imports)
     567     18235224 :         bitmap_clear_bit (m_imports, j);
     568     47006084 :     }
     569       123465 :   else if (dump_file && (dump_flags & TDF_DETAILS))
     570            9 :     fprintf (dump_file, "  FAIL: Search space limit %d reached.\n",
     571              :              param_max_jump_thread_paths);
     572              : 
     573              :   // Reset things to their original state.
     574     63199000 :   profit.pop_bb ();
     575     63199000 :   m_path.pop ();
     576     63199000 :   bb->flags &= ~m_visited_flag;
     577              : }
     578              : 
     579              : // Search backwards from BB looking for paths where the final
     580              : // conditional maybe threaded to a successor block.  Record such paths
     581              : // for jump threading.
     582              : 
     583              : void
     584     26670035 : back_threader::maybe_thread_block (basic_block bb)
     585              : {
     586     26670035 :   if (EDGE_COUNT (bb->succs) <= 1)
     587      4427630 :     return;
     588              : 
     589     26670035 :   gimple *stmt = *gsi_last_bb (bb);
     590     26670035 :   if (!stmt)
     591              :     return;
     592              : 
     593     26670035 :   enum gimple_code code = gimple_code (stmt);
     594     26670035 :   if (code != GIMPLE_SWITCH
     595     26670035 :       && code != GIMPLE_COND
     596      4380451 :       && code != GIMPLE_GOTO)
     597              :     return;
     598              : 
     599     22290558 :   m_last_stmt = stmt;
     600     22290558 :   m_path.truncate (0);
     601              : 
     602              :   // We compute imports of the path during discovery starting
     603              :   // just with names used in the conditional.
     604     22290558 :   bitmap_clear (m_imports);
     605     22290558 :   ssa_op_iter iter;
     606     22290558 :   tree name;
     607     49453186 :   FOR_EACH_SSA_TREE_OPERAND (name, stmt, iter, SSA_OP_USE)
     608              :     {
     609     27210781 :       if (!gimple_range_ssa_p (name))
     610              :         return;
     611     27162628 :       bitmap_set_bit (m_imports, SSA_NAME_VERSION (name));
     612              :     }
     613              : 
     614              :   // Interesting is the set of imports we still not have see
     615              :   // the definition of.  So while imports only grow, the
     616              :   // set of interesting defs dwindles and once empty we can
     617              :   // stop searching.
     618     22242405 :   auto_bitmap interesting;
     619     22242405 :   bitmap_copy (interesting, m_imports);
     620     22242405 :   back_threader_profitability profit (m_flags & BT_SPEED, stmt);
     621     22242405 :   find_paths_to_names (bb, interesting, 1, profit);
     622     22242405 : }
     623              : 
     624              : DEBUG_FUNCTION void
     625            0 : debug (const vec <basic_block> &path)
     626              : {
     627            0 :   dump_path (stderr, path);
     628            0 :   fputc ('\n', stderr);
     629            0 : }
     630              : 
     631              : void
     632            0 : back_threader::dump (FILE *out)
     633              : {
     634            0 :   fprintf (out, "\nCandidates for pre-computation:\n");
     635            0 :   fprintf (out, "===================================\n");
     636              : 
     637            0 :   bitmap_iterator bi;
     638            0 :   unsigned i;
     639              : 
     640            0 :   EXECUTE_IF_SET_IN_BITMAP (m_imports, 0, i, bi)
     641              :     {
     642            0 :       tree name = ssa_name (i);
     643            0 :       print_generic_expr (out, name, TDF_NONE);
     644            0 :       fprintf (out, "\n");
     645              :     }
     646            0 : }
     647              : 
     648              : void
     649            0 : back_threader::debug ()
     650              : {
     651            0 :   dump (stderr);
     652            0 : }
     653              : 
     654              : /* Examine jump threading path PATH and return TRUE if it is possibly
     655              :    profitable to thread it, otherwise return FALSE.  If this function
     656              :    returns TRUE profitable_path_p might not be satisfied but when
     657              :    the path is extended it might be.  In particular indicate in
     658              :    *LARGE_NON_FSM whether the thread is too large for a non-FSM thread
     659              :    but would be OK if we extend the path to cover the loop backedge.
     660              : 
     661              :    ?? It seems we should be able to loosen some of the restrictions in
     662              :    this function after loop optimizations have run.  */
     663              : 
     664              : bool
     665     40956595 : back_threader_profitability::possibly_profitable_path_p
     666              :                                   (const vec<basic_block> &m_path,
     667              :                                    bool *large_non_fsm)
     668              : {
     669     40956595 :   gcc_checking_assert (!m_path.is_empty ());
     670              : 
     671              :   /* We can an empty path here (excluding the DEF block) when the
     672              :      statement that makes a conditional generate a compile-time
     673              :      constant result is in the same block as the conditional.
     674              : 
     675              :      That's not really a jump threading opportunity, but instead is
     676              :      simple cprop & simplification.  We could handle it here if we
     677              :      wanted by wiring up all the incoming edges.  If we run this
     678              :      early in IPA, that might be worth doing.   For now we just
     679              :      reject that case.  */
     680     40956595 :   if (m_path.length () <= 1)
     681              :       return false;
     682              : 
     683     40956595 :   loop_p loop = m_loop;
     684              : 
     685     40956595 :   if (m_stats.unprofitable_bb)
     686              :     return false;
     687              : 
     688     40917799 :   if (dump_file && (dump_flags & TDF_DETAILS))
     689              :     {
     690          681 :       fprintf (dump_file, "Checking profitability of path (backwards): ");
     691         3751 :       for (unsigned j = 0; j < m_path.length (); j++)
     692              :         {
     693         2389 :           fprintf (dump_file, " bb:%i", m_path[j]->index);
     694              :           /* The last block on the path is not copied, so it has no
     695              :              count of its own.  */
     696         2389 :           if (j + 1 < m_path.length ())
     697         1708 :             fprintf (dump_file, " (%i insns)", m_unwind[j + 1].bb_insns);
     698         2389 :           if (loop->latch == m_path[j])
     699          104 :             fprintf (dump_file, " (latch)");
     700              :         }
     701          681 :       fprintf (dump_file, "\n  Control statement insns: %i\n"
     702              :                "  Overall: %i insns\n",
     703              :                m_exit_jump_benefit, net_insns ());
     704              :     }
     705              : 
     706              :   /* Threading is profitable if the path duplicated is hot but also
     707              :      in a case we separate cold path from hot path and permit optimization
     708              :      of the hot path later.  Be on the aggressive side here. In some testcases,
     709              :      as in PR 78407 this leads to noticeable improvements.  */
     710     40917799 :   if (m_speed_p)
     711              :     {
     712     36726715 :       if (net_insns () >= param_max_fsm_thread_path_insns)
     713              :         {
     714         7533 :           if (dump_file && (dump_flags & TDF_DETAILS))
     715            0 :             fprintf (dump_file, "  FAIL: Jump-thread path not considered: "
     716              :                      "the number of instructions on the path "
     717              :                      "exceeds PARAM_MAX_FSM_THREAD_PATH_INSNS.\n");
     718              :           return false;
     719              :         }
     720     73438364 :       edge entry = find_edge (m_path[m_path.length () - 1],
     721     36719182 :                               m_path[m_path.length () - 2]);
     722     36719182 :       if (probably_never_executed_edge_p (cfun, entry))
     723              :         {
     724       144932 :           if (dump_file && (dump_flags & TDF_DETAILS))
     725            1 :             fprintf (dump_file, "  FAIL: Jump-thread path not considered: "
     726              :                      "path entry is probably never executed.\n");
     727              :           return false;
     728              :         }
     729              :     }
     730      4191084 :   else if (net_insns () > 1)
     731              :     {
     732      1424163 :       if (dump_file && (dump_flags & TDF_DETAILS))
     733           11 :         fprintf (dump_file, "  FAIL: Jump-thread path not considered: "
     734              :                  "duplication of %i insns is needed and optimizing for size.\n",
     735              :                  net_insns ());
     736              :       return false;
     737              :     }
     738              : 
     739              :   /* The generic copier used by the backthreader does not re-use an
     740              :      existing threading path to reduce code duplication.  So for that
     741              :      case, drastically reduce the number of statements we are allowed
     742              :      to copy.  We don't know yet whether we will thread through the latch
     743              :      so we have to be permissive and continue threading, but indicate
     744              :      to the caller the thread, if final, wouldn't be profitable.  */
     745     39341171 :   if ((!m_threaded_multiway_branch
     746       164602 :        || !loop->latch
     747       163660 :        || loop->latch->index == EXIT_BLOCK)
     748     39341171 :       && (net_insns () * param_fsm_scale_path_stmts
     749     39239026 :           >= param_max_jump_thread_duplication_stmts))
     750              :     {
     751     10428209 :       if (dump_file && (dump_flags & TDF_DETAILS))
     752           68 :         fprintf (dump_file,
     753              :                  "  FAIL: Did not thread around loop and would copy too "
     754              :                  "many statements.\n");
     755              :       return false;
     756              :     }
     757      4490611 :   *large_non_fsm = (!(m_stats.threaded_through_latch
     758              :                       && m_threaded_multiway_branch)
     759     28912962 :                     && (net_insns () * param_fsm_scale_path_stmts
     760     28889182 :                         >= param_max_jump_thread_duplication_stmts));
     761              : 
     762     28912962 :   if (dump_file && (dump_flags & TDF_DETAILS))
     763          601 :     fputc ('\n', dump_file);
     764              :   return true;
     765              : }
     766              : 
     767              : /* Examine jump threading path PATH and return TRUE if it is profitable to
     768              :    thread it, otherwise return FALSE.
     769              : 
     770              :    The taken edge out of the path is TAKEN_EDGE.
     771              : 
     772              :    CREATES_IRREDUCIBLE_LOOP is set to TRUE if threading this path
     773              :    would create an irreducible loop.
     774              : 
     775              :    ?? It seems we should be able to loosen some of the restrictions in
     776              :    this function after loop optimizations have run.  */
     777              : 
     778              : bool
     779      2977367 : back_threader_profitability::profitable_path_p (const vec<basic_block> &m_path,
     780              :                                                 edge taken_edge,
     781              :                                                 bool *creates_irreducible_loop)
     782              : {
     783              :   // We can assume that possibly_profitable_path_p holds here
     784              : 
     785      2977367 :   loop_p loop = m_path[0]->loop_father;
     786              : 
     787      2977367 :   if (dump_file && (dump_flags & TDF_DETAILS))
     788          156 :     fprintf (dump_file, "Checking profitability of path (backwards): ");
     789              : 
     790              :   /* If this path threaded through the loop latch back into the
     791              :      same loop and the destination does not dominate the loop
     792              :      latch, then this thread would create an irreducible loop.  */
     793      2977367 :   *creates_irreducible_loop = false;
     794      2977367 :   if (m_stats.threaded_through_latch
     795       132686 :       && loop == taken_edge->dest->loop_father
     796      3099363 :       && (determine_bb_domination_status (loop, taken_edge->dest)
     797              :           == DOMST_NONDOMINATING))
     798        86645 :     *creates_irreducible_loop = true;
     799              : 
     800              :   /* Threading is profitable if the path duplicated is hot but also
     801              :      in a case we separate cold path from hot path and permit optimization
     802              :      of the hot path later.  Be on the aggressive side here. In some testcases,
     803              :      as in PR 78407 this leads to noticeable improvements.  */
     804      2977367 :   if (m_speed_p
     805      2977367 :       && (optimize_edge_for_speed_p (taken_edge) || m_stats.contains_hot_bb))
     806              :     {
     807      1799841 :       if (probably_never_executed_edge_p (cfun, taken_edge))
     808              :         {
     809        27526 :           if (dump_file && (dump_flags & TDF_DETAILS))
     810            3 :             fprintf (dump_file, "  FAIL: Jump-thread path not considered: "
     811              :                      "path leads to probably never executed edge.\n");
     812              :           return false;
     813              :         }
     814              :     }
     815      1177526 :   else if (net_insns () > 1)
     816              :     {
     817       210376 :       if (dump_file && (dump_flags & TDF_DETAILS))
     818            0 :         fprintf (dump_file, "  FAIL: Jump-thread path not considered: "
     819              :                  "duplication of %i insns is needed and optimizing for size.\n",
     820              :                  net_insns ());
     821              :       return false;
     822              :     }
     823              : 
     824              :   /* We avoid creating irreducible inner loops unless we thread through
     825              :      a multiway branch, in which case we have deemed it worth losing
     826              :      other loop optimizations later.
     827              : 
     828              :      We also consider it worth creating an irreducible inner loop after
     829              :      loop optimizations if the number of copied statement is low.  */
     830      2739465 :   if (!m_threaded_multiway_branch
     831      2732685 :       && *creates_irreducible_loop
     832      2820047 :       && (!(cfun->curr_properties & PROP_loop_opts_done)
     833        37469 :           || (net_insns () * param_fsm_scale_path_stmts
     834        37469 :               >= param_max_jump_thread_duplication_stmts)))
     835              :     {
     836        43113 :       if (dump_file && (dump_flags & TDF_DETAILS))
     837            1 :         fprintf (dump_file,
     838              :                  "  FAIL: Would create irreducible loop early without "
     839              :                  "threading multiway branch.\n");
     840              :       /* We compute creates_irreducible_loop only late.  */
     841              :       return false;
     842              :     }
     843              : 
     844              :   /* The generic copier used by the backthreader does not re-use an
     845              :      existing threading path to reduce code duplication.  So for that
     846              :      case, drastically reduce the number of statements we are allowed
     847              :      to copy.  */
     848        85121 :   if (!(m_stats.threaded_through_latch && m_threaded_multiway_branch)
     849      2696352 :       && (net_insns () * param_fsm_scale_path_stmts
     850      2693697 :           >= param_max_jump_thread_duplication_stmts))
     851              :     {
     852            0 :       if (dump_file && (dump_flags & TDF_DETAILS))
     853            0 :         fprintf (dump_file,
     854              :                  "  FAIL: Did not thread around loop and would copy too "
     855              :                  "many statements.\n");
     856              :       return false;
     857              :     }
     858              : 
     859              :   /* When there is a multi-way branch on the path, then threading can
     860              :      explode the CFG due to duplicating the edges for that multi-way
     861              :      branch.  So like above, only allow a multi-way branch on the path
     862              :      if we actually thread a multi-way branch.  */
     863      2696352 :   if (!m_threaded_multiway_branch && m_stats.multiway_branch_in_path)
     864              :     {
     865          188 :       if (dump_file && (dump_flags & TDF_DETAILS))
     866            6 :         fprintf (dump_file,
     867              :                  "  FAIL: Thread through multiway branch without threading "
     868              :                  "a multiway branch.\n");
     869              :       return false;
     870              :     }
     871              : 
     872              :   /* Threading through an empty latch would cause code to be added to
     873              :      the latch.  This could alter the loop form sufficiently to cause
     874              :      loop optimizations to fail.  Disable these threads until after
     875              :      loop optimizations have run.  */
     876      2611048 :   if ((m_stats.threaded_through_latch || taken_edge->dest == loop->latch)
     877       697536 :       && !(cfun->curr_properties & PROP_loop_opts_done)
     878      3212308 :       && empty_block_p (loop->latch))
     879              :     {
     880       150044 :       if (dump_file && (dump_flags & TDF_DETAILS))
     881           15 :         fprintf (dump_file,
     882              :                  "  FAIL: Thread through latch before loop opts would create "
     883              :                  "non-empty latch\n");
     884              :       return false;
     885              :     }
     886      2546120 :   if (dump_file && (dump_flags & TDF_DETAILS))
     887          131 :     fputc ('\n', dump_file);
     888              :   return true;
     889              : }
     890              : 
     891              : 
     892              : /* The current path PATH is a vector of blocks forming a jump threading
     893              :    path in reverse order.  TAKEN_EDGE is the edge taken from path[0].
     894              : 
     895              :    Convert the current path into the form used by register_jump_thread and
     896              :    register it.
     897              : 
     898              :    Return TRUE if successful or FALSE otherwise.  */
     899              : 
     900              : bool
     901      2546120 : back_threader_registry::register_path (const vec<basic_block> &m_path,
     902              :                                        edge taken_edge)
     903              : {
     904      2546120 :   vec<jump_thread_edge *> *jump_thread_path = allocate_thread_path ();
     905              : 
     906              :   // The generic copier ignores the edge type.  We can build the
     907              :   // thread edges with any type.
     908      8665688 :   for (unsigned int j = 0; j + 1 < m_path.length (); j++)
     909              :     {
     910      3573448 :       basic_block bb1 = m_path[m_path.length () - j - 1];
     911      3573448 :       basic_block bb2 = m_path[m_path.length () - j - 2];
     912              : 
     913      3573448 :       edge e = find_edge (bb1, bb2);
     914      3573448 :       gcc_assert (e);
     915      3573448 :       push_edge (jump_thread_path, e, EDGE_COPY_SRC_BLOCK);
     916              :     }
     917              : 
     918      2546120 :   push_edge (jump_thread_path, taken_edge, EDGE_NO_COPY_SRC_BLOCK);
     919      2546120 :   return register_jump_thread (jump_thread_path);
     920              : }
     921              : 
     922              : // Return a new path solver for the search.
     923              : 
     924              : path_range_query *
     925      6523291 : back_threader::make_solver (gimple_ranger &ranger)
     926              : {
     927      6523291 :   return new path_range_query (ranger, m_flags & BT_RESOLVE);
     928              : }
     929              : 
     930              : // Find the paths to thread in the current function.
     931              : 
     932              : void
     933      6523291 : back_threader::search ()
     934              : {
     935      6523291 :   m_solver = make_solver (*m_ranger);
     936              : 
     937      6523291 :   basic_block bb;
     938     63047021 :   FOR_EACH_BB_FN (bb, m_fun)
     939     83193765 :     if (EDGE_COUNT (bb->succs) > 1)
     940     26670035 :       maybe_thread_block (bb);
     941              : 
     942              :   // The solver lives as long as the search: the IL changes after it.
     943      6523291 :   delete m_solver;
     944      6523291 :   m_solver = NULL;
     945      6523291 : }
     946              : 
     947              : // Thread the paths found.  Return TODO_flags.
     948              : 
     949              : unsigned int
     950      6523291 : back_threader::apply ()
     951              : {
     952      6523291 :   bool changed = m_registry.thread_through_all_blocks (true);
     953              : 
     954      6523291 :   if (m_flags & BT_SPEED)
     955      3954356 :     return changed ? TODO_cleanup_cfg : 0;
     956              : 
     957              :   return false;
     958              : }
     959              : 
     960              : // Thread all suitable paths in the current function.
     961              : //
     962              : // Return TODO_flags.
     963              : 
     964              : unsigned int
     965      6523291 : back_threader::thread_blocks ()
     966              : {
     967      6523291 :   search ();
     968      6523291 :   return apply ();
     969              : }
     970              : 
     971              : namespace {
     972              : 
     973              : const pass_data pass_data_early_thread_jumps =
     974              : {
     975              :   GIMPLE_PASS,
     976              :   "ethread",
     977              :   OPTGROUP_NONE,
     978              :   TV_TREE_SSA_THREAD_JUMPS,
     979              :   ( PROP_cfg | PROP_ssa ),
     980              :   0,
     981              :   0,
     982              :   0,
     983              :   ( TODO_cleanup_cfg | TODO_update_ssa ),
     984              : };
     985              : 
     986              : const pass_data pass_data_thread_jumps =
     987              : {
     988              :   GIMPLE_PASS,
     989              :   "thread",
     990              :   OPTGROUP_NONE,
     991              :   TV_TREE_SSA_THREAD_JUMPS,
     992              :   ( PROP_cfg | PROP_ssa ),
     993              :   0,
     994              :   0,
     995              :   0,
     996              :   TODO_update_ssa,
     997              : };
     998              : 
     999              : const pass_data pass_data_thread_jumps_full =
    1000              : {
    1001              :   GIMPLE_PASS,
    1002              :   "threadfull",
    1003              :   OPTGROUP_NONE,
    1004              :   TV_TREE_SSA_THREAD_JUMPS,
    1005              :   ( PROP_cfg | PROP_ssa ),
    1006              :   0,
    1007              :   0,
    1008              :   0,
    1009              :   TODO_update_ssa,
    1010              : };
    1011              : 
    1012              : // Early jump threading pass optimizing for size.
    1013              : class pass_early_thread_jumps : public gimple_opt_pass
    1014              : {
    1015              : public:
    1016       294536 :   pass_early_thread_jumps (gcc::context *ctxt)
    1017       589072 :     : gimple_opt_pass (pass_data_early_thread_jumps, ctxt)
    1018              :   {}
    1019              : 
    1020            0 :   opt_pass * clone () override
    1021              :   {
    1022            0 :     return new pass_early_thread_jumps (m_ctxt);
    1023              :   }
    1024       294536 :   void set_pass_param (unsigned int, bool param) override
    1025              :   {
    1026       294536 :     m_first = param;
    1027       294536 :   }
    1028      2569301 :   bool gate (function *) override
    1029              :   {
    1030      2569301 :     return flag_thread_jumps;
    1031              :   }
    1032      2568935 :   unsigned int execute (function *fun) override
    1033              :   {
    1034      2568935 :     back_threader threader (fun, BT_NONE, m_first);
    1035      2568935 :     return threader.thread_blocks ();
    1036      2568935 :   }
    1037              : private:
    1038              :   bool m_first;
    1039              : };
    1040              : 
    1041              : // Jump threading pass without resolving of unknown SSAs.
    1042              : class pass_thread_jumps : public gimple_opt_pass
    1043              : {
    1044              : public:
    1045       589072 :   pass_thread_jumps (gcc::context *ctxt)
    1046      1178144 :     : gimple_opt_pass (pass_data_thread_jumps, ctxt)
    1047              :   {}
    1048       294536 :   opt_pass * clone (void) override
    1049              :   {
    1050       294536 :     return new pass_thread_jumps (m_ctxt);
    1051              :   }
    1052       589072 :   void set_pass_param (unsigned int, bool param) override
    1053              :   {
    1054       589072 :     m_first = param;
    1055       589072 :   }
    1056      2136438 :   bool gate (function *) override
    1057              :   {
    1058      2136438 :     return flag_thread_jumps && flag_expensive_optimizations;
    1059              :   }
    1060      1977175 :   unsigned int execute (function *fun) override
    1061              :   {
    1062      1977175 :     back_threader threader (fun, BT_SPEED, m_first);
    1063      1977175 :     return threader.thread_blocks ();
    1064      1977175 :   }
    1065              : private:
    1066              :   bool m_first;
    1067              : };
    1068              : 
    1069              : // Jump threading pass that fully resolves unknown SSAs.
    1070              : class pass_thread_jumps_full : public gimple_opt_pass
    1071              : {
    1072              : public:
    1073       589072 :   pass_thread_jumps_full (gcc::context *ctxt)
    1074      1178144 :     : gimple_opt_pass (pass_data_thread_jumps_full, ctxt)
    1075              :   {}
    1076       294536 :   opt_pass * clone (void) override
    1077              :   {
    1078       294536 :     return new pass_thread_jumps_full (m_ctxt);
    1079              :   }
    1080       589072 :   void set_pass_param (unsigned int, bool param) override
    1081              :   {
    1082       589072 :     m_first = param;
    1083       589072 :   }
    1084      2136438 :   bool gate (function *) override
    1085              :   {
    1086      2136438 :     return flag_thread_jumps && flag_expensive_optimizations;
    1087              :   }
    1088      1977181 :   unsigned int execute (function *fun) override
    1089              :   {
    1090      1977181 :     back_threader threader (fun, BT_SPEED | BT_RESOLVE, m_first);
    1091      1977181 :     return threader.thread_blocks ();
    1092      1977181 :   }
    1093              : private:
    1094              :   bool m_first;
    1095              : };
    1096              : 
    1097              : } // namespace {
    1098              : 
    1099              : gimple_opt_pass *
    1100       294536 : make_pass_thread_jumps (gcc::context *ctxt)
    1101              : {
    1102       294536 :   return new pass_thread_jumps (ctxt);
    1103              : }
    1104              : 
    1105              : gimple_opt_pass *
    1106       294536 : make_pass_thread_jumps_full (gcc::context *ctxt)
    1107              : {
    1108       294536 :   return new pass_thread_jumps_full (ctxt);
    1109              : }
    1110              : 
    1111              : gimple_opt_pass *
    1112       294536 : make_pass_early_thread_jumps (gcc::context *ctxt)
    1113              : {
    1114       294536 :   return new pass_early_thread_jumps (ctxt);
    1115              : }
        

Generated by: LCOV version 2.5.0-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.