LCOV - code coverage report
Current view: top level - gcc - gimple-ssa-sccopy.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.6 % 242 224
Test Date: 2026-02-28 14:20:25 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 occurences of _3 by _2
      74              : 
      75              :    _8 = PHI <_9, _10>;
      76              :    _9 = PHI <_8, _10>;
      77              :    _10 = PHI <_8, _9, _1>; // Replace all occurences 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      3453819 : scc_discovery::scc_discovery ()
     148              : {
     149              :   /* Create vertex struct for each SSA name.  */
     150      6907638 :   vertices = XNEWVEC (struct vertex, num_ssa_names);
     151      3453819 :   unsigned i = 0;
     152    130153589 :   for (i = 0; i < num_ssa_names; i++)
     153    126699770 :     vertices[i].active = false;
     154      3453819 : }
     155              : 
     156      3453819 : scc_discovery::~scc_discovery ()
     157              : {
     158      3453819 :   XDELETEVEC (vertices);
     159      3453819 : }
     160              : 
     161              : /* Part of 'scc_discovery::compute_sccs ()'.  */
     162              : 
     163              : void
     164     45892352 : scc_discovery::visit_neighbor (tree neigh_tree, unsigned parent_version)
     165              : {
     166     45892352 :   if (TREE_CODE (neigh_tree) != SSA_NAME)
     167     34547929 :     return; /* Skip any neighbor that isn't an SSA name.  */
     168     41197202 :   unsigned neigh_version = SSA_NAME_VERSION (neigh_tree);
     169              : 
     170              :   /* Skip neighbors outside the subgraph that Tarjan currently works
     171              :      with.  */
     172     41197202 :   if (!vertices[neigh_version].active)
     173              :     return;
     174              : 
     175     11344423 :   vstate neigh_state = vertices[neigh_version].state;
     176     11344423 :   vstate parent_state = vertices[parent_version].state;
     177     11344423 :   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      3956582 :       switch (neigh_state)
     182              :         {
     183      2791088 :         case unvisited:
     184      2791088 :           worklist.safe_push (neigh_version);
     185      2791088 :           break;
     186       561023 :         case vopen:
     187       561023 :         case closed:
     188       561023 :           vertices[parent_version].lowlink
     189       561023 :             = std::min (vertices[parent_version].lowlink,
     190              :                         vertices[neigh_version].index);
     191       561023 :           break;
     192              :         case in_scc:
     193              :           /* Ignore these edges.  */
     194              :           break;
     195              :         }
     196              :     }
     197      7387841 :   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      4120388 :       if (neigh_state == closed)
     202              :         {
     203       707500 :           vertices[parent_version].lowlink
     204       707500 :             = 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     10298880 : scc_discovery::compute_sccs (vec<gimple *> &stmts)
     218              : {
     219     10298880 :   auto_vec<vec<gimple *>> sccs;
     220              : 
     221     20341294 :   for (gimple *stmt : stmts)
     222              :     {
     223      7717960 :       unsigned i;
     224      7717960 :       switch (gimple_code (stmt))
     225              :         {
     226        21588 :           case GIMPLE_ASSIGN:
     227        21588 :             i = SSA_NAME_VERSION (gimple_assign_lhs (stmt));
     228        21588 :             break;
     229      7696372 :           case GIMPLE_PHI:
     230      7696372 :             i = SSA_NAME_VERSION (gimple_phi_result (stmt));
     231      7696372 :             break;
     232            0 :           default:
     233            0 :             gcc_unreachable ();
     234              :         }
     235              : 
     236      7717960 :       vertices[i].index = 0;
     237      7717960 :       vertices[i].lowlink = 0;
     238      7717960 :       vertices[i].state = unvisited;
     239      7717960 :       vertices[i].active = true; /* Mark the subgraph we'll be working on so
     240              :                                     that we don't leave it.  */
     241              : 
     242      7717960 :       worklist.safe_push (i);
     243              :     }
     244              : 
     245              :   /* Worklist loop.  */
     246              :   unsigned curr_index = 0;
     247     28525888 :   while (!worklist.is_empty ())
     248              :     {
     249     18227008 :       unsigned i = worklist.pop ();
     250     18227008 :       gimple *stmt = SSA_NAME_DEF_STMT (ssa_name (i));
     251     18227008 :       vstate state = vertices[i].state;
     252              : 
     253     18227008 :       if (state == unvisited)
     254              :         {
     255      7717960 :           vertices[i].state = vopen;
     256              : 
     257              :           /* Assign index to this vertex.  */
     258      7717960 :           vertices[i].index = curr_index;
     259      7717960 :           vertices[i].lowlink = curr_index;
     260      7717960 :           curr_index++;
     261              : 
     262              :           /* Put vertex on stack and also on worklist to be closed later.  */
     263      7717960 :           stack.safe_push (i);
     264      7717960 :           worklist.safe_push (i);
     265              :         }
     266     10509048 :       else if (state == vopen)
     267      7717960 :         vertices[i].state = closed;
     268              : 
     269              :       /* Visit neighbors of this vertex.  */
     270     18227008 :       tree op;
     271     18227008 :       gphi *phi;
     272     18227008 :       switch (gimple_code (stmt))
     273              :         {
     274     18182792 :           case GIMPLE_PHI:
     275     18182792 :             phi = as_a <gphi *> (stmt);
     276     18182792 :             unsigned j;
     277     82213720 :             for (j = 0; j < gimple_phi_num_args (phi); j++)
     278              :               {
     279     45848136 :                 op = gimple_phi_arg_def (phi, j);
     280     45848136 :                 visit_neighbor (op, i);
     281              :               }
     282              :             break;
     283        44216 :           case GIMPLE_ASSIGN:
     284        44216 :             op = gimple_assign_rhs1 (stmt);
     285        44216 :             visit_neighbor (op, i);
     286        44216 :             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     18227008 :       if (state == vopen && vertices[i].lowlink == vertices[i].index)
     293              :         {
     294      7252183 :           vec<gimple *> scc = vNULL;
     295              : 
     296      7717960 :           unsigned j;
     297      7717960 :           do
     298              :             {
     299      7717960 :               j = stack.pop ();
     300      7717960 :               scc.safe_push (SSA_NAME_DEF_STMT (ssa_name (j)));
     301      7717960 :               vertices[j].state = in_scc;
     302              :             }
     303      7717960 :           while (j != i);
     304              : 
     305      7252183 :           sccs.safe_push (scc);
     306              :         }
     307              :     }
     308              : 
     309     10298880 :   if (!stack.is_empty ())
     310            0 :     gcc_unreachable ();
     311              : 
     312              :   /* Clear 'active' flags.  */
     313     20341294 :   for (gimple *stmt : stmts)
     314              :     {
     315      7717960 :       unsigned i;
     316      7717960 :       switch (gimple_code (stmt))
     317              :         {
     318        21588 :           case GIMPLE_ASSIGN:
     319        21588 :             i = SSA_NAME_VERSION (gimple_assign_lhs (stmt));
     320        21588 :             break;
     321      7696372 :           case GIMPLE_PHI:
     322      7696372 :             i = SSA_NAME_VERSION (gimple_phi_result (stmt));
     323      7696372 :             break;
     324            0 :           default:
     325            0 :             gcc_unreachable ();
     326              :         }
     327              : 
     328      7717960 :       vertices[i].active = false;
     329              :     }
     330              : 
     331     10298880 :   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    157822972 : stmt_may_generate_copy (gimple *stmt)
     347              : {
     348              :   /* A PHI may generate a copy.  */
     349    157822972 :   if (gimple_code (stmt) == GIMPLE_PHI)
     350              :     {
     351      7894182 :       gphi *phi = as_a <gphi *> (stmt);
     352              : 
     353              :       /* No OCCURS_IN_ABNORMAL_PHI SSA names in lhs nor rhs.  */
     354      7894182 :       if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (phi)))
     355              :         return false;
     356              : 
     357              :       unsigned i;
     358     28042343 :       for (i = 0; i < gimple_phi_num_args (phi); i++)
     359              :         {
     360     20160528 :           tree op = gimple_phi_arg_def (phi, i);
     361     20160528 :           if (TREE_CODE (op) == SSA_NAME
     362     20160528 :               && 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     27178353 :       for (i = 0; i < gimple_phi_num_args (phi); i++)
     370              :         {
     371     19623867 :           tree op = gimple_phi_arg_def (phi, i);
     372     19623867 :           if (TREE_CODE (op) != SSA_NAME)
     373              :             {
     374      2646901 :               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    149928790 :   if (!gimple_assign_single_p (stmt))
     386              :     return false;
     387              : 
     388     28935434 :   tree lhs = gimple_assign_lhs (stmt);
     389     28935434 :   tree rhs = gimple_assign_rhs1 (stmt);
     390              : 
     391     28935434 :   if (TREE_CODE (lhs) != SSA_NAME)
     392              :     return false;
     393              : 
     394              :   /* lhs shouldn't flow through any abnormal edges.  */
     395     13392925 :   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
     396              :     return false;
     397              : 
     398     13392265 :   if (is_gimple_min_invariant (rhs))
     399              :     return true;  /* A statement of type _2 = 5;.  */
     400              : 
     401     13386619 :   if (TREE_CODE (rhs) != SSA_NAME)
     402              :     return false;
     403              : 
     404              :   /* rhs shouldn't flow through any abnormal edges.  */
     405        25404 :   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs))
     406              :     return false;
     407              : 
     408              :   /* It is possible that lhs has more alignment or value range information.  By
     409              :      propagating we would lose this information.  So in the case that alignment
     410              :      or value range information differs, we are conservative and do not
     411              :      propagate.
     412              : 
     413              :      FIXME: Propagate alignment and value range info the same way copy-prop
     414              :      does.  */
     415        47210 :   if (POINTER_TYPE_P (TREE_TYPE (lhs))
     416         1475 :       && POINTER_TYPE_P (TREE_TYPE (rhs))
     417        25793 :       && SSA_NAME_PTR_INFO (lhs) != SSA_NAME_PTR_INFO (rhs))
     418              :     return false;
     419        45874 :   if (!POINTER_TYPE_P (TREE_TYPE (lhs))
     420        22843 :       && !POINTER_TYPE_P (TREE_TYPE (rhs))
     421        45874 :       && SSA_NAME_RANGE_INFO (lhs) != SSA_NAME_RANGE_INFO (rhs))
     422              :     return false;
     423              : 
     424              :   return true;  /* A statement of type _2 = _1;.  */
     425              : }
     426              : 
     427              : /* Return all statements in cfun that could generate copies.  All statements
     428              :    for which stmt_may_generate_copy returns 'true'.  */
     429              : 
     430              : static auto_vec<gimple *>
     431      3453819 : get_all_stmt_may_generate_copy (void)
     432              : {
     433      3453819 :   auto_vec<gimple *> result;
     434              : 
     435      3453819 :   basic_block bb;
     436     24394623 :   FOR_EACH_BB_FN (bb, cfun)
     437              :     {
     438     20940804 :       gimple_stmt_iterator gsi;
     439    191810398 :       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     440              :         {
     441    149928790 :           gimple *s = gsi_stmt (gsi);
     442    149928790 :           if (stmt_may_generate_copy (s))
     443        21588 :             result.safe_push (s);
     444              :         }
     445              : 
     446     20940804 :       gphi_iterator pi;
     447     28834986 :       for (pi = gsi_start_phis (bb); !gsi_end_p (pi); gsi_next (&pi))
     448              :         {
     449      7894182 :           gimple *s = pi.phi ();
     450      7894182 :           if (stmt_may_generate_copy (s))
     451      7554486 :             result.safe_push (s);
     452              :         }
     453              :     }
     454              : 
     455      3453819 :   return result;
     456              : }
     457              : 
     458              : /* SCC copy propagation
     459              : 
     460              :    'scc_copy_prop::propagate ()' is the main function of this pass.  */
     461              : 
     462              : class scc_copy_prop
     463              : {
     464              : public:
     465              :   scc_copy_prop ();
     466              :   ~scc_copy_prop ();
     467              :   bool propagate ();
     468              : 
     469              : private:
     470              :   /* Bitmap tracking statements which were propagated so that they can be
     471              :      removed at the end of the pass.  */
     472              :   bitmap dead_stmts;
     473              : 
     474              :   void visit_op (tree op, hash_set<tree> &outer_ops,
     475              :                                 hash_set<gimple *> &scc_set, bool &is_inner,
     476              :                                 tree &last_outer_op);
     477              :   bool replace_scc_by_value (vec<gimple *> scc, tree val);
     478              : };
     479              : 
     480              : /* For each statement from given SCC, replace its usages by value
     481              :    VAL.  */
     482              : 
     483              : bool
     484       407122 : scc_copy_prop::replace_scc_by_value (vec<gimple *> scc, tree val)
     485              : {
     486       407122 :   bool didsomething = false;
     487      1633339 :   for (gimple *stmt : scc)
     488              :     {
     489       411973 :       tree name = gimple_get_lhs (stmt);
     490       411973 :       if (dump_file && (dump_flags & TDF_DETAILS))
     491              :         {
     492            0 :           fprintf (dump_file, "Replacing ");
     493            0 :           print_generic_expr (dump_file, name);
     494            0 :           fprintf (dump_file, " with ");
     495            0 :           print_generic_expr (dump_file, val);
     496            0 :           fprintf (dump_file, "\n");
     497              :           
     498              :         }
     499       411973 :       replace_uses_by (name, val);
     500       411973 :       bitmap_set_bit (dead_stmts, SSA_NAME_VERSION (name));
     501       411973 :       didsomething = true;
     502              :     }
     503              : 
     504       407122 :   if (dump_file)
     505           56 :     fprintf (dump_file, "Replacing SCC of size %d\n", scc.length ());
     506       407122 :   return didsomething;
     507              : }
     508              : 
     509              : /* Part of 'scc_copy_prop::propagate ()'.  */
     510              : 
     511              : void
     512     19242025 : scc_copy_prop::visit_op (tree op, hash_set<tree> &outer_ops,
     513              :                          hash_set<gimple *> &scc_set, bool &is_inner,
     514              :                          tree &last_outer_op)
     515              : {
     516     19242025 :   bool op_in_scc = false;
     517              : 
     518     19242025 :   if (TREE_CODE (op) == SSA_NAME)
     519              :     {
     520     17261806 :       gimple *op_stmt = SSA_NAME_DEF_STMT (op);
     521     17261806 :       if (scc_set.contains (op_stmt))
     522      1133246 :         op_in_scc = true;
     523              :     }
     524              : 
     525     17261806 :   if (!op_in_scc)
     526              :     {
     527     18108779 :       outer_ops.add (op);
     528     18108779 :       last_outer_op = op;
     529     18108779 :       is_inner = false;
     530              :     }
     531     19242025 : }
     532              : 
     533              : /* Main function of this pass.  Find and propagate all three types of copy
     534              :    statements (see pass description above).
     535              : 
     536              :    This is an implementation of an algorithm from the paper Simple and
     537              :    Efficient Construction of Static Single Assignmemnt Form[1].  It is based
     538              :    on strongly-connected components (SCCs) in dataflow graph.  The original
     539              :    algorithm only considers PHI statements.  We extend it to also consider
     540              :    assignment statements of type _2 = _1;.
     541              : 
     542              :    The algorithm is based on this definition of a set of redundant PHIs[1]:
     543              : 
     544              :      A non-empty set P of PHI functions is redundant iff the PHI functions just
     545              :      reference each other or one other value
     546              : 
     547              :    It uses this lemma[1]:
     548              : 
     549              :      Let P be a redundant set of PHI functions.  Then there is a
     550              :      strongly-connected component S subset of P that is also redundant.
     551              : 
     552              :    The algorithm works in this way:
     553              : 
     554              :      1 Find SCCs
     555              :      2 For each SCC S in topological order:
     556              :      3   Construct set 'inner' of statements that only have other statements
     557              :          from S on their right hand side
     558              :      4   Construct set 'outer' of values that originate outside S and appear on
     559              :          right hand side of some statement from S
     560              :      5   If |outer| = 1, outer only contains a value v.  Statements in S only
     561              :          refer to each other or to v -- they are redundant.  Propagate v.
     562              :          Else, recurse on statements in inner.
     563              : 
     564              :    The implementation is non-recursive.
     565              : 
     566              :    References:
     567              : 
     568              :      [1] Simple and Efficient Construction of Static Single Assignmemnt Form,
     569              :      Braun, Buchwald, Hack, Leissa, Mallon, Zwinkau, 2013, LNCS vol. 7791,
     570              :      Section 3.2.  */
     571              : 
     572              : bool
     573      3453819 : scc_copy_prop::propagate ()
     574              : {
     575      3453819 :   bool didsomething = false;
     576      3453819 :   auto_vec<gimple *> useful_stmts = get_all_stmt_may_generate_copy ();
     577      3453819 :   scc_discovery discovery;
     578              : 
     579      3453819 :   auto_vec<vec<gimple *>> worklist = discovery.compute_sccs (useful_stmts);
     580              : 
     581     14159821 :   while (!worklist.is_empty ())
     582              :     {
     583      7252183 :       vec<gimple *> scc = worklist.pop ();
     584              : 
     585              :       /* When we do 'replace_scc_by_value' it may happen that some EH edges
     586              :          get removed.  That means parts of CFG get removed.  Those may
     587              :          contain copy statements.  For that reason we prune SCCs here.  */
     588      7252183 :       unsigned i;
     589     14970143 :       for (i = 0; i < scc.length ();)
     590      7717960 :         if (gimple_bb (scc[i]) == NULL)
     591            0 :           scc.unordered_remove (i);
     592              :         else
     593      7717960 :           i++;
     594      7252183 :       if (scc.is_empty ())
     595              :         {
     596            0 :           scc.release ();
     597            0 :           continue;
     598              :         }
     599              : 
     600      7252183 :       auto_vec<gimple *> inner;
     601      7252183 :       hash_set<tree> outer_ops;
     602      7252183 :       tree last_outer_op = NULL_TREE;
     603              : 
     604              :       /* Prepare hash set of PHIs in scc to query later.  */
     605      7252183 :       hash_set<gimple *> scc_set;
     606     14970143 :       for (gimple *stmt : scc)
     607      7717960 :         scc_set.add (stmt);
     608              : 
     609     14970143 :       for (gimple *stmt : scc)
     610              :         {
     611      7717960 :           bool is_inner = true;
     612              : 
     613      7717960 :           gphi *phi;
     614      7717960 :           tree op;
     615              : 
     616      7717960 :           switch (gimple_code (stmt))
     617              :             {
     618      7696372 :               case GIMPLE_PHI:
     619      7696372 :                 phi = as_a <gphi *> (stmt);
     620      7696372 :                 unsigned j;
     621     34613181 :                 for (j = 0; j < gimple_phi_num_args (phi); j++)
     622              :                   {
     623     19220437 :                     op = gimple_phi_arg_def (phi, j);
     624     19220437 :                     visit_op (op, outer_ops, scc_set, is_inner, last_outer_op);
     625              :                   }
     626              :                 break;
     627        21588 :               case GIMPLE_ASSIGN:
     628        21588 :                 op = gimple_assign_rhs1 (stmt);
     629        21588 :                 visit_op (op, outer_ops, scc_set, is_inner, last_outer_op);
     630        21588 :                 break;
     631            0 :               default:
     632            0 :                 gcc_unreachable ();
     633              :             }
     634              : 
     635      7717960 :           if (is_inner)
     636       146214 :             inner.safe_push (stmt);
     637              :         }
     638              : 
     639      7252183 :       if (outer_ops.elements () == 1)
     640              :         {
     641              :           /* The only operand in outer_ops.  */
     642       407122 :           tree outer_op = last_outer_op;
     643       407122 :           didsomething |= replace_scc_by_value (scc, outer_op);
     644              :         }
     645      6845061 :       else if (outer_ops.elements () > 1)
     646              :         {
     647              :           /* Add inner sccs to worklist.  */
     648      6845061 :           auto_vec<vec<gimple *>> inner_sccs
     649      6845061 :             = discovery.compute_sccs (inner);
     650      7105400 :           for (vec<gimple *> inner_scc : inner_sccs)
     651       114627 :             worklist.safe_push (inner_scc);
     652      6845061 :         }
     653              :       else
     654            0 :         gcc_unreachable ();
     655              : 
     656      7252183 :       scc.release ();
     657      7252183 :     }
     658      3453819 :   return didsomething;
     659      3453819 : }
     660              : 
     661      3453819 : scc_copy_prop::scc_copy_prop ()
     662              : {
     663              :   /* For propagated statements.  */
     664      3453819 :   dead_stmts = BITMAP_ALLOC (NULL);
     665      3453819 : }
     666              : 
     667      3453819 : scc_copy_prop::~scc_copy_prop ()
     668              : {
     669              :   /* Remove all propagated statements.  */
     670      3453819 :   simple_dce_from_worklist (dead_stmts);
     671      3453819 :   BITMAP_FREE (dead_stmts);
     672              : 
     673              :   /* Propagating a constant may create dead eh edges.  */
     674      3453819 :   basic_block bb;
     675     24394623 :   FOR_EACH_BB_FN (bb, cfun)
     676     20940804 :     gimple_purge_dead_eh_edges (bb);
     677      3453819 : }
     678              : 
     679              : namespace {
     680              : 
     681              : const pass_data pass_data_sccopy =
     682              : {
     683              :   GIMPLE_PASS, /* type */
     684              :   "sccopy", /* name */
     685              :   OPTGROUP_NONE, /* optinfo_flags */
     686              :   TV_NONE, /* tv_id */
     687              :   ( PROP_cfg | PROP_ssa ), /* properties_required */
     688              :   0, /* properties_provided */
     689              :   0, /* properties_destroyed */
     690              :   0, /* todo_flags_start */
     691              :   0, /* todo_flags_finish */
     692              : };
     693              : 
     694              : class pass_sccopy : public gimple_opt_pass
     695              : {
     696              : public:
     697       571444 :   pass_sccopy (gcc::context *ctxt)
     698      1142888 :     : gimple_opt_pass (pass_data_sccopy, ctxt)
     699              :   {}
     700              : 
     701              :   /* opt_pass methods: */
     702      3453912 :   virtual bool gate (function *) final override { return true; }
     703              :   virtual unsigned int execute (function *) final override;
     704       285722 :   opt_pass * clone () final override { return new pass_sccopy (m_ctxt); }
     705              : }; // class pass_sccopy
     706              : 
     707              : unsigned
     708      3453819 : pass_sccopy::execute (function *)
     709              : {
     710      3453819 :   scc_copy_prop sccopy;
     711      3453819 :   return sccopy.propagate () ?  TODO_cleanup_cfg : 0;
     712      3453819 : }
     713              : 
     714              : } // anon namespace
     715              : 
     716              : gimple_opt_pass *
     717       285722 : make_pass_sccopy (gcc::context *ctxt)
     718              : {
     719       285722 :   return new pass_sccopy (ctxt);
     720              : }
        

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.