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

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.