LCOV - code coverage report
Current view: top level - gcc - value-pointer-equiv.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 96.6 % 118 114
Test Date: 2024-12-14 13:15:07 Functions: 100.0 % 16 16
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Context-aware pointer equivalence tracker.
       2                 :             :    Copyright (C) 2020-2024 Free Software Foundation, Inc.
       3                 :             :    Contributed by Aldy Hernandez <aldyh@redhat.com>
       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                 :             : #include "config.h"
      22                 :             : #include "system.h"
      23                 :             : #include "coretypes.h"
      24                 :             : #include "backend.h"
      25                 :             : #include "tree.h"
      26                 :             : #include "gimple.h"
      27                 :             : #include "tree-pass.h"
      28                 :             : #include "ssa.h"
      29                 :             : #include "gimple-pretty-print.h"
      30                 :             : #include "cfganal.h"
      31                 :             : #include "gimple-iterator.h"
      32                 :             : #include "gimple-fold.h"
      33                 :             : #include "tree-eh.h"
      34                 :             : #include "tree-cfg.h"
      35                 :             : #include "tree-ssa-loop-manip.h"
      36                 :             : #include "tree-ssa-loop.h"
      37                 :             : #include "cfgloop.h"
      38                 :             : #include "tree-scalar-evolution.h"
      39                 :             : #include "tree-ssa-propagate.h"
      40                 :             : #include "alloc-pool.h"
      41                 :             : #include "domwalk.h"
      42                 :             : #include "tree-cfgcleanup.h"
      43                 :             : #include "vr-values.h"
      44                 :             : #include "gimple-range.h"
      45                 :             : #include "fold-const.h"
      46                 :             : #include "value-pointer-equiv.h"
      47                 :             : 
      48                 :             : // Unwindable SSA equivalence table for pointers.
      49                 :             : //
      50                 :             : // The main query point is get_replacement() which returns what a
      51                 :             : // given SSA can be replaced with in the current scope.
      52                 :             : 
      53                 :     3972962 : class ssa_equiv_stack
      54                 :             : {
      55                 :             : public:
      56                 :             :   ssa_equiv_stack ();
      57                 :             :   void enter (basic_block);
      58                 :             :   void leave (basic_block);
      59                 :             :   void push_replacement (tree name, tree replacement);
      60                 :             :   tree get_replacement (tree name);
      61                 :             : 
      62                 :             : private:
      63                 :             :   auto_vec<std::pair <tree, tree>> m_stack;
      64                 :             :   auto_vec<tree> m_replacements;
      65                 :             :   const std::pair <tree, tree> m_marker = std::make_pair (NULL_TREE, NULL_TREE);
      66                 :             : };
      67                 :             : 
      68                 :     3972962 : ssa_equiv_stack::ssa_equiv_stack ()
      69                 :             : {
      70                 :     7945924 :   m_replacements.safe_grow_cleared (num_ssa_names + 1);
      71                 :     3972962 : }
      72                 :             : 
      73                 :             : // Pushes a marker at the given point.
      74                 :             : 
      75                 :             : void
      76                 :    34648013 : ssa_equiv_stack::enter (basic_block)
      77                 :             : {
      78                 :    34648013 :   m_stack.safe_push (m_marker);
      79                 :    34648013 : }
      80                 :             : 
      81                 :             : // Pops the stack to the last marker, while performing replacements
      82                 :             : // along the way.
      83                 :             : 
      84                 :             : void
      85                 :    34648013 : ssa_equiv_stack::leave (basic_block)
      86                 :             : {
      87                 :    34648013 :   gcc_checking_assert (!m_stack.is_empty ());
      88                 :    34762635 :   while (m_stack.last () != m_marker)
      89                 :             :     {
      90                 :      114622 :       std::pair<tree, tree> e = m_stack.pop ();
      91                 :      114622 :       m_replacements[SSA_NAME_VERSION (e.first)] = e.second;
      92                 :             :     }
      93                 :    34648013 :   m_stack.pop ();
      94                 :    34648013 : }
      95                 :             : 
      96                 :             : // Set the equivalence of NAME to REPLACEMENT.
      97                 :             : 
      98                 :             : void
      99                 :      114622 : ssa_equiv_stack::push_replacement (tree name, tree replacement)
     100                 :             : {
     101                 :      114622 :   unsigned v = SSA_NAME_VERSION (name);
     102                 :             : 
     103                 :      114622 :   if (v >= m_replacements.length ())
     104                 :           0 :     m_replacements.safe_grow_cleared (num_ssa_names + 1);
     105                 :             : 
     106                 :      114622 :   tree old = m_replacements[v];
     107                 :      114622 :   m_replacements[v] = replacement;
     108                 :      114622 :   m_stack.safe_push (std::make_pair (name, old));
     109                 :      114622 : }
     110                 :             : 
     111                 :             : // Return the equivalence of NAME.
     112                 :             : 
     113                 :             : tree
     114                 :    65534297 : ssa_equiv_stack::get_replacement (tree name)
     115                 :             : {
     116                 :    65534297 :   unsigned v = SSA_NAME_VERSION (name);
     117                 :             : 
     118                 :    65534297 :   if (v >= m_replacements.length ())
     119                 :           0 :     m_replacements.safe_grow_cleared (num_ssa_names + 1);
     120                 :             : 
     121                 :    65534297 :   return m_replacements[v];
     122                 :             : }
     123                 :             : 
     124                 :     3972962 : pointer_equiv_analyzer::pointer_equiv_analyzer (gimple_ranger *r)
     125                 :             : {
     126                 :     3972962 :   m_ranger = r;
     127                 :     7945924 :   m_global_points.safe_grow_cleared (num_ssa_names + 1);
     128                 :     3972962 :   m_cond_points = new ssa_equiv_stack;
     129                 :     3972962 : }
     130                 :             : 
     131                 :     3972962 : pointer_equiv_analyzer::~pointer_equiv_analyzer ()
     132                 :             : {
     133                 :     7945924 :   delete m_cond_points;
     134                 :     3972962 : }
     135                 :             : 
     136                 :             : // Set the global pointer equivalency for SSA to POINTEE.
     137                 :             : 
     138                 :             : void
     139                 :       48436 : pointer_equiv_analyzer::set_global_equiv (tree ssa, tree pointee)
     140                 :             : {
     141                 :       48436 :   unsigned v = SSA_NAME_VERSION (ssa);
     142                 :             : 
     143                 :       48436 :   if (v >= m_global_points.length ())
     144                 :           0 :     m_global_points.safe_grow_cleared (num_ssa_names + 1);
     145                 :             : 
     146                 :       48436 :   m_global_points[v] = pointee;
     147                 :       48436 : }
     148                 :             : 
     149                 :             : // Set the conditional pointer equivalency for SSA to POINTEE.
     150                 :             : 
     151                 :             : void
     152                 :      114622 : pointer_equiv_analyzer::set_cond_equiv (tree ssa, tree pointee)
     153                 :             : {
     154                 :      114622 :   m_cond_points->push_replacement (ssa, pointee);
     155                 :      114622 : }
     156                 :             : 
     157                 :             : // Return the current pointer equivalency info for SSA, or NULL if
     158                 :             : // none is available.  Note that global info takes priority over
     159                 :             : // conditional info.
     160                 :             : 
     161                 :             : tree
     162                 :    65573160 : pointer_equiv_analyzer::get_equiv (tree ssa)
     163                 :             : {
     164                 :    65573160 :   unsigned v = SSA_NAME_VERSION (ssa);
     165                 :             : 
     166                 :    65573160 :   if (v >= m_global_points.length ())
     167                 :           0 :     m_global_points.safe_grow_cleared (num_ssa_names + 1);
     168                 :             : 
     169                 :    65573160 :   tree ret = m_global_points[v];
     170                 :    65573160 :   if (ret)
     171                 :             :     return ret;
     172                 :    65534297 :   return m_cond_points->get_replacement (ssa);
     173                 :             : }
     174                 :             : 
     175                 :             : // Method to be called on entry to a BB.
     176                 :             : 
     177                 :             : void
     178                 :    34648013 : pointer_equiv_analyzer::enter (basic_block bb)
     179                 :             : {
     180                 :    34648013 :   m_cond_points->enter (bb);
     181                 :             : 
     182                 :    34648013 :   for (gphi_iterator iter = gsi_start_phis (bb);
     183                 :    48314105 :        !gsi_end_p (iter);
     184                 :    13666092 :        gsi_next (&iter))
     185                 :             :     {
     186                 :    13862616 :       gphi *phi = iter.phi ();
     187                 :    13862616 :       tree lhs = gimple_phi_result (phi);
     188                 :    13862616 :       if (!POINTER_TYPE_P (TREE_TYPE (lhs)))
     189                 :    12163504 :         continue;
     190                 :     1699112 :       tree arg0 = gimple_phi_arg_def (phi, 0);
     191                 :     1699112 :       if (TREE_CODE (arg0) == SSA_NAME && !is_gimple_min_invariant (arg0))
     192                 :     1463368 :         arg0 = get_equiv (arg0);
     193                 :     1699112 :       if (arg0 && is_gimple_min_invariant (arg0))
     194                 :             :         {
     195                 :             :           // If all the PHI args point to the same place, set the
     196                 :             :           // pointer equivalency info for the PHI result.  This can
     197                 :             :           // happen for passes that create redundant PHIs like
     198                 :             :           // PHI<&foo, &foo> or PHI<&foo>.
     199                 :      260175 :           for (size_t i = 1; i < gimple_phi_num_args (phi); ++i)
     200                 :             :             {
     201                 :      220951 :               tree argi = gimple_phi_arg_def (phi, i);
     202                 :      220951 :               if (TREE_CODE (argi) == SSA_NAME
     203                 :      220951 :                   && !is_gimple_min_invariant (argi))
     204                 :      161082 :                 argi = get_equiv (argi);
     205                 :      220951 :               if (!argi || !operand_equal_p (arg0, argi))
     206                 :      196524 :                 return;
     207                 :             :             }
     208                 :       39224 :           set_global_equiv (lhs, arg0);
     209                 :             :         }
     210                 :             :     }
     211                 :             : 
     212                 :    34451489 :   edge pred = single_pred_edge_ignoring_loop_edges (bb, false);
     213                 :    34451489 :   if (pred)
     214                 :    25300398 :     visit_edge (pred);
     215                 :             : }
     216                 :             : 
     217                 :             : // Method to be called on exit from a BB.
     218                 :             : 
     219                 :             : void
     220                 :    34648013 : pointer_equiv_analyzer::leave (basic_block bb)
     221                 :             : {
     222                 :    34648013 :   m_cond_points->leave (bb);
     223                 :    34648013 : }
     224                 :             : 
     225                 :             : // Helper function to return the pointer equivalency information for
     226                 :             : // EXPR from a gimple statement with CODE.  This returns either the
     227                 :             : // cached pointer equivalency info for an SSA, or an invariant in case
     228                 :             : // EXPR is one (i.e. &foo).  Returns NULL if EXPR is neither an SSA
     229                 :             : // nor an invariant.
     230                 :             : 
     231                 :             : tree
     232                 :    12178438 : pointer_equiv_analyzer::get_equiv_expr (tree_code code, tree expr)
     233                 :             : {
     234                 :    12178438 :   if (code == SSA_NAME)
     235                 :       20872 :     return get_equiv (expr);
     236                 :             : 
     237                 :    12157566 :   if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS
     238                 :    12157566 :       && is_gimple_min_invariant (expr))
     239                 :             :     return expr;
     240                 :             : 
     241                 :             :   return NULL;
     242                 :             : }
     243                 :             : 
     244                 :             : // Hack to provide context to the gimple fold callback.
     245                 :             : static struct
     246                 :             : {
     247                 :             :   gimple *m_stmt;
     248                 :             :   gimple_ranger *m_ranger;
     249                 :             :   pointer_equiv_analyzer *m_pta;
     250                 :             : } x_fold_context;
     251                 :             : 
     252                 :             : // Gimple fold callback.
     253                 :             : static tree
     254                 :    30487108 : pta_valueize (tree name)
     255                 :             : {
     256                 :    30487108 :   tree ret
     257                 :    30487108 :     = x_fold_context.m_ranger->value_of_expr (name, x_fold_context.m_stmt);
     258                 :             : 
     259                 :    30487108 :   if (!ret && supported_pointer_equiv_p (name))
     260                 :    11976726 :     ret = x_fold_context.m_pta->get_equiv (name);
     261                 :             : 
     262                 :    30487108 :   return ret ? ret : name;
     263                 :             : }
     264                 :             : 
     265                 :             : // Method to be called on gimple statements during traversal of the IL.
     266                 :             : 
     267                 :             : void
     268                 :   205230144 : pointer_equiv_analyzer::visit_stmt (gimple *stmt)
     269                 :             : {
     270                 :   205230144 :   if (gimple_code (stmt) != GIMPLE_ASSIGN)
     271                 :             :     return;
     272                 :             : 
     273                 :    62515409 :   tree lhs = gimple_assign_lhs (stmt);
     274                 :    62515409 :   if (!supported_pointer_equiv_p (lhs))
     275                 :             :     return;
     276                 :             : 
     277                 :    10806200 :   tree rhs = gimple_assign_rhs1 (stmt);
     278                 :    10806200 :   rhs = get_equiv_expr (gimple_assign_rhs_code (stmt), rhs);
     279                 :    10806200 :   if (rhs)
     280                 :             :     {
     281                 :        4303 :       set_global_equiv (lhs, rhs);
     282                 :        4303 :       return;
     283                 :             :     }
     284                 :             : 
     285                 :             :   // If we couldn't find anything, try fold.
     286                 :    10801897 :   x_fold_context = { stmt, m_ranger, this};
     287                 :    10801897 :   rhs = gimple_fold_stmt_to_constant_1 (stmt, pta_valueize, pta_valueize);
     288                 :    10801897 :   if (rhs)
     289                 :             :     {
     290                 :     1372238 :       rhs = get_equiv_expr (TREE_CODE (rhs), rhs);
     291                 :     1372238 :       if (rhs)
     292                 :             :         {
     293                 :        4909 :           set_global_equiv (lhs, rhs);
     294                 :        4909 :           return;
     295                 :             :         }
     296                 :             :     }
     297                 :             : }
     298                 :             : 
     299                 :             : // If the edge in E is a conditional that sets a pointer equality, set the
     300                 :             : // conditional pointer equivalency information.
     301                 :             : 
     302                 :             : void
     303                 :    25300398 : pointer_equiv_analyzer::visit_edge (edge e)
     304                 :             : {
     305                 :    50600796 :   gcond *stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (e->src));
     306                 :    15786258 :   tree lhs;
     307                 :             :   // Recognize: x_13 [==,!=] &foo.
     308                 :    15786258 :   if (stmt
     309                 :    15786258 :       && ((lhs = gimple_cond_lhs (stmt)), true)
     310                 :    15786258 :       && TREE_CODE (lhs) == SSA_NAME
     311                 :    15277260 :       && POINTER_TYPE_P (TREE_TYPE (lhs))
     312                 :     2460997 :       && TREE_CODE (gimple_cond_rhs (stmt)) == ADDR_EXPR)
     313                 :             :     {
     314                 :      299561 :       tree_code code = gimple_cond_code (stmt);
     315                 :      299561 :       if ((code == EQ_EXPR && e->flags & EDGE_TRUE_VALUE)
     316                 :      261764 :           || ((code == NE_EXPR && e->flags & EDGE_FALSE_VALUE)))
     317                 :      114622 :         set_cond_equiv (lhs, gimple_cond_rhs (stmt));
     318                 :             :     }
     319                 :    25300398 : }
        

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.