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