LCOV - code coverage report
Current view: top level - gcc - gimple-ssa-sccopy.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 93.8 % 242 227
Test Date: 2025-06-21 16:26:05 Functions: 100.0 % 15 15
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Strongly-connected copy propagation pass for the GNU compiler.
       2                 :             :    Copyright (C) 2023-2025 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 bellow.
      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                 :     3462825 : scc_discovery::scc_discovery ()
     148                 :             : {
     149                 :             :   /* Create vertex struct for each SSA name.  */
     150                 :     6925650 :   vertices = XNEWVEC (struct vertex, num_ssa_names);
     151                 :     3462825 :   unsigned i = 0;
     152                 :   130769351 :   for (i = 0; i < num_ssa_names; i++)
     153                 :   127306526 :     vertices[i].active = false;
     154                 :     3462825 : }
     155                 :             : 
     156                 :     3462825 : scc_discovery::~scc_discovery ()
     157                 :             : {
     158                 :     3462825 :   XDELETEVEC (vertices);
     159                 :     3462825 : }
     160                 :             : 
     161                 :             : /* Part of 'scc_discovery::compute_sccs ()'.  */
     162                 :             : 
     163                 :             : void
     164                 :    45266030 : scc_discovery::visit_neighbor (tree neigh_tree, unsigned parent_version)
     165                 :             : {
     166                 :    45266030 :   if (TREE_CODE (neigh_tree) != SSA_NAME)
     167                 :    34642647 :     return; /* Skip any neighbor that isn't an SSA name.  */
     168                 :    40854048 :   unsigned neigh_version = SSA_NAME_VERSION (neigh_tree);
     169                 :             : 
     170                 :             :   /* Skip neighbors outside the subgraph that Tarjan currently works
     171                 :             :      with.  */
     172                 :    40854048 :   if (!vertices[neigh_version].active)
     173                 :             :     return;
     174                 :             : 
     175                 :    10623383 :   vstate neigh_state = vertices[neigh_version].state;
     176                 :    10623383 :   vstate parent_state = vertices[parent_version].state;
     177                 :    10623383 :   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                 :     3981492 :       switch (neigh_state)
     182                 :             :         {
     183                 :     2787654 :         case unvisited:
     184                 :     2787654 :           worklist.safe_push (neigh_version);
     185                 :     2787654 :           break;
     186                 :      564231 :         case vopen:
     187                 :      564231 :         case closed:
     188                 :      564231 :           vertices[parent_version].lowlink
     189                 :      564231 :             = std::min (vertices[parent_version].lowlink,
     190                 :             :                         vertices[neigh_version].index);
     191                 :      564231 :           break;
     192                 :             :         case in_scc:
     193                 :             :           /* Ignore these edges.  */
     194                 :             :           break;
     195                 :             :         }
     196                 :             :     }
     197                 :     6641891 :   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                 :     4147093 :       if (neigh_state == closed)
     202                 :             :         {
     203                 :      739357 :           vertices[parent_version].lowlink
     204                 :      739357 :             = 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                 :    10623602 : scc_discovery::compute_sccs (vec<gimple *> &stmts)
     218                 :             : {
     219                 :    10623602 :   auto_vec<vec<gimple *>> sccs;
     220                 :             : 
     221                 :    21016296 :   for (gimple *stmt : stmts)
     222                 :             :     {
     223                 :     8068794 :       unsigned i;
     224                 :     8068794 :       switch (gimple_code (stmt))
     225                 :             :         {
     226                 :       22350 :           case GIMPLE_ASSIGN:
     227                 :       22350 :             i = SSA_NAME_VERSION (gimple_assign_lhs (stmt));
     228                 :       22350 :             break;
     229                 :     8046444 :           case GIMPLE_PHI:
     230                 :     8046444 :             i = SSA_NAME_VERSION (gimple_phi_result (stmt));
     231                 :     8046444 :             break;
     232                 :           0 :           default:
     233                 :           0 :             gcc_unreachable ();
     234                 :             :         }
     235                 :             : 
     236                 :     8068794 :       vertices[i].index = 0;
     237                 :     8068794 :       vertices[i].lowlink = 0;
     238                 :     8068794 :       vertices[i].state = unvisited;
     239                 :     8068794 :       vertices[i].active = true; /* Mark the subgraph we'll be working on so
     240                 :             :                                     that we don't leave it.  */
     241                 :             : 
     242                 :     8068794 :       worklist.safe_push (i);
     243                 :             :     }
     244                 :             : 
     245                 :             :   /* Worklist loop.  */
     246                 :             :   unsigned curr_index = 0;
     247                 :    29548844 :   while (!worklist.is_empty ())
     248                 :             :     {
     249                 :    18925242 :       unsigned i = worklist.pop ();
     250                 :    18925242 :       gimple *stmt = SSA_NAME_DEF_STMT (ssa_name (i));
     251                 :    18925242 :       vstate state = vertices[i].state;
     252                 :             : 
     253                 :    18925242 :       if (state == unvisited)
     254                 :             :         {
     255                 :     8068794 :           vertices[i].state = vopen;
     256                 :             : 
     257                 :             :           /* Assign index to this vertex.  */
     258                 :     8068794 :           vertices[i].index = curr_index;
     259                 :     8068794 :           vertices[i].lowlink = curr_index;
     260                 :     8068794 :           curr_index++;
     261                 :             : 
     262                 :             :           /* Put vertex on stack and also on worklist to be closed later.  */
     263                 :     8068794 :           stack.safe_push (i);
     264                 :     8068794 :           worklist.safe_push (i);
     265                 :             :         }
     266                 :    10856448 :       else if (state == vopen)
     267                 :     8068794 :         vertices[i].state = closed;
     268                 :             : 
     269                 :             :       /* Visit neighbors of this vertex.  */
     270                 :    18925242 :       tree op;
     271                 :    18925242 :       gphi *phi;
     272                 :    18925242 :       switch (gimple_code (stmt))
     273                 :             :         {
     274                 :    18879531 :           case GIMPLE_PHI:
     275                 :    18879531 :             phi = as_a <gphi *> (stmt);
     276                 :    18879531 :             unsigned j;
     277                 :    82979381 :             for (j = 0; j < gimple_phi_num_args (phi); j++)
     278                 :             :               {
     279                 :    45220319 :                 op = gimple_phi_arg_def (phi, j);
     280                 :    45220319 :                 visit_neighbor (op, i);
     281                 :             :               }
     282                 :             :             break;
     283                 :       45711 :           case GIMPLE_ASSIGN:
     284                 :       45711 :             op = gimple_assign_rhs1 (stmt);
     285                 :       45711 :             visit_neighbor (op, i);
     286                 :       45711 :             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                 :    18925242 :       if (state == vopen && vertices[i].lowlink == vertices[i].index)
     293                 :             :         {
     294                 :     7591942 :           vec<gimple *> scc = vNULL;
     295                 :             : 
     296                 :     8068794 :           unsigned j;
     297                 :     8068794 :           do
     298                 :             :             {
     299                 :     8068794 :               j = stack.pop ();
     300                 :     8068794 :               scc.safe_push (SSA_NAME_DEF_STMT (ssa_name (j)));
     301                 :     8068794 :               vertices[j].state = in_scc;
     302                 :             :             }
     303                 :     8068794 :           while (j != i);
     304                 :             : 
     305                 :     7591942 :           sccs.safe_push (scc);
     306                 :             :         }
     307                 :             :     }
     308                 :             : 
     309                 :    10623602 :   if (!stack.is_empty ())
     310                 :           0 :     gcc_unreachable ();
     311                 :             : 
     312                 :             :   /* Clear 'active' flags.  */
     313                 :    21016296 :   for (gimple *stmt : stmts)
     314                 :             :     {
     315                 :     8068794 :       unsigned i;
     316                 :     8068794 :       switch (gimple_code (stmt))
     317                 :             :         {
     318                 :       22350 :           case GIMPLE_ASSIGN:
     319                 :       22350 :             i = SSA_NAME_VERSION (gimple_assign_lhs (stmt));
     320                 :       22350 :             break;
     321                 :     8046444 :           case GIMPLE_PHI:
     322                 :     8046444 :             i = SSA_NAME_VERSION (gimple_phi_result (stmt));
     323                 :     8046444 :             break;
     324                 :           0 :           default:
     325                 :           0 :             gcc_unreachable ();
     326                 :             :         }
     327                 :             : 
     328                 :     8068794 :       vertices[i].active = false;
     329                 :             :     }
     330                 :             : 
     331                 :    10623602 :   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                 :   159193788 : stmt_may_generate_copy (gimple *stmt)
     347                 :             : {
     348                 :             :   /* A PHI may generate a copy.  */
     349                 :   159193788 :   if (gimple_code (stmt) == GIMPLE_PHI)
     350                 :             :     {
     351                 :     8243012 :       gphi *phi = as_a <gphi *> (stmt);
     352                 :             : 
     353                 :             :       /* No OCCURS_IN_ABNORMAL_PHI SSA names in lhs nor rhs.  */
     354                 :     8243012 :       if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (phi)))
     355                 :             :         return false;
     356                 :             : 
     357                 :             :       unsigned i;
     358                 :    28275236 :       for (i = 0; i < gimple_phi_num_args (phi); i++)
     359                 :             :         {
     360                 :    20044078 :           tree op = gimple_phi_arg_def (phi, i);
     361                 :    20044078 :           if (TREE_CODE (op) == SSA_NAME
     362                 :    20044078 :               && 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                 :    27554977 :       for (i = 0; i < gimple_phi_num_args (phi); i++)
     370                 :             :         {
     371                 :    19663763 :           tree op = gimple_phi_arg_def (phi, i);
     372                 :    19663763 :           if (TREE_CODE (op) != SSA_NAME)
     373                 :             :             {
     374                 :     2630026 :               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                 :   150950776 :   if (!gimple_assign_single_p (stmt))
     386                 :             :     return false;
     387                 :             : 
     388                 :    29824635 :   tree lhs = gimple_assign_lhs (stmt);
     389                 :    29824635 :   tree rhs = gimple_assign_rhs1 (stmt);
     390                 :             : 
     391                 :    29824635 :   if (TREE_CODE (lhs) != SSA_NAME)
     392                 :             :     return false;
     393                 :             : 
     394                 :             :   /* lhs shouldn't flow through any abnormal edges.  */
     395                 :    13399994 :   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
     396                 :             :     return false;
     397                 :             : 
     398                 :    13399336 :   if (is_gimple_min_invariant (rhs))
     399                 :             :     return true;  /* A statement of type _2 = 5;.  */
     400                 :             : 
     401                 :    13393749 :   if (TREE_CODE (rhs) != SSA_NAME)
     402                 :             :     return false;
     403                 :             : 
     404                 :             :   /* rhs shouldn't flow through any abnormal edges.  */
     405                 :       28665 :   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                 :       52952 :   if (POINTER_TYPE_P (TREE_TYPE (lhs))
     416                 :        2304 :       && POINTER_TYPE_P (TREE_TYPE (rhs))
     417                 :       29927 :       && SSA_NAME_PTR_INFO (lhs) != SSA_NAME_PTR_INFO (rhs))
     418                 :             :     return false;
     419                 :       50818 :   if (!POINTER_TYPE_P (TREE_TYPE (lhs))
     420                 :       25319 :       && !POINTER_TYPE_P (TREE_TYPE (rhs))
     421                 :       50818 :       && 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                 :     3462825 : get_all_stmt_may_generate_copy (void)
     432                 :             : {
     433                 :     3462825 :   auto_vec<gimple *> result;
     434                 :             : 
     435                 :     3462825 :   basic_block bb;
     436                 :    24782600 :   FOR_EACH_BB_FN (bb, cfun)
     437                 :             :     {
     438                 :    21319775 :       gimple_stmt_iterator gsi;
     439                 :   193590326 :       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     440                 :             :         {
     441                 :   150950776 :           gimple *s = gsi_stmt (gsi);
     442                 :   150950776 :           if (stmt_may_generate_copy (s))
     443                 :       22350 :             result.safe_push (s);
     444                 :             :         }
     445                 :             : 
     446                 :    21319775 :       gphi_iterator pi;
     447                 :    29562787 :       for (pi = gsi_start_phis (bb); !gsi_end_p (pi); gsi_next (&pi))
     448                 :             :         {
     449                 :     8243012 :           gimple *s = pi.phi ();
     450                 :     8243012 :           if (stmt_may_generate_copy (s))
     451                 :     7891214 :             result.safe_push (s);
     452                 :             :         }
     453                 :             :     }
     454                 :             : 
     455                 :     3462825 :   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                 :      431164 : scc_copy_prop::replace_scc_by_value (vec<gimple *> scc, tree val)
     485                 :             : {
     486                 :      431164 :   bool didsomething = false;
     487                 :     1729795 :   for (gimple *stmt : scc)
     488                 :             :     {
     489                 :      436303 :       tree name = gimple_get_lhs (stmt);
     490                 :      436303 :       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                 :      436303 :       replace_uses_by (name, val);
     500                 :      436303 :       bitmap_set_bit (dead_stmts, SSA_NAME_VERSION (name));
     501                 :      436303 :       didsomething = true;
     502                 :             :     }
     503                 :             : 
     504                 :      431164 :   if (dump_file)
     505                 :          56 :     fprintf (dump_file, "Replacing SCC of size %d\n", scc.length ());
     506                 :      431164 :   return didsomething;
     507                 :             : }
     508                 :             : 
     509                 :             : /* Part of 'scc_copy_prop::propagate ()'.  */
     510                 :             : 
     511                 :             : void
     512                 :    19270603 : 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                 :    19270603 :   bool op_in_scc = false;
     517                 :             : 
     518                 :    19270603 :   if (TREE_CODE (op) == SSA_NAME)
     519                 :             :     {
     520                 :    17332753 :       gimple *op_stmt = SSA_NAME_DEF_STMT (op);
     521                 :    17332753 :       if (scc_set.contains (op_stmt))
     522                 :     1144567 :         op_in_scc = true;
     523                 :             :     }
     524                 :             : 
     525                 :    17332753 :   if (!op_in_scc)
     526                 :             :     {
     527                 :    18126036 :       outer_ops.add (op);
     528                 :    18126036 :       last_outer_op = op;
     529                 :    18126036 :       is_inner = false;
     530                 :             :     }
     531                 :    19270603 : }
     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                 :     3462825 : scc_copy_prop::propagate ()
     574                 :             : {
     575                 :     3462825 :   bool didsomething = false;
     576                 :     3462825 :   auto_vec<gimple *> useful_stmts = get_all_stmt_may_generate_copy ();
     577                 :     3462825 :   scc_discovery discovery;
     578                 :             : 
     579                 :     3462825 :   auto_vec<vec<gimple *>> worklist = discovery.compute_sccs (useful_stmts);
     580                 :             : 
     581                 :    14517592 :   while (!worklist.is_empty ())
     582                 :             :     {
     583                 :     7591942 :       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                 :     7591942 :       unsigned i;
     589                 :    15660736 :       for (i = 0; i < scc.length ();)
     590                 :     8068794 :         if (gimple_bb (scc[i]) == NULL)
     591                 :           1 :           scc.unordered_remove (i);
     592                 :             :         else
     593                 :     8068793 :           i++;
     594                 :     7591942 :       if (scc.is_empty ())
     595                 :             :         {
     596                 :           1 :           scc.release ();
     597                 :           1 :           continue;
     598                 :             :         }
     599                 :             : 
     600                 :     7591941 :       auto_vec<gimple *> inner;
     601                 :     7591941 :       hash_set<tree> outer_ops;
     602                 :     7591941 :       tree last_outer_op = NULL_TREE;
     603                 :             : 
     604                 :             :       /* Prepare hash set of PHIs in scc to query later.  */
     605                 :     7591941 :       hash_set<gimple *> scc_set;
     606                 :    15660734 :       for (gimple *stmt : scc)
     607                 :     8068793 :         scc_set.add (stmt);
     608                 :             : 
     609                 :    15660734 :       for (gimple *stmt : scc)
     610                 :             :         {
     611                 :     8068793 :           bool is_inner = true;
     612                 :             : 
     613                 :     8068793 :           gphi *phi;
     614                 :     8068793 :           tree op;
     615                 :             : 
     616                 :     8068793 :           switch (gimple_code (stmt))
     617                 :             :             {
     618                 :     8046443 :               case GIMPLE_PHI:
     619                 :     8046443 :                 phi = as_a <gphi *> (stmt);
     620                 :     8046443 :                 unsigned j;
     621                 :    35341139 :                 for (j = 0; j < gimple_phi_num_args (phi); j++)
     622                 :             :                   {
     623                 :    19248253 :                     op = gimple_phi_arg_def (phi, j);
     624                 :    19248253 :                     visit_op (op, outer_ops, scc_set, is_inner, last_outer_op);
     625                 :             :                   }
     626                 :             :                 break;
     627                 :       22350 :               case GIMPLE_ASSIGN:
     628                 :       22350 :                 op = gimple_assign_rhs1 (stmt);
     629                 :       22350 :                 visit_op (op, outer_ops, scc_set, is_inner, last_outer_op);
     630                 :       22350 :                 break;
     631                 :           0 :               default:
     632                 :           0 :                 gcc_unreachable ();
     633                 :             :             }
     634                 :             : 
     635                 :     8068793 :           if (is_inner)
     636                 :      159754 :             inner.safe_push (stmt);
     637                 :             :         }
     638                 :             : 
     639                 :     7591941 :       if (outer_ops.elements () == 1)
     640                 :             :         {
     641                 :             :           /* The only operand in outer_ops.  */
     642                 :      431164 :           tree outer_op = last_outer_op;
     643                 :      431164 :           didsomething |= replace_scc_by_value (scc, outer_op);
     644                 :             :         }
     645                 :     7160777 :       else if (outer_ops.elements () > 1)
     646                 :             :         {
     647                 :             :           /* Add inner sccs to worklist.  */
     648                 :     7160777 :           auto_vec<vec<gimple *>> inner_sccs
     649                 :     7160777 :             = discovery.compute_sccs (inner);
     650                 :     7445104 :           for (vec<gimple *> inner_scc : inner_sccs)
     651                 :      126281 :             worklist.safe_push (inner_scc);
     652                 :     7160777 :         }
     653                 :             :       else
     654                 :           0 :         gcc_unreachable ();
     655                 :             : 
     656                 :     7591941 :       scc.release ();
     657                 :     7591941 :     }
     658                 :     3462825 :   return didsomething;
     659                 :     3462825 : }
     660                 :             : 
     661                 :     3462825 : scc_copy_prop::scc_copy_prop ()
     662                 :             : {
     663                 :             :   /* For propagated statements.  */
     664                 :     3462825 :   dead_stmts = BITMAP_ALLOC (NULL);
     665                 :     3462825 : }
     666                 :             : 
     667                 :     3462825 : scc_copy_prop::~scc_copy_prop ()
     668                 :             : {
     669                 :             :   /* Remove all propagated statements.  */
     670                 :     3462825 :   simple_dce_from_worklist (dead_stmts);
     671                 :     3462825 :   BITMAP_FREE (dead_stmts);
     672                 :             : 
     673                 :             :   /* Propagating a constant may create dead eh edges.  */
     674                 :     3462825 :   basic_block bb;
     675                 :    24782596 :   FOR_EACH_BB_FN (bb, cfun)
     676                 :    21319771 :     gimple_purge_dead_eh_edges (bb);
     677                 :     3462825 : }
     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                 :      570162 :   pass_sccopy (gcc::context *ctxt)
     698                 :     1140324 :     : gimple_opt_pass (pass_data_sccopy, ctxt)
     699                 :             :   {}
     700                 :             : 
     701                 :             :   /* opt_pass methods: */
     702                 :     3462900 :   virtual bool gate (function *) { return true; }
     703                 :             :   virtual unsigned int execute (function *);
     704                 :      285081 :   opt_pass * clone () final override { return new pass_sccopy (m_ctxt); }
     705                 :             : }; // class pass_sccopy
     706                 :             : 
     707                 :             : unsigned
     708                 :     3462825 : pass_sccopy::execute (function *)
     709                 :             : {
     710                 :     3462825 :   scc_copy_prop sccopy;
     711                 :     3462825 :   return sccopy.propagate () ?  TODO_cleanup_cfg : 0;
     712                 :     3462825 : }
     713                 :             : 
     714                 :             : } // anon namespace
     715                 :             : 
     716                 :             : gimple_opt_pass *
     717                 :      285081 : make_pass_sccopy (gcc::context *ctxt)
     718                 :             : {
     719                 :      285081 :   return new pass_sccopy (ctxt);
     720                 :             : }
        

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