LCOV - code coverage report
Current view: top level - gcc - gimple-ssa-sccopy.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 93.7 % 239 224
Test Date: 2025-03-22 13:13:03 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                 :     3315974 : scc_discovery::scc_discovery ()
     148                 :             : {
     149                 :             :   /* Create vertex struct for each SSA name.  */
     150                 :     6631948 :   vertices = XNEWVEC (struct vertex, num_ssa_names);
     151                 :     3315974 :   unsigned i = 0;
     152                 :   124287064 :   for (i = 0; i < num_ssa_names; i++)
     153                 :   120971090 :     vertices[i].active = false;
     154                 :     3315974 : }
     155                 :             : 
     156                 :     3315974 : scc_discovery::~scc_discovery ()
     157                 :             : {
     158                 :     3315974 :   XDELETEVEC (vertices);
     159                 :     3315974 : }
     160                 :             : 
     161                 :             : /* Part of 'scc_discovery::compute_sccs ()'.  */
     162                 :             : 
     163                 :             : void
     164                 :    42722989 : scc_discovery::visit_neighbor (tree neigh_tree, unsigned parent_version)
     165                 :             : {
     166                 :    42722989 :   if (TREE_CODE (neigh_tree) != SSA_NAME)
     167                 :    32733972 :     return; /* Skip any neighbor that isn't an SSA name.  */
     168                 :    38520758 :   unsigned neigh_version = SSA_NAME_VERSION (neigh_tree);
     169                 :             : 
     170                 :             :   /* Skip neighbors outside the subgraph that Tarjan currently works
     171                 :             :      with.  */
     172                 :    38520758 :   if (!vertices[neigh_version].active)
     173                 :             :     return;
     174                 :             : 
     175                 :     9989017 :   vstate neigh_state = vertices[neigh_version].state;
     176                 :     9989017 :   vstate parent_state = vertices[parent_version].state;
     177                 :     9989017 :   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                 :     3739152 :       switch (neigh_state)
     182                 :             :         {
     183                 :     2618953 :         case unvisited:
     184                 :     2618953 :           worklist.safe_push (neigh_version);
     185                 :     2618953 :           break;
     186                 :      548086 :         case vopen:
     187                 :      548086 :         case closed:
     188                 :      548086 :           vertices[parent_version].lowlink
     189                 :      548086 :             = std::min (vertices[parent_version].lowlink,
     190                 :             :                         vertices[neigh_version].index);
     191                 :      548086 :           break;
     192                 :             :         case in_scc:
     193                 :             :           /* Ignore these edges.  */
     194                 :             :           break;
     195                 :             :         }
     196                 :             :     }
     197                 :     6249865 :   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                 :     3906674 :       if (neigh_state == closed)
     202                 :             :         {
     203                 :      722959 :           vertices[parent_version].lowlink
     204                 :      722959 :             = 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                 :    10059199 : scc_discovery::compute_sccs (vec<gimple *> &stmts)
     218                 :             : {
     219                 :    10059199 :   auto_vec<vec<gimple *>> sccs;
     220                 :             : 
     221                 :    19907931 :   for (gimple *stmt : stmts)
     222                 :             :     {
     223                 :     7618346 :       unsigned i;
     224                 :     7618346 :       switch (gimple_code (stmt))
     225                 :             :         {
     226                 :       22625 :           case GIMPLE_ASSIGN:
     227                 :       22625 :             i = SSA_NAME_VERSION (gimple_assign_lhs (stmt));
     228                 :       22625 :             break;
     229                 :     7595721 :           case GIMPLE_PHI:
     230                 :     7595721 :             i = SSA_NAME_VERSION (gimple_phi_result (stmt));
     231                 :     7595721 :             break;
     232                 :           0 :           default:
     233                 :           0 :             gcc_unreachable ();
     234                 :             :         }
     235                 :             : 
     236                 :     7618346 :       vertices[i].index = 0;
     237                 :     7618346 :       vertices[i].lowlink = 0;
     238                 :     7618346 :       vertices[i].state = unvisited;
     239                 :     7618346 :       vertices[i].active = true; /* Mark the subgraph we'll be working on so
     240                 :             :                                     that we don't leave it.  */
     241                 :             : 
     242                 :     7618346 :       worklist.safe_push (i);
     243                 :             :     }
     244                 :             : 
     245                 :             :   /* Worklist loop.  */
     246                 :             :   unsigned curr_index = 0;
     247                 :    27914844 :   while (!worklist.is_empty ())
     248                 :             :     {
     249                 :    17855645 :       unsigned i = worklist.pop ();
     250                 :    17855645 :       gimple *stmt = SSA_NAME_DEF_STMT (ssa_name (i));
     251                 :    17855645 :       vstate state = vertices[i].state;
     252                 :             : 
     253                 :    17855645 :       if (state == unvisited)
     254                 :             :         {
     255                 :     7618346 :           vertices[i].state = vopen;
     256                 :             : 
     257                 :             :           /* Assign index to this vertex.  */
     258                 :     7618346 :           vertices[i].index = curr_index;
     259                 :     7618346 :           vertices[i].lowlink = curr_index;
     260                 :     7618346 :           curr_index++;
     261                 :             : 
     262                 :             :           /* Put vertex on stack and also on worklist to be closed later.  */
     263                 :     7618346 :           stack.safe_push (i);
     264                 :     7618346 :           worklist.safe_push (i);
     265                 :             :         }
     266                 :    10237299 :       else if (state == vopen)
     267                 :     7618346 :         vertices[i].state = closed;
     268                 :             : 
     269                 :             :       /* Visit neighbors of this vertex.  */
     270                 :    17855645 :       tree op;
     271                 :    17855645 :       gphi *phi;
     272                 :    17855645 :       switch (gimple_code (stmt))
     273                 :             :         {
     274                 :    17809435 :           case GIMPLE_PHI:
     275                 :    17809435 :             phi = as_a <gphi *> (stmt);
     276                 :    17809435 :             unsigned j;
     277                 :    78295649 :             for (j = 0; j < gimple_phi_num_args (phi); j++)
     278                 :             :               {
     279                 :    42676779 :                 op = gimple_phi_arg_def (phi, j);
     280                 :    42676779 :                 visit_neighbor (op, i);
     281                 :             :               }
     282                 :             :             break;
     283                 :       46210 :           case GIMPLE_ASSIGN:
     284                 :       46210 :             op = gimple_assign_rhs1 (stmt);
     285                 :       46210 :             visit_neighbor (op, i);
     286                 :       46210 :             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                 :    17855645 :       if (state == vopen && vertices[i].lowlink == vertices[i].index)
     293                 :             :         {
     294                 :     7158706 :           vec<gimple *> scc = vNULL;
     295                 :             : 
     296                 :     7618346 :           unsigned j;
     297                 :     7618346 :           do
     298                 :             :             {
     299                 :     7618346 :               j = stack.pop ();
     300                 :     7618346 :               scc.safe_push (SSA_NAME_DEF_STMT (ssa_name (j)));
     301                 :     7618346 :               vertices[j].state = in_scc;
     302                 :             :             }
     303                 :     7618346 :           while (j != i);
     304                 :             : 
     305                 :     7158706 :           sccs.safe_push (scc);
     306                 :             :         }
     307                 :             :     }
     308                 :             : 
     309                 :    10059199 :   if (!stack.is_empty ())
     310                 :           0 :     gcc_unreachable ();
     311                 :             : 
     312                 :             :   /* Clear 'active' flags.  */
     313                 :    19907931 :   for (gimple *stmt : stmts)
     314                 :             :     {
     315                 :     7618346 :       unsigned i;
     316                 :     7618346 :       switch (gimple_code (stmt))
     317                 :             :         {
     318                 :       22625 :           case GIMPLE_ASSIGN:
     319                 :       22625 :             i = SSA_NAME_VERSION (gimple_assign_lhs (stmt));
     320                 :       22625 :             break;
     321                 :     7595721 :           case GIMPLE_PHI:
     322                 :     7595721 :             i = SSA_NAME_VERSION (gimple_phi_result (stmt));
     323                 :     7595721 :             break;
     324                 :           0 :           default:
     325                 :           0 :             gcc_unreachable ();
     326                 :             :         }
     327                 :             : 
     328                 :     7618346 :       vertices[i].active = false;
     329                 :             :     }
     330                 :             : 
     331                 :    10059199 :   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                 :   145749147 : stmt_may_generate_copy (gimple *stmt)
     347                 :             : {
     348                 :             :   /* A PHI may generate a copy.  */
     349                 :   145749147 :   if (gimple_code (stmt) == GIMPLE_PHI)
     350                 :             :     {
     351                 :     7764947 :       gphi *phi = as_a <gphi *> (stmt);
     352                 :             : 
     353                 :             :       /* No OCCURS_IN_ABNORMAL_PHI SSA names in lhs nor rhs.  */
     354                 :     7764947 :       if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (phi)))
     355                 :             :         return false;
     356                 :             : 
     357                 :             :       unsigned i;
     358                 :    26655133 :       for (i = 0; i < gimple_phi_num_args (phi); i++)
     359                 :             :         {
     360                 :    18901949 :           tree op = gimple_phi_arg_def (phi, i);
     361                 :    18901949 :           if (TREE_CODE (op) == SSA_NAME
     362                 :    18901949 :               && 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                 :    25980533 :       for (i = 0; i < gimple_phi_num_args (phi); i++)
     370                 :             :         {
     371                 :    18534490 :           tree op = gimple_phi_arg_def (phi, i);
     372                 :    18534490 :           if (TREE_CODE (op) != SSA_NAME)
     373                 :             :             {
     374                 :     2475642 :               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                 :   137984200 :   if (!gimple_assign_single_p (stmt))
     386                 :             :     return false;
     387                 :             : 
     388                 :    28257852 :   tree lhs = gimple_assign_lhs (stmt);
     389                 :    28257852 :   tree rhs = gimple_assign_rhs1 (stmt);
     390                 :             : 
     391                 :    28257852 :   if (TREE_CODE (lhs) != SSA_NAME)
     392                 :             :     return false;
     393                 :             : 
     394                 :             :   /* lhs shouldn't flow through any abnormal edges.  */
     395                 :    12972093 :   if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
     396                 :             :     return false;
     397                 :             : 
     398                 :    12971437 :   if (is_gimple_min_invariant (rhs))
     399                 :             :     return true;  /* A statement of type _2 = 5;.  */
     400                 :             : 
     401                 :    12965906 :   if (TREE_CODE (rhs) != SSA_NAME)
     402                 :             :     return false;
     403                 :             : 
     404                 :             :   /* rhs shouldn't flow through any abnormal edges.  */
     405                 :       29047 :   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                 :       53814 :   if (POINTER_TYPE_P (TREE_TYPE (lhs))
     416                 :        2200 :       && POINTER_TYPE_P (TREE_TYPE (rhs))
     417                 :       30205 :       && SSA_NAME_PTR_INFO (lhs) != SSA_NAME_PTR_INFO (rhs))
     418                 :             :     return false;
     419                 :       51790 :   if (!POINTER_TYPE_P (TREE_TYPE (lhs))
     420                 :       25805 :       && !POINTER_TYPE_P (TREE_TYPE (rhs))
     421                 :       51790 :       && 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                 :     3315974 : get_all_stmt_may_generate_copy (void)
     432                 :             : {
     433                 :     3315974 :   auto_vec<gimple *> result;
     434                 :             : 
     435                 :     3315974 :   basic_block bb;
     436                 :    23556482 :   FOR_EACH_BB_FN (bb, cfun)
     437                 :             :     {
     438                 :    20240508 :       gimple_stmt_iterator gsi;
     439                 :   178465216 :       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     440                 :             :         {
     441                 :   137984200 :           gimple *s = gsi_stmt (gsi);
     442                 :   137984200 :           if (stmt_may_generate_copy (s))
     443                 :       22625 :             result.safe_push (s);
     444                 :             :         }
     445                 :             : 
     446                 :    20240508 :       gphi_iterator pi;
     447                 :    28005455 :       for (pi = gsi_start_phis (bb); !gsi_end_p (pi); gsi_next (&pi))
     448                 :             :         {
     449                 :     7764947 :           gimple *s = pi.phi ();
     450                 :     7764947 :           if (stmt_may_generate_copy (s))
     451                 :     7446043 :             result.safe_push (s);
     452                 :             :         }
     453                 :             :     }
     454                 :             : 
     455                 :     3315974 :   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                 :             :   void 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                 :             :   void 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                 :             : void
     484                 :      415480 : scc_copy_prop::replace_scc_by_value (vec<gimple *> scc, tree val)
     485                 :             : {
     486                 :     1666612 :   for (gimple *stmt : scc)
     487                 :             :     {
     488                 :      420172 :       tree name = gimple_get_lhs (stmt);
     489                 :      420172 :       if (dump_file && (dump_flags & TDF_DETAILS))
     490                 :             :         {
     491                 :           0 :           fprintf (dump_file, "Replacing ");
     492                 :           0 :           print_generic_expr (dump_file, name);
     493                 :           0 :           fprintf (dump_file, " with ");
     494                 :           0 :           print_generic_expr (dump_file, val);
     495                 :           0 :           fprintf (dump_file, "\n");
     496                 :             :           
     497                 :             :         }
     498                 :      420172 :       replace_uses_by (name, val);
     499                 :      420172 :       bitmap_set_bit (dead_stmts, SSA_NAME_VERSION (name));
     500                 :             :     }
     501                 :             : 
     502                 :      415480 :   if (dump_file)
     503                 :          56 :     fprintf (dump_file, "Replacing SCC of size %d\n", scc.length ());
     504                 :      415480 : }
     505                 :             : 
     506                 :             : /* Part of 'scc_copy_prop::propagate ()'.  */
     507                 :             : 
     508                 :             : void
     509                 :    18203918 : scc_copy_prop::visit_op (tree op, hash_set<tree> &outer_ops,
     510                 :             :                          hash_set<gimple *> &scc_set, bool &is_inner,
     511                 :             :                          tree &last_outer_op)
     512                 :             : {
     513                 :    18203918 :   bool op_in_scc = false;
     514                 :             : 
     515                 :    18203918 :   if (TREE_CODE (op) == SSA_NAME)
     516                 :             :     {
     517                 :    16352921 :       gimple *op_stmt = SSA_NAME_DEF_STMT (op);
     518                 :    16352921 :       if (scc_set.contains (op_stmt))
     519                 :     1111674 :         op_in_scc = true;
     520                 :             :     }
     521                 :             : 
     522                 :    16352921 :   if (!op_in_scc)
     523                 :             :     {
     524                 :    17092244 :       outer_ops.add (op);
     525                 :    17092244 :       last_outer_op = op;
     526                 :    17092244 :       is_inner = false;
     527                 :             :     }
     528                 :    18203918 : }
     529                 :             : 
     530                 :             : /* Main function of this pass.  Find and propagate all three types of copy
     531                 :             :    statements (see pass description above).
     532                 :             : 
     533                 :             :    This is an implementation of an algorithm from the paper Simple and
     534                 :             :    Efficient Construction of Static Single Assignmemnt Form[1].  It is based
     535                 :             :    on strongly-connected components (SCCs) in dataflow graph.  The original
     536                 :             :    algorithm only considers PHI statements.  We extend it to also consider
     537                 :             :    assignment statements of type _2 = _1;.
     538                 :             : 
     539                 :             :    The algorithm is based on this definition of a set of redundant PHIs[1]:
     540                 :             : 
     541                 :             :      A non-empty set P of PHI functions is redundant iff the PHI functions just
     542                 :             :      reference each other or one other value
     543                 :             : 
     544                 :             :    It uses this lemma[1]:
     545                 :             : 
     546                 :             :      Let P be a redundant set of PHI functions.  Then there is a
     547                 :             :      strongly-connected component S subset of P that is also redundant.
     548                 :             : 
     549                 :             :    The algorithm works in this way:
     550                 :             : 
     551                 :             :      1 Find SCCs
     552                 :             :      2 For each SCC S in topological order:
     553                 :             :      3   Construct set 'inner' of statements that only have other statements
     554                 :             :          from S on their right hand side
     555                 :             :      4   Construct set 'outer' of values that originate outside S and appear on
     556                 :             :          right hand side of some statement from S
     557                 :             :      5   If |outer| = 1, outer only contains a value v.  Statements in S only
     558                 :             :          refer to each other or to v -- they are redundant.  Propagate v.
     559                 :             :          Else, recurse on statements in inner.
     560                 :             : 
     561                 :             :    The implementation is non-recursive.
     562                 :             : 
     563                 :             :    References:
     564                 :             : 
     565                 :             :      [1] Simple and Efficient Construction of Static Single Assignmemnt Form,
     566                 :             :      Braun, Buchwald, Hack, Leissa, Mallon, Zwinkau, 2013, LNCS vol. 7791,
     567                 :             :      Section 3.2.  */
     568                 :             : 
     569                 :             : void
     570                 :     3315974 : scc_copy_prop::propagate ()
     571                 :             : {
     572                 :     3315974 :   auto_vec<gimple *> useful_stmts = get_all_stmt_may_generate_copy ();
     573                 :     3315974 :   scc_discovery discovery;
     574                 :             : 
     575                 :     3315974 :   auto_vec<vec<gimple *>> worklist = discovery.compute_sccs (useful_stmts);
     576                 :             : 
     577                 :    14829742 :   while (!worklist.is_empty ())
     578                 :             :     {
     579                 :     7158706 :       vec<gimple *> scc = worklist.pop ();
     580                 :             : 
     581                 :             :       /* When we do 'replace_scc_by_value' it may happen that some EH edges
     582                 :             :          get removed.  That means parts of CFG get removed.  Those may
     583                 :             :          contain copy statements.  For that reason we prune SCCs here.  */
     584                 :     7158706 :       unsigned i;
     585                 :    14777052 :       for (i = 0; i < scc.length ();)
     586                 :     7618346 :         if (gimple_bb (scc[i]) == NULL)
     587                 :           1 :           scc.unordered_remove (i);
     588                 :             :         else
     589                 :     7618345 :           i++;
     590                 :     7158706 :       if (scc.is_empty ())
     591                 :             :         {
     592                 :           1 :           scc.release ();
     593                 :           1 :           continue;
     594                 :             :         }
     595                 :             : 
     596                 :     7158705 :       auto_vec<gimple *> inner;
     597                 :     7158705 :       hash_set<tree> outer_ops;
     598                 :     7158705 :       tree last_outer_op = NULL_TREE;
     599                 :             : 
     600                 :             :       /* Prepare hash set of PHIs in scc to query later.  */
     601                 :     7158705 :       hash_set<gimple *> scc_set;
     602                 :    14777050 :       for (gimple *stmt : scc)
     603                 :     7618345 :         scc_set.add (stmt);
     604                 :             : 
     605                 :    14777050 :       for (gimple *stmt : scc)
     606                 :             :         {
     607                 :     7618345 :           bool is_inner = true;
     608                 :             : 
     609                 :     7618345 :           gphi *phi;
     610                 :     7618345 :           tree op;
     611                 :             : 
     612                 :     7618345 :           switch (gimple_code (stmt))
     613                 :             :             {
     614                 :     7595720 :               case GIMPLE_PHI:
     615                 :     7595720 :                 phi = as_a <gphi *> (stmt);
     616                 :     7595720 :                 unsigned j;
     617                 :    33372733 :                 for (j = 0; j < gimple_phi_num_args (phi); j++)
     618                 :             :                   {
     619                 :    18181293 :                     op = gimple_phi_arg_def (phi, j);
     620                 :    18181293 :                     visit_op (op, outer_ops, scc_set, is_inner, last_outer_op);
     621                 :             :                   }
     622                 :             :                 break;
     623                 :       22625 :               case GIMPLE_ASSIGN:
     624                 :       22625 :                 op = gimple_assign_rhs1 (stmt);
     625                 :       22625 :                 visit_op (op, outer_ops, scc_set, is_inner, last_outer_op);
     626                 :       22625 :                 break;
     627                 :           0 :               default:
     628                 :           0 :                 gcc_unreachable ();
     629                 :             :             }
     630                 :             : 
     631                 :     7618345 :           if (is_inner)
     632                 :      153809 :             inner.safe_push (stmt);
     633                 :             :         }
     634                 :             : 
     635                 :     7158705 :       if (outer_ops.elements () == 1)
     636                 :             :         {
     637                 :             :           /* The only operand in outer_ops.  */
     638                 :      415480 :           tree outer_op = last_outer_op;
     639                 :      415480 :           replace_scc_by_value (scc, outer_op);
     640                 :             :         }
     641                 :     6743225 :       else if (outer_ops.elements () > 1)
     642                 :             :         {
     643                 :             :           /* Add inner sccs to worklist.  */
     644                 :     6743225 :           auto_vec<vec<gimple *>> inner_sccs
     645                 :     6743225 :             = discovery.compute_sccs (inner);
     646                 :     7017891 :           for (vec<gimple *> inner_scc : inner_sccs)
     647                 :      122456 :             worklist.safe_push (inner_scc);
     648                 :     6743225 :         }
     649                 :             :       else
     650                 :           0 :         gcc_unreachable ();
     651                 :             : 
     652                 :     7158705 :       scc.release ();
     653                 :     7158705 :     }
     654                 :     3315974 : }
     655                 :             : 
     656                 :     3315974 : scc_copy_prop::scc_copy_prop ()
     657                 :             : {
     658                 :             :   /* For propagated statements.  */
     659                 :     3315974 :   dead_stmts = BITMAP_ALLOC (NULL);
     660                 :     3315974 : }
     661                 :             : 
     662                 :     3315974 : scc_copy_prop::~scc_copy_prop ()
     663                 :             : {
     664                 :             :   /* Remove all propagated statements.  */
     665                 :     3315974 :   simple_dce_from_worklist (dead_stmts);
     666                 :     3315974 :   BITMAP_FREE (dead_stmts);
     667                 :             : 
     668                 :             :   /* Propagating a constant may create dead eh edges.  */
     669                 :     3315974 :   basic_block bb;
     670                 :    23556478 :   FOR_EACH_BB_FN (bb, cfun)
     671                 :    20240504 :     gimple_purge_dead_eh_edges (bb);
     672                 :     3315974 : }
     673                 :             : 
     674                 :             : namespace {
     675                 :             : 
     676                 :             : const pass_data pass_data_sccopy =
     677                 :             : {
     678                 :             :   GIMPLE_PASS, /* type */
     679                 :             :   "sccopy", /* name */
     680                 :             :   OPTGROUP_NONE, /* optinfo_flags */
     681                 :             :   TV_NONE, /* tv_id */
     682                 :             :   ( PROP_cfg | PROP_ssa ), /* properties_required */
     683                 :             :   0, /* properties_provided */
     684                 :             :   0, /* properties_destroyed */
     685                 :             :   0, /* todo_flags_start */
     686                 :             :   TODO_update_ssa | TODO_cleanup_cfg, /* todo_flags_finish */
     687                 :             : };
     688                 :             : 
     689                 :             : class pass_sccopy : public gimple_opt_pass
     690                 :             : {
     691                 :             : public:
     692                 :      566314 :   pass_sccopy (gcc::context *ctxt)
     693                 :     1132628 :     : gimple_opt_pass (pass_data_sccopy, ctxt)
     694                 :             :   {}
     695                 :             : 
     696                 :             :   /* opt_pass methods: */
     697                 :     3316048 :   virtual bool gate (function *) { return true; }
     698                 :             :   virtual unsigned int execute (function *);
     699                 :      283157 :   opt_pass * clone () final override { return new pass_sccopy (m_ctxt); }
     700                 :             : }; // class pass_sccopy
     701                 :             : 
     702                 :             : unsigned
     703                 :     3315974 : pass_sccopy::execute (function *)
     704                 :             : {
     705                 :     3315974 :   scc_copy_prop sccopy;
     706                 :     3315974 :   sccopy.propagate ();
     707                 :     6631948 :   return 0;
     708                 :     3315974 : }
     709                 :             : 
     710                 :             : } // anon namespace
     711                 :             : 
     712                 :             : gimple_opt_pass *
     713                 :      283157 : make_pass_sccopy (gcc::context *ctxt)
     714                 :             : {
     715                 :      283157 :   return new pass_sccopy (ctxt);
     716                 :             : }
        

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.