LCOV - code coverage report
Current view: top level - gcc - gimple-ssa-sccopy.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.4 % 238 220
Test Date: 2026-06-20 15:32:29 Functions: 100.0 % 15 15
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Strongly-connected copy propagation pass for the GNU compiler.
       2              :    Copyright (C) 2023-2026 Free Software Foundation, Inc.
       3              :    Contributed by Filip Kastl <fkastl@suse.cz>
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it under
       8              : the terms of the GNU General Public License as published by the Free
       9              : Software Foundation; either version 3, or (at your option) any later
      10              : version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15              : for more details.
      16              : 
      17              : You should have received a copy of the GNU General Public License
      18              : along with GCC; see the file COPYING3.  If not see
      19              : <http://www.gnu.org/licenses/>.  */
      20              : 
      21              : #define INCLUDE_ALGORITHM
      22              : #include "config.h"
      23              : #include "system.h"
      24              : #include "coretypes.h"
      25              : #include "backend.h"
      26              : #include "tree.h"
      27              : #include "gimple.h"
      28              : #include "tree-pass.h"
      29              : #include "ssa.h"
      30              : #include "gimple-iterator.h"
      31              : #include "vec.h"
      32              : #include "hash-set.h"
      33              : #include "ssa-iterators.h"
      34              : #include "gimple-fold.h"
      35              : #include "gimplify.h"
      36              : #include "tree-cfg.h"
      37              : #include "tree-eh.h"
      38              : #include "builtins.h"
      39              : #include "tree-ssa-dce.h"
      40              : #include "fold-const.h"
      41              : #include "tree-pretty-print.h"
      42              : 
      43              : /* Strongly connected copy propagation pass.
      44              : 
      45              :    This is a lightweight copy propagation pass that is also able to eliminate
      46              :    redundant PHI statements.  The pass considers the following types of copy
      47              :    statements:
      48              : 
      49              :    1 An assignment statement with a single argument.
      50              : 
      51              :    _3 = _2;
      52              :    _4 = 5;
      53              : 
      54              :    2 A degenerate PHI statement.  A degenerate PHI is a PHI that only refers to
      55              :      itself or one other value.
      56              : 
      57              :    _5 = PHI <_1>;
      58              :    _6 = PHI <_6, _6, _1, _1>;
      59              :    _7 = PHI <16, _7>;
      60              : 
      61              :    3 A set of PHI statements that only refer to each other or to one other
      62              :      value.
      63              : 
      64              :    _8 = PHI <_9, _10>;
      65              :    _9 = PHI <_8, _10>;
      66              :    _10 = PHI <_8, _9, _1>;
      67              : 
      68              :    All of these statements produce copies and can be eliminated from the
      69              :    program.  For a copy statement we identify the value it creates a copy of
      70              :    and replace references to the statement with the value -- we propagate the
      71              :    copy.
      72              : 
      73              :    _3 = _2; // Replace all occurrences of _3 by _2
      74              : 
      75              :    _8 = PHI <_9, _10>;
      76              :    _9 = PHI <_8, _10>;
      77              :    _10 = PHI <_8, _9, _1>; // Replace all occurrences of _8, _9 and _10 by _1
      78              : 
      79              :    To find all three types of copy statements we use an algorithm based on
      80              :    strongly-connected components (SCCs) in dataflow graph.  The algorithm was
      81              :    introduced in an article from 2013[1]. We describe the algorithm below.
      82              : 
      83              :    To identify SCCs we implement the Robert Tarjan's SCC algorithm.  For the
      84              :    SCC computation we wrap potential copy statements in the 'vertex' struct.
      85              :    To each of these statements we also assign a vertex number ('vxnum'). Since
      86              :    the main algorithm has to be able to compute SCCs of subgraphs of the whole
      87              :    dataflow graph we use GIMPLE stmt flags to prevent Tarjan's algorithm from
      88              :    leaving the subgraph.
      89              : 
      90              :    References:
      91              : 
      92              :      [1] Simple and Efficient Construction of Static Single Assignmemnt Form,
      93              :      Braun, Buchwald, Hack, Leissa, Mallon, Zwinkau, 2013, LNCS vol. 7791,
      94              :      Section 3.2.  */
      95              : 
      96              : namespace {
      97              : 
      98              : /* State of vertex during SCC discovery.
      99              : 
     100              :    unvisited  Vertex hasn't yet been popped from worklist.
     101              :    vopen      DFS has visited vertex for the first time.  Vertex has been put
     102              :               on Tarjan stack.
     103              :    closed     DFS has backtracked through vertex.  At this point, vertex
     104              :               doesn't have any unvisited neighbors.
     105              :    in_scc     Vertex has been popped from Tarjan stack.  */
     106              : 
     107              : enum vstate
     108              : {
     109              :   unvisited,
     110              :   vopen,
     111              :   closed,
     112              :   in_scc
     113              : };
     114              : 
     115              : /* Information about a vertex.  Used by SCC discovery.  */
     116              : 
     117              : struct vertex
     118              : {
     119              :   bool active; /* scc_discovery::compute_sccs () only considers a subgraph of
     120              :                   the whole dataflow graph.  It uses this flag so that it knows
     121              :                   which vertices are part of this subgraph.  */
     122              :   vstate state;
     123              :   unsigned index;
     124              :   unsigned lowlink;
     125              : };
     126              : 
     127              : /* SCC discovery.
     128              : 
     129              :    Used to find SCCs in a dataflow graph.  Implements Tarjan's SCC
     130              :    algorithm.  */
     131              : 
     132              : class scc_discovery
     133              : {
     134              : public:
     135              :   scc_discovery ();
     136              :   ~scc_discovery ();
     137              :   auto_vec<vec<gimple *>> compute_sccs (vec<gimple *> &stmts);
     138              : 
     139              : private:
     140              :   vertex* vertices; /* Indexed by SSA_NAME_VERSION.  */
     141              :   auto_vec<unsigned> worklist; /* DFS stack.  */
     142              :   auto_vec<unsigned> stack; /* Tarjan stack.  */
     143              : 
     144              :   void visit_neighbor (tree neigh_tree, unsigned parent_vxnum);
     145              : };
     146              : 
     147      3442878 : scc_discovery::scc_discovery ()
     148              : {
     149              :   /* Create vertex struct for each SSA name.  */
     150      6885756 :   vertices = XNEWVEC (struct vertex, num_ssa_names);
     151      3442878 :   unsigned i = 0;
     152    129776926 :   for (i = 0; i < num_ssa_names; i++)
     153    126334048 :     vertices[i].active = false;
     154      3442878 : }
     155              : 
     156      3442878 : scc_discovery::~scc_discovery ()
     157              : {
     158      3442878 :   XDELETEVEC (vertices);
     159      3442878 : }
     160              : 
     161              : /* Part of 'scc_discovery::compute_sccs ()'.  */
     162              : 
     163              : void
     164     49944397 : scc_discovery::visit_neighbor (tree neigh_tree, unsigned parent_version)
     165              : {
     166     49944397 :   if (TREE_CODE (neigh_tree) != SSA_NAME)
     167     37807482 :     return; /* Skip any neighbor that isn't an SSA name.  */
     168     45403432 :   unsigned neigh_version = SSA_NAME_VERSION (neigh_tree);
     169              : 
     170              :   /* Skip neighbors outside the subgraph that Tarjan currently works
     171              :      with.  */
     172     45403432 :   if (!vertices[neigh_version].active)
     173              :     return;
     174              : 
     175     12136915 :   vstate neigh_state = vertices[neigh_version].state;
     176     12136915 :   vstate parent_state = vertices[parent_version].state;
     177     12136915 :   if (parent_state == vopen) /* We're currently opening parent.  */
     178              :     {
     179              :       /* Put unvisited neighbors on worklist.  Update lowlink of parent
     180              :          vertex according to indices of neighbors present on stack.  */
     181      4352920 :       switch (neigh_state)
     182              :         {
     183      3113880 :         case unvisited:
     184      3113880 :           worklist.safe_push (neigh_version);
     185      3113880 :           break;
     186       578453 :         case vopen:
     187       578453 :         case closed:
     188       578453 :           vertices[parent_version].lowlink
     189       578453 :             = std::min (vertices[parent_version].lowlink,
     190              :                         vertices[neigh_version].index);
     191       578453 :           break;
     192              :         case in_scc:
     193              :           /* Ignore these edges.  */
     194              :           break;
     195              :         }
     196              :     }
     197      7783995 :   else if (parent_state == closed) /* We're currently closing parent.  */
     198              :     {
     199              :       /* Update lowlink of parent vertex according to lowlinks of
     200              :          children of parent (in terms of DFS tree).  */
     201      4526619 :       if (neigh_state == closed)
     202              :         {
     203       758932 :           vertices[parent_version].lowlink
     204       758932 :             = std::min (vertices[parent_version].lowlink,
     205              :                         vertices[neigh_version].lowlink);
     206              :         }
     207              :     }
     208              : }
     209              : 
     210              : /* Compute SCCs in dataflow graph on given statements 'stmts'.  Ignore
     211              :    statements outside 'stmts'.  Return the SCCs in a reverse topological
     212              :    order.
     213              : 
     214              :    stmt_may_generate_copy () must be true for all statements from 'stmts'!  */
     215              : 
     216              : auto_vec<vec<gimple *>>
     217     10415705 : scc_discovery::compute_sccs (vec<gimple *> &stmts)
     218              : {
     219     10415705 :   auto_vec<vec<gimple *>> sccs;
     220              : 
     221     21362081 :   for (gimple *stmt : stmts)
     222              :     {
     223      8479238 :       unsigned i;
     224      8479238 :       switch (gimple_code (stmt))
     225              :         {
     226        32470 :           case GIMPLE_ASSIGN:
     227        32470 :             i = SSA_NAME_VERSION (gimple_assign_lhs (stmt));
     228        32470 :             break;
     229      8446768 :           case GIMPLE_PHI:
     230      8446768 :             i = SSA_NAME_VERSION (gimple_phi_result (stmt));
     231      8446768 :             break;
     232            0 :           default:
     233            0 :             gcc_unreachable ();
     234              :         }
     235              : 
     236      8479238 :       vertices[i].index = 0;
     237      8479238 :       vertices[i].lowlink = 0;
     238      8479238 :       vertices[i].state = unvisited;
     239      8479238 :       vertices[i].active = true; /* Mark the subgraph we'll be working on so
     240              :                                     that we don't leave it.  */
     241              : 
     242      8479238 :       worklist.safe_push (i);
     243              :     }
     244              : 
     245              :   /* Worklist loop.  */
     246              :   unsigned curr_index = 0;
     247     30488061 :   while (!worklist.is_empty ())
     248              :     {
     249     20072356 :       unsigned i = worklist.pop ();
     250     20072356 :       gimple *stmt = SSA_NAME_DEF_STMT (ssa_name (i));
     251     20072356 :       vstate state = vertices[i].state;
     252              : 
     253     20072356 :       if (state == unvisited)
     254              :         {
     255      8479238 :           vertices[i].state = vopen;
     256              : 
     257              :           /* Assign index to this vertex.  */
     258      8479238 :           vertices[i].index = curr_index;
     259      8479238 :           vertices[i].lowlink = curr_index;
     260      8479238 :           curr_index++;
     261              : 
     262              :           /* Put vertex on stack and also on worklist to be closed later.  */
     263      8479238 :           stack.safe_push (i);
     264      8479238 :           worklist.safe_push (i);
     265              :         }
     266     11593118 :       else if (state == vopen)
     267      8479238 :         vertices[i].state = closed;
     268              : 
     269              :       /* Visit neighbors of this vertex.  */
     270     20072356 :       tree op;
     271     20072356 :       gphi *phi;
     272     20072356 :       switch (gimple_code (stmt))
     273              :         {
     274     20005016 :           case GIMPLE_PHI:
     275     20005016 :             phi = as_a <gphi *> (stmt);
     276     20005016 :             unsigned j;
     277     89887089 :             for (j = 0; j < gimple_phi_num_args (phi); j++)
     278              :               {
     279     49877057 :                 op = gimple_phi_arg_def (phi, j);
     280     49877057 :                 visit_neighbor (op, i);
     281              :               }
     282              :             break;
     283        67340 :           case GIMPLE_ASSIGN:
     284        67340 :             op = gimple_assign_rhs1 (stmt);
     285        67340 :             visit_neighbor (op, i);
     286        67340 :             break;
     287            0 :           default:
     288            0 :             gcc_unreachable ();
     289              :         }
     290              : 
     291              :       /* If we've just closed a root vertex of an scc, pop scc from stack.  */
     292     20072356 :       if (state == vopen && vertices[i].lowlink == vertices[i].index)
     293              :         {
     294      7966085 :           vec<gimple *> scc = vNULL;
     295              : 
     296      8479238 :           unsigned j;
     297      8479238 :           do
     298              :             {
     299      8479238 :               j = stack.pop ();
     300      8479238 :               scc.safe_push (SSA_NAME_DEF_STMT (ssa_name (j)));
     301      8479238 :               vertices[j].state = in_scc;
     302              :             }
     303      8479238 :           while (j != i);
     304              : 
     305      7966085 :           sccs.safe_push (scc);
     306              :         }
     307              :     }
     308              : 
     309     10415705 :   if (!stack.is_empty ())
     310            0 :     gcc_unreachable ();
     311              : 
     312              :   /* Clear 'active' flags.  */
     313     21362081 :   for (gimple *stmt : stmts)
     314              :     {
     315      8479238 :       unsigned i;
     316      8479238 :       switch (gimple_code (stmt))
     317              :         {
     318        32470 :           case GIMPLE_ASSIGN:
     319        32470 :             i = SSA_NAME_VERSION (gimple_assign_lhs (stmt));
     320        32470 :             break;
     321      8446768 :           case GIMPLE_PHI:
     322      8446768 :             i = SSA_NAME_VERSION (gimple_phi_result (stmt));
     323      8446768 :             break;
     324            0 :           default:
     325            0 :             gcc_unreachable ();
     326              :         }
     327              : 
     328      8479238 :       vertices[i].active = false;
     329              :     }
     330              : 
     331     10415705 :   return sccs;
     332              : }
     333              : 
     334              : } // anon namespace
     335              : 
     336              : /* Could this statement potentially be a copy statement?
     337              : 
     338              :    This pass only considers statements for which this function returns 'true'.
     339              :    Those are basically PHI functions and assignment statements similar to
     340              : 
     341              :    _2 = _1;
     342              :    or
     343              :    _2 = 5;  */
     344              : 
     345              : static bool
     346    164646181 : stmt_may_generate_copy (gimple *stmt)
     347              : {
     348              :   /* A PHI may generate a copy.  */
     349    164646181 :   if (gimple_code (stmt) == GIMPLE_PHI)
     350              :     {
     351      8601511 :       gphi *phi = as_a <gphi *> (stmt);
     352              : 
     353              :       /* No OCCURS_IN_ABNORMAL_PHI SSA names in lhs nor rhs.  */
     354      8601511 :       if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (phi)))
     355              :         return false;
     356              : 
     357              :       unsigned i;
     358     30501420 :       for (i = 0; i < gimple_phi_num_args (phi); i++)
     359              :         {
     360     21914003 :           tree op = gimple_phi_arg_def (phi, i);
     361     21914003 :           if (TREE_CODE (op) == SSA_NAME
     362     21914003 :               && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op))
     363              :             return false;
     364              :         }
     365              : 
     366              :       /* If PHI has more than one unique non-SSA arguments, it won't generate a
     367              :          copy.  */
     368              :       tree const_op = NULL_TREE;
     369     29686431 :       for (i = 0; i < gimple_phi_num_args (phi); i++)
     370              :         {
     371     21419306 :           tree op = gimple_phi_arg_def (phi, i);
     372     21419306 :           if (TREE_CODE (op) != SSA_NAME)
     373              :             {
     374      2645923 :               if (const_op && !operand_equal_p (op, const_op))
     375              :                 return false;
     376              :               const_op = op;
     377              :             }
     378              :         }
     379              : 
     380              :       return true;
     381              :     }
     382              : 
     383              :   /* Or a statement of type _2 = _1; OR _2 = 5; may generate a copy.  */
     384              : 
     385    156044670 :   if (!gimple_assign_single_p (stmt))
     386              :     return false;
     387              : 
     388     31347437 :   tree lhs = gimple_assign_lhs (stmt);
     389     31347437 :   tree rhs = gimple_assign_rhs1 (stmt);
     390              : 
     391     31347437 :   if (TREE_CODE (lhs) != SSA_NAME)
     392              :     return false;
     393              : 
     394              :   /* lhs shouldn't flow through any abnormal edges.  */
     395     13791017 :   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
     396              :     return false;
     397              : 
     398     13790193 :   if (is_gimple_min_invariant (rhs))
     399              :     return true;  /* A statement of type _2 = 5;.  */
     400              : 
     401     13783476 :   if (TREE_CODE (rhs) != SSA_NAME)
     402              :     return false;
     403              : 
     404              :   /* rhs shouldn't flow through any abnormal edges.  */
     405        26927 :   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs))
     406              :     return false;
     407              : 
     408              :   return true;  /* A statement of type _2 = _1;.  */
     409              : }
     410              : 
     411              : /* Return all statements in cfun that could generate copies.  All statements
     412              :    for which stmt_may_generate_copy returns 'true'.  */
     413              : 
     414              : static auto_vec<gimple *>
     415      3442878 : get_all_stmt_may_generate_copy (void)
     416              : {
     417      3442878 :   auto_vec<gimple *> result;
     418              : 
     419      3442878 :   basic_block bb;
     420     25870885 :   FOR_EACH_BB_FN (bb, cfun)
     421              :     {
     422     22428007 :       gimple_stmt_iterator gsi;
     423    200900684 :       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     424              :         {
     425    156044670 :           gimple *s = gsi_stmt (gsi);
     426    156044670 :           if (stmt_may_generate_copy (s))
     427        32470 :             result.safe_push (s);
     428              :         }
     429              : 
     430     22428007 :       gphi_iterator pi;
     431     31029518 :       for (pi = gsi_start_phis (bb); !gsi_end_p (pi); gsi_next (&pi))
     432              :         {
     433      8601511 :           gimple *s = pi.phi ();
     434      8601511 :           if (stmt_may_generate_copy (s))
     435      8267125 :             result.safe_push (s);
     436              :         }
     437              :     }
     438              : 
     439      3442878 :   return result;
     440              : }
     441              : 
     442              : /* SCC copy propagation
     443              : 
     444              :    'scc_copy_prop::propagate ()' is the main function of this pass.  */
     445              : 
     446              : class scc_copy_prop
     447              : {
     448              : public:
     449              :   scc_copy_prop ();
     450              :   ~scc_copy_prop ();
     451              :   bool propagate ();
     452              : 
     453              : private:
     454              :   /* Bitmap tracking statements which were propagated so that they can be
     455              :      removed at the end of the pass.  */
     456              :   bitmap dead_stmts;
     457              : 
     458              :   void visit_op (tree op, hash_set<tree> &outer_ops,
     459              :                                 hash_set<gimple *> &scc_set, bool &is_inner,
     460              :                                 tree &last_outer_op);
     461              :   bool replace_scc_by_value (vec<gimple *> scc, tree val);
     462              : };
     463              : 
     464              : /* For each statement from given SCC, replace its usages by value
     465              :    VAL.  */
     466              : 
     467              : bool
     468       993258 : scc_copy_prop::replace_scc_by_value (vec<gimple *> scc, tree val)
     469              : {
     470       993258 :   bool didsomething = false;
     471      3983615 :   for (gimple *stmt : scc)
     472              :     {
     473      1003841 :       tree name = gimple_get_lhs (stmt);
     474      1003841 :       if (dump_file && (dump_flags & TDF_DETAILS))
     475              :         {
     476            0 :           fprintf (dump_file, "Replacing ");
     477            0 :           print_generic_expr (dump_file, name);
     478            0 :           fprintf (dump_file, " with ");
     479            0 :           print_generic_expr (dump_file, val);
     480            0 :           fprintf (dump_file, "\n");
     481              :           
     482              :         }
     483      1003841 :       replace_uses_by (name, val);
     484      1003841 :       if (TREE_CODE (val) == SSA_NAME)
     485       994501 :         maybe_duplicate_ssa_info_at_copy (name, val);
     486      1003841 :       bitmap_set_bit (dead_stmts, SSA_NAME_VERSION (name));
     487      1003841 :       didsomething = true;
     488              :     }
     489              : 
     490       993258 :   if (dump_file)
     491           56 :     fprintf (dump_file, "Replacing SCC of size %d\n", scc.length ());
     492       993258 :   return didsomething;
     493              : }
     494              : 
     495              : /* Part of 'scc_copy_prop::propagate ()'.  */
     496              : 
     497              : void
     498     21068345 : scc_copy_prop::visit_op (tree op, hash_set<tree> &outer_ops,
     499              :                          hash_set<gimple *> &scc_set, bool &is_inner,
     500              :                          tree &last_outer_op)
     501              : {
     502     21068345 :   bool op_in_scc = false;
     503              : 
     504     21068345 :   if (TREE_CODE (op) == SSA_NAME)
     505              :     {
     506     19122167 :       gimple *op_stmt = SSA_NAME_DEF_STMT (op);
     507     19122167 :       if (scc_set.contains (op_stmt))
     508      1203102 :         op_in_scc = true;
     509              :     }
     510              : 
     511     19122167 :   if (!op_in_scc)
     512              :     {
     513     19865243 :       outer_ops.add (op);
     514     19865243 :       last_outer_op = op;
     515     19865243 :       is_inner = false;
     516              :     }
     517     21068345 : }
     518              : 
     519              : /* Main function of this pass.  Find and propagate all three types of copy
     520              :    statements (see pass description above).
     521              : 
     522              :    This is an implementation of an algorithm from the paper Simple and
     523              :    Efficient Construction of Static Single Assignmemnt Form[1].  It is based
     524              :    on strongly-connected components (SCCs) in dataflow graph.  The original
     525              :    algorithm only considers PHI statements.  We extend it to also consider
     526              :    assignment statements of type _2 = _1;.
     527              : 
     528              :    The algorithm is based on this definition of a set of redundant PHIs[1]:
     529              : 
     530              :      A non-empty set P of PHI functions is redundant iff the PHI functions just
     531              :      reference each other or one other value
     532              : 
     533              :    It uses this lemma[1]:
     534              : 
     535              :      Let P be a redundant set of PHI functions.  Then there is a
     536              :      strongly-connected component S subset of P that is also redundant.
     537              : 
     538              :    The algorithm works in this way:
     539              : 
     540              :      1 Find SCCs
     541              :      2 For each SCC S in topological order:
     542              :      3   Construct set 'inner' of statements that only have other statements
     543              :          from S on their right hand side
     544              :      4   Construct set 'outer' of values that originate outside S and appear on
     545              :          right hand side of some statement from S
     546              :      5   If |outer| = 1, outer only contains a value v.  Statements in S only
     547              :          refer to each other or to v -- they are redundant.  Propagate v.
     548              :          Else, recurse on statements in inner.
     549              : 
     550              :    The implementation is non-recursive.
     551              : 
     552              :    References:
     553              : 
     554              :      [1] Simple and Efficient Construction of Static Single Assignmemnt Form,
     555              :      Braun, Buchwald, Hack, Leissa, Mallon, Zwinkau, 2013, LNCS vol. 7791,
     556              :      Section 3.2.  */
     557              : 
     558              : bool
     559      3442878 : scc_copy_prop::propagate ()
     560              : {
     561      3442878 :   bool didsomething = false;
     562      3442878 :   auto_vec<gimple *> useful_stmts = get_all_stmt_may_generate_copy ();
     563      3442878 :   scc_discovery discovery;
     564              : 
     565      3442878 :   auto_vec<vec<gimple *>> worklist = discovery.compute_sccs (useful_stmts);
     566              : 
     567     14851841 :   while (!worklist.is_empty ())
     568              :     {
     569      7966085 :       vec<gimple *> scc = worklist.pop ();
     570              : 
     571              :       /* When we do 'replace_scc_by_value' it may happen that some EH edges
     572              :          get removed.  That means parts of CFG get removed.  Those may
     573              :          contain copy statements.  For that reason we prune SCCs here.  */
     574      7966085 :       unsigned i;
     575     16445323 :       for (i = 0; i < scc.length ();)
     576      8479238 :         if (gimple_bb (scc[i]) == NULL)
     577            0 :           scc.unordered_remove (i);
     578              :         else
     579      8479238 :           i++;
     580      7966085 :       if (scc.is_empty ())
     581              :         {
     582            0 :           scc.release ();
     583            0 :           continue;
     584              :         }
     585              : 
     586      7966085 :       auto_vec<gimple *> inner;
     587      7966085 :       hash_set<tree> outer_ops;
     588      7966085 :       tree last_outer_op = NULL_TREE;
     589              : 
     590              :       /* Prepare hash set of PHIs in scc to query later.  */
     591      7966085 :       hash_set<gimple *> scc_set;
     592     16445323 :       for (gimple *stmt : scc)
     593      8479238 :         scc_set.add (stmt);
     594              : 
     595     16445323 :       for (gimple *stmt : scc)
     596              :         {
     597      8479238 :           bool is_inner = true;
     598              : 
     599      8479238 :           gphi *phi;
     600      8479238 :           tree op;
     601              : 
     602      8479238 :           switch (gimple_code (stmt))
     603              :             {
     604      8446768 :               case GIMPLE_PHI:
     605      8446768 :                 phi = as_a <gphi *> (stmt);
     606      8446768 :                 unsigned j;
     607     37929411 :                 for (j = 0; j < gimple_phi_num_args (phi); j++)
     608              :                   {
     609     21035875 :                     op = gimple_phi_arg_def (phi, j);
     610     21035875 :                     visit_op (op, outer_ops, scc_set, is_inner, last_outer_op);
     611              :                   }
     612              :                 break;
     613        32470 :               case GIMPLE_ASSIGN:
     614        32470 :                 op = gimple_assign_rhs1 (stmt);
     615        32470 :                 visit_op (op, outer_ops, scc_set, is_inner, last_outer_op);
     616        32470 :                 break;
     617            0 :               default:
     618            0 :                 gcc_unreachable ();
     619              :             }
     620              : 
     621      8479238 :           if (is_inner)
     622       189767 :             inner.safe_push (stmt);
     623              :         }
     624              : 
     625      7966085 :       if (outer_ops.elements () == 1)
     626              :         {
     627              :           /* The only operand in outer_ops.  */
     628       993258 :           tree outer_op = last_outer_op;
     629       993258 :           didsomething |= replace_scc_by_value (scc, outer_op);
     630              :         }
     631      6972827 :       else if (outer_ops.elements () > 1)
     632              :         {
     633              :           /* Add inner sccs to worklist.  */
     634      6972827 :           auto_vec<vec<gimple *>> inner_sccs
     635      6972827 :             = discovery.compute_sccs (inner);
     636      7302009 :           for (vec<gimple *> inner_scc : inner_sccs)
     637       149284 :             worklist.safe_push (inner_scc);
     638      6972827 :         }
     639              :       else
     640            0 :         gcc_unreachable ();
     641              : 
     642      7966085 :       scc.release ();
     643      7966085 :     }
     644      3442878 :   return didsomething;
     645      3442878 : }
     646              : 
     647      3442878 : scc_copy_prop::scc_copy_prop ()
     648              : {
     649              :   /* For propagated statements.  */
     650      3442878 :   dead_stmts = BITMAP_ALLOC (NULL);
     651      3442878 : }
     652              : 
     653      3442878 : scc_copy_prop::~scc_copy_prop ()
     654              : {
     655              :   /* Remove all propagated statements.  */
     656      3442878 :   simple_dce_from_worklist (dead_stmts);
     657      3442878 :   BITMAP_FREE (dead_stmts);
     658              : 
     659              :   /* Propagating a constant may create dead eh edges.  */
     660      3442878 :   basic_block bb;
     661     25870883 :   FOR_EACH_BB_FN (bb, cfun)
     662     22428005 :     gimple_purge_dead_eh_edges (bb);
     663      3442878 : }
     664              : 
     665              : namespace {
     666              : 
     667              : const pass_data pass_data_sccopy =
     668              : {
     669              :   GIMPLE_PASS, /* type */
     670              :   "sccopy", /* name */
     671              :   OPTGROUP_NONE, /* optinfo_flags */
     672              :   TV_NONE, /* tv_id */
     673              :   ( PROP_cfg | PROP_ssa ), /* properties_required */
     674              :   0, /* properties_provided */
     675              :   0, /* properties_destroyed */
     676              :   0, /* todo_flags_start */
     677              :   0, /* todo_flags_finish */
     678              : };
     679              : 
     680              : class pass_sccopy : public gimple_opt_pass
     681              : {
     682              : public:
     683       597656 :   pass_sccopy (gcc::context *ctxt)
     684      1195312 :     : gimple_opt_pass (pass_data_sccopy, ctxt)
     685              :   {}
     686              : 
     687              :   /* opt_pass methods: */
     688      3442999 :   virtual bool gate (function *) final override { return true; }
     689              :   virtual unsigned int execute (function *) final override;
     690       298828 :   opt_pass * clone () final override { return new pass_sccopy (m_ctxt); }
     691              : }; // class pass_sccopy
     692              : 
     693              : unsigned
     694      3442878 : pass_sccopy::execute (function *)
     695              : {
     696      3442878 :   scc_copy_prop sccopy;
     697      3442878 :   return sccopy.propagate () ?  TODO_cleanup_cfg : 0;
     698      3442878 : }
     699              : 
     700              : } // anon namespace
     701              : 
     702              : gimple_opt_pass *
     703       298828 : make_pass_sccopy (gcc::context *ctxt)
     704              : {
     705       298828 :   return new pass_sccopy (ctxt);
     706              : }
        

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.