1  /* Callgraph summary data structure.
       2     Copyright (C) 2014-2023 Free Software Foundation, Inc.
       3     Contributed by Martin Liska
       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  #ifndef GCC_SYMBOL_SUMMARY_H
      22  #define GCC_SYMBOL_SUMMARY_H
      23  
      24  /* Base class for function_summary and fast_function_summary classes.  */
      25  
      26  template <class T>
      27  class function_summary_base
      28  {
      29  public:
      30    /* Default construction takes SYMTAB as an argument.  */
      31    function_summary_base (symbol_table *symtab,
      32  			 cgraph_node_hook symtab_insertion,
      33  			 cgraph_node_hook symtab_removal,
      34  			 cgraph_2node_hook symtab_duplication
      35  			 CXX_MEM_STAT_INFO):
      36    m_symtab (symtab), m_symtab_insertion (symtab_insertion),
      37    m_symtab_removal (symtab_removal),
      38    m_symtab_duplication (symtab_duplication),
      39    m_symtab_insertion_hook (NULL), m_symtab_duplication_hook (NULL),
      40    m_allocator ("function summary" PASS_MEM_STAT)
      41    {
      42      enable_insertion_hook ();
      43      m_symtab_removal_hook
      44        = m_symtab->add_cgraph_removal_hook (m_symtab_removal, this);
      45      enable_duplication_hook ();
      46    }
      47  
      48    /* Basic implementation of insert operation.  */
      49    virtual void insert (cgraph_node *, T *)
      50    {
      51      /* In most cases, it makes no sense to create summaries without
      52         initializing them.  */
      53      gcc_unreachable ();
      54    }
      55  
      56    /* Basic implementation of removal operation.  */
      57    virtual void remove (cgraph_node *, T *) {}
      58  
      59    /* Basic implementation of duplication operation.  */
      60    virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *)
      61    {
      62      /* It makes no sense to not copy anything during duplication.  */
      63      gcc_unreachable ();
      64    }
      65  
      66    /* Enable insertion hook invocation.  */
      67    void enable_insertion_hook ()
      68    {
      69      if (m_symtab_insertion_hook == NULL)
      70        m_symtab_insertion_hook
      71  	= m_symtab->add_cgraph_insertion_hook (m_symtab_insertion, this);
      72    }
      73  
      74    /* Enable insertion hook invocation.  */
      75    void disable_insertion_hook ()
      76    {
      77      if (m_symtab_insertion_hook != NULL)
      78        {
      79  	m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
      80  	m_symtab_insertion_hook = NULL;
      81        }
      82    }
      83  
      84    /* Enable duplication hook invocation.  */
      85    void enable_duplication_hook ()
      86    {
      87      if (m_symtab_duplication_hook == NULL)
      88        m_symtab_duplication_hook
      89  	= m_symtab->add_cgraph_duplication_hook (m_symtab_duplication, this);
      90    }
      91  
      92    /* Enable duplication hook invocation.  */
      93    void disable_duplication_hook ()
      94    {
      95      if (m_symtab_duplication_hook != NULL)
      96        {
      97  	m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
      98  	m_symtab_duplication_hook = NULL;
      99        }
     100    }
     101  
     102  protected:
     103    /* Allocates new data that are stored within map.  */
     104    T* allocate_new ()
     105    {
     106      /* Call gcc_internal_because we do not want to call finalizer for
     107         a type T.  We call dtor explicitly.  */
     108      return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
     109  		     : m_allocator.allocate () ;
     110    }
     111  
     112    /* Release an item that is stored within map.  */
     113    void release (T *item)
     114    {
     115      if (is_ggc ())
     116        ggc_delete (item);
     117      else
     118        m_allocator.remove (item);
     119    }
     120  
     121    /* Unregister all call-graph hooks.  */
     122    void unregister_hooks ();
     123  
     124    /* Symbol table the summary is registered to.  */
     125    symbol_table *m_symtab;
     126  
     127    /* Insertion function defined by a summary.  */
     128    cgraph_node_hook m_symtab_insertion;
     129    /* Removal function defined by a summary.  */
     130    cgraph_node_hook m_symtab_removal;
     131    /* Duplication function defined by a summary.  */
     132    cgraph_2node_hook m_symtab_duplication;
     133  
     134    /* Internal summary insertion hook pointer.  */
     135    cgraph_node_hook_list *m_symtab_insertion_hook;
     136    /* Internal summary removal hook pointer.  */
     137    cgraph_node_hook_list *m_symtab_removal_hook;
     138    /* Internal summary duplication hook pointer.  */
     139    cgraph_2node_hook_list *m_symtab_duplication_hook;
     140  
     141  private:
     142    /* Return true when the summary uses GGC memory for allocation.  */
     143    virtual bool is_ggc () = 0;
     144  
     145    /* Object allocator for heap allocation.  */
     146    object_allocator<T> m_allocator;
     147  };
     148  
     149  template <typename T>
     150  void
     151  function_summary_base<T>::unregister_hooks ()
     152  {
     153    disable_insertion_hook ();
     154    m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
     155    disable_duplication_hook ();
     156  }
     157  
     158  /* We want to pass just pointer types as argument for function_summary
     159     template class.  */
     160  
     161  template <class T>
     162  class function_summary
     163  {
     164  private:
     165    function_summary();
     166  };
     167  
     168  /* Function summary is a helper class that is used to associate a data structure
     169     related to a callgraph node.  Typical usage can be seen in IPA passes which
     170     create a temporary pass-related structures.  The summary class registers
     171     hooks that are triggered when a new node is inserted, duplicated and deleted.
     172     A user of a summary class can ovewrite virtual methods than are triggered by
     173     the summary if such hook is triggered.  Apart from a callgraph node, the user
     174     is given a data structure tied to the node.
     175  
     176     The function summary class can work both with a heap-allocated memory and
     177     a memory gained by garbage collected memory.  */
     178  
     179  template <class T>
     180  class GTY((user)) function_summary <T *>: public function_summary_base<T>
     181  {
     182  public:
     183    /* Default construction takes SYMTAB as an argument.  */
     184    function_summary (symbol_table *symtab, bool ggc = false CXX_MEM_STAT_INFO);
     185  
     186    /* Destructor.  */
     187    virtual ~function_summary ();
     188  
     189    /* Traverses all summarys with a function F called with
     190       ARG as argument.  */
     191    template<typename Arg, bool (*f)(const T &, Arg)>
     192    void traverse (Arg a) const
     193    {
     194      m_map.template traverse <f> (a);
     195    }
     196  
     197    /* Getter for summary callgraph node pointer.  If a summary for a node
     198       does not exist it will be created.  */
     199    T* get_create (cgraph_node *node)
     200    {
     201      bool existed;
     202      T **v = &m_map.get_or_insert (node->get_uid (), &existed);
     203      if (!existed)
     204        *v = this->allocate_new ();
     205  
     206      return *v;
     207    }
     208  
     209    /* Getter for summary callgraph node pointer.  */
     210    T* get (cgraph_node *node) ATTRIBUTE_PURE
     211    {
     212      T **v = m_map.get (node->get_uid ());
     213      return v == NULL ? NULL : *v;
     214    }
     215  
     216    /* Remove node from summary.  */
     217    using function_summary_base<T>::remove;
     218    void remove (cgraph_node *node)
     219    {
     220      int uid = node->get_uid ();
     221      T **v = m_map.get (uid);
     222      if (v)
     223        {
     224  	m_map.remove (uid);
     225  	this->release (*v);
     226        }
     227    }
     228  
     229    /* Return true if a summary for the given NODE already exists.  */
     230    bool exists (cgraph_node *node)
     231    {
     232      return m_map.get (node->get_uid ()) != NULL;
     233    }
     234  
     235    /* Symbol insertion hook that is registered to symbol table.  */
     236    static void symtab_insertion (cgraph_node *node, void *data);
     237  
     238    /* Symbol removal hook that is registered to symbol table.  */
     239    static void symtab_removal (cgraph_node *node, void *data);
     240  
     241    /* Symbol duplication hook that is registered to symbol table.  */
     242    static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
     243  				  void *data);
     244  
     245  protected:
     246    /* Indication if we use ggc summary.  */
     247    bool m_ggc;
     248  
     249  private:
     250    /* Indication if we use ggc summary.  */
     251    bool is_ggc () final override
     252    {
     253      return m_ggc;
     254    }
     255  
     256    typedef int_hash <int, 0, -1> map_hash;
     257  
     258    /* Main summary store, where summary ID is used as key.  */
     259    hash_map <map_hash, T *> m_map;
     260  
     261    template <typename U> friend void gt_ggc_mx (function_summary <U *> * const &);
     262    template <typename U> friend void gt_pch_nx (function_summary <U *> * const &);
     263    template <typename U> friend void gt_pch_nx (function_summary <U *> * const &,
     264        gt_pointer_operator, void *);
     265  };
     266  
     267  template <typename T>
     268  function_summary<T *>::function_summary (symbol_table *symtab, bool ggc
     269  					 MEM_STAT_DECL):
     270    function_summary_base<T> (symtab, function_summary::symtab_insertion,
     271  			    function_summary::symtab_removal,
     272  			    function_summary::symtab_duplication
     273  			    PASS_MEM_STAT),
     274    m_ggc (ggc), m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT) {}
     275  
     276  template <typename T>
     277  function_summary<T *>::~function_summary ()
     278  {
     279    this->unregister_hooks ();
     280  
     281    /* Release all summaries.  */
     282    typedef typename hash_map <map_hash, T *>::iterator map_iterator;
     283    for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
     284      this->release ((*it).second);
     285  }
     286  
     287  template <typename T>
     288  void
     289  function_summary<T *>::symtab_insertion (cgraph_node *node, void *data)
     290  {
     291    gcc_checking_assert (node->get_uid ());
     292    function_summary *summary = (function_summary <T *> *) (data);
     293    summary->insert (node, summary->get_create (node));
     294  }
     295  
     296  template <typename T>
     297  void
     298  function_summary<T *>::symtab_removal (cgraph_node *node, void *data)
     299  {
     300    gcc_checking_assert (node->get_uid ());
     301    function_summary *summary = (function_summary <T *> *) (data);
     302    summary->remove (node);
     303  }
     304  
     305  template <typename T>
     306  void
     307  function_summary<T *>::symtab_duplication (cgraph_node *node,
     308  					   cgraph_node *node2, void *data)
     309  {
     310    function_summary *summary = (function_summary <T *> *) (data);
     311    T *v = summary->get (node);
     312  
     313    if (v)
     314      summary->duplicate (node, node2, v, summary->get_create (node2));
     315  }
     316  
     317  template <typename T>
     318  void
     319  gt_ggc_mx(function_summary<T *>* const &summary)
     320  {
     321    gcc_checking_assert (summary->m_ggc);
     322    gt_ggc_mx (&summary->m_map);
     323  }
     324  
     325  template <typename T>
     326  void
     327  gt_pch_nx (function_summary<T *> *const &)
     328  {
     329    gcc_unreachable ();
     330  }
     331  
     332  template <typename T>
     333  void
     334  gt_pch_nx (function_summary<T *> *const &, gt_pointer_operator, void *)
     335  {
     336    gcc_unreachable ();
     337  }
     338  
     339  /* Help template from std c++11.  */
     340  
     341  template<typename T, typename U>
     342  struct is_same
     343  {
     344      static const bool value = false;
     345  };
     346  
     347  template<typename T>
     348  struct is_same<T,T>  //specialization
     349  {
     350     static const bool value = true;
     351  };
     352  
     353  /* We want to pass just pointer types as argument for fast_function_summary
     354     template class.  */
     355  
     356  template <class T, class V>
     357  class fast_function_summary
     358  {
     359  private:
     360    fast_function_summary ();
     361  };
     362  
     363  /* Function vector summary is a fast implementation of function_summary that
     364     utilizes vector as primary storage of summaries.  */
     365  
     366  template <class T, class V>
     367  class GTY((user)) fast_function_summary <T *, V>
     368    : public function_summary_base<T>
     369  {
     370  public:
     371    /* Default construction takes SYMTAB as an argument.  */
     372    fast_function_summary (symbol_table *symtab CXX_MEM_STAT_INFO);
     373  
     374    /* Destructor.  */
     375    virtual ~fast_function_summary ();
     376  
     377    /* Traverses all summarys with a function F called with
     378       ARG as argument.  */
     379    template<typename Arg, bool (*f)(const T &, Arg)>
     380    void traverse (Arg a) const
     381    {
     382      for (unsigned i = 0; i < m_vector->length (); i++)
     383        if ((*m_vector[i]) != NULL)
     384  	f ((*m_vector)[i], a);
     385    }
     386  
     387    /* Getter for summary callgraph node pointer.  If a summary for a node
     388       does not exist it will be created.  */
     389    T* get_create (cgraph_node *node)
     390    {
     391      int id = node->get_summary_id ();
     392      if (id == -1)
     393        id = this->m_symtab->assign_summary_id (node);
     394  
     395      if ((unsigned int)id >= m_vector->length ())
     396        vec_safe_grow_cleared (m_vector,
     397  			     this->m_symtab->cgraph_max_summary_id);
     398  
     399      if ((*m_vector)[id] == NULL)
     400        (*m_vector)[id] = this->allocate_new ();
     401  
     402      return (*m_vector)[id];
     403    }
     404  
     405    /* Getter for summary callgraph node pointer.  */
     406    T* get (cgraph_node *node) ATTRIBUTE_PURE
     407    {
     408      return exists (node) ? (*m_vector)[node->get_summary_id ()] : NULL;
     409    }
     410  
     411    using function_summary_base<T>::remove;
     412    void remove (cgraph_node *node)
     413    {
     414      if (exists (node))
     415        {
     416  	int id = node->get_summary_id ();
     417  	this->release ((*m_vector)[id]);
     418  	(*m_vector)[id] = NULL;
     419        }
     420    }
     421  
     422    /* Return true if a summary for the given NODE already exists.  */
     423    bool exists (cgraph_node *node)
     424    {
     425      int id = node->get_summary_id ();
     426      return (id != -1
     427  	    && (unsigned int)id < m_vector->length ()
     428  	    && (*m_vector)[id] != NULL);
     429    }
     430  
     431    /* Symbol insertion hook that is registered to symbol table.  */
     432    static void symtab_insertion (cgraph_node *node, void *data);
     433  
     434    /* Symbol removal hook that is registered to symbol table.  */
     435    static void symtab_removal (cgraph_node *node, void *data);
     436  
     437    /* Symbol duplication hook that is registered to symbol table.  */
     438    static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
     439  				  void *data);
     440  
     441  private:
     442    bool is_ggc () final override;
     443  
     444    /* Summary is stored in the vector.  */
     445    vec <T *, V> *m_vector;
     446  
     447    template <typename U> friend void gt_ggc_mx (fast_function_summary <U *, va_gc> * const &);
     448    template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &);
     449    template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &,
     450        gt_pointer_operator, void *);
     451  };
     452  
     453  template <typename T, typename V>
     454  fast_function_summary<T *, V>::fast_function_summary (symbol_table *symtab
     455  						      MEM_STAT_DECL):
     456    function_summary_base<T> (symtab,
     457  			    fast_function_summary::symtab_insertion,
     458  			    fast_function_summary::symtab_removal,
     459  			    fast_function_summary::symtab_duplication
     460  			    PASS_MEM_STAT), m_vector (NULL)
     461  {
     462    vec_alloc (m_vector, 13 PASS_MEM_STAT);
     463  }
     464  
     465  template <typename T, typename V>
     466  fast_function_summary<T *, V>::~fast_function_summary ()
     467  {
     468    this->unregister_hooks ();
     469  
     470    /* Release all summaries.  */
     471    for (unsigned i = 0; i < m_vector->length (); i++)
     472      if ((*m_vector)[i] != NULL)
     473        this->release ((*m_vector)[i]);
     474    vec_free (m_vector);
     475  }
     476  
     477  template <typename T, typename V>
     478  void
     479  fast_function_summary<T *, V>::symtab_insertion (cgraph_node *node, void *data)
     480  {
     481    gcc_checking_assert (node->get_uid ());
     482    fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
     483    summary->insert (node, summary->get_create (node));
     484  }
     485  
     486  template <typename T, typename V>
     487  void
     488  fast_function_summary<T *, V>::symtab_removal (cgraph_node *node, void *data)
     489  {
     490    gcc_checking_assert (node->get_uid ());
     491    fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
     492  
     493    if (summary->exists (node))
     494      summary->remove (node);
     495  }
     496  
     497  template <typename T, typename V>
     498  void
     499  fast_function_summary<T *, V>::symtab_duplication (cgraph_node *node,
     500  						   cgraph_node *node2,
     501  						   void *data)
     502  {
     503    fast_function_summary *summary = (fast_function_summary <T *, V> *) (data);
     504    T *v = summary->get (node);
     505  
     506    if (v)
     507      {
     508        T *duplicate = summary->get_create (node2);
     509        summary->duplicate (node, node2, v, duplicate);
     510      }
     511  }
     512  
     513  template <typename T, typename V>
     514  inline bool
     515  fast_function_summary<T *, V>::is_ggc ()
     516  {
     517    return is_same<V, va_gc>::value;
     518  }
     519  
     520  template <typename T>
     521  void
     522  gt_ggc_mx (fast_function_summary<T *, va_heap>* const &)
     523  {
     524  }
     525  
     526  template <typename T>
     527  void
     528  gt_pch_nx (fast_function_summary<T *, va_heap>* const &)
     529  {
     530  }
     531  
     532  template <typename T>
     533  void
     534  gt_pch_nx (fast_function_summary<T *, va_heap>* const&, gt_pointer_operator,
     535  	   void *)
     536  {
     537  }
     538  
     539  template <typename T>
     540  void
     541  gt_ggc_mx (fast_function_summary<T *, va_gc>* const &summary)
     542  {
     543    ggc_test_and_set_mark (summary->m_vector);
     544    gt_ggc_mx (summary->m_vector);
     545  }
     546  
     547  template <typename T>
     548  void
     549  gt_pch_nx (fast_function_summary<T *, va_gc> *const &)
     550  {
     551    gcc_unreachable ();
     552  }
     553  
     554  template <typename T>
     555  void
     556  gt_pch_nx (fast_function_summary<T *, va_gc> *const &, gt_pointer_operator,
     557  	   void *)
     558  {
     559    gcc_unreachable ();
     560  }
     561  
     562  /* Base class for call_summary and fast_call_summary classes.  */
     563  
     564  template <class T>
     565  class call_summary_base
     566  {
     567  public:
     568    /* Default construction takes SYMTAB as an argument.  */
     569    call_summary_base (symbol_table *symtab, cgraph_edge_hook symtab_removal,
     570  		     cgraph_2edge_hook symtab_duplication CXX_MEM_STAT_INFO):
     571    m_symtab (symtab), m_symtab_removal (symtab_removal),
     572    m_symtab_duplication (symtab_duplication), m_symtab_duplication_hook (NULL),
     573    m_initialize_when_cloning (false),
     574    m_allocator ("call summary" PASS_MEM_STAT)
     575    {
     576      m_symtab_removal_hook
     577        = m_symtab->add_edge_removal_hook (m_symtab_removal, this);
     578      enable_duplication_hook ();
     579    }
     580  
     581    /* Basic implementation of removal operation.  */
     582    virtual void remove (cgraph_edge *, T *) {}
     583  
     584    /* Basic implementation of duplication operation.  */
     585    virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *)
     586    {
     587      gcc_unreachable ();
     588    }
     589  
     590    /* Enable duplication hook invocation.  */
     591    void enable_duplication_hook ()
     592    {
     593      if (m_symtab_duplication_hook == NULL)
     594        m_symtab_duplication_hook
     595  	= m_symtab->add_edge_duplication_hook (m_symtab_duplication,
     596  					       this);
     597    }
     598  
     599    /* Enable duplication hook invocation.  */
     600    void disable_duplication_hook ()
     601    {
     602      if (m_symtab_duplication_hook != NULL)
     603        {
     604  	m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
     605  	m_symtab_duplication_hook = NULL;
     606        }
     607    }
     608  
     609  protected:
     610    /* Allocates new data that are stored within map.  */
     611    T* allocate_new ()
     612    {
     613      /* Call gcc_internal_because we do not want to call finalizer for
     614         a type T.  We call dtor explicitly.  */
     615      return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T ()
     616  		     : m_allocator.allocate ();
     617    }
     618  
     619    /* Release an item that is stored within map.  */
     620    void release (T *item)
     621    {
     622      if (is_ggc ())
     623        ggc_delete (item);
     624      else
     625        m_allocator.remove (item);
     626    }
     627  
     628    /* Unregister all call-graph hooks.  */
     629    void unregister_hooks ();
     630  
     631    /* Symbol table the summary is registered to.  */
     632    symbol_table *m_symtab;
     633  
     634    /* Removal function defined by a summary.  */
     635    cgraph_edge_hook m_symtab_removal;
     636    /* Duplication function defined by a summary.  */
     637    cgraph_2edge_hook m_symtab_duplication;
     638  
     639    /* Internal summary removal hook pointer.  */
     640    cgraph_edge_hook_list *m_symtab_removal_hook;
     641    /* Internal summary duplication hook pointer.  */
     642    cgraph_2edge_hook_list *m_symtab_duplication_hook;
     643    /* Initialize summary for an edge that is cloned.  */
     644    bool m_initialize_when_cloning;
     645  
     646  private:
     647    /* Return true when the summary uses GGC memory for allocation.  */
     648    virtual bool is_ggc () = 0;
     649  
     650    /* Object allocator for heap allocation.  */
     651    object_allocator<T> m_allocator;
     652  };
     653  
     654  template <typename T>
     655  void
     656  call_summary_base<T>::unregister_hooks ()
     657  {
     658    m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
     659    disable_duplication_hook ();
     660  }
     661  
     662  /* An impossible class templated by non-pointers so, which makes sure that only
     663     summaries gathering pointers can be created.  */
     664  
     665  template <class T>
     666  class call_summary
     667  {
     668  private:
     669    call_summary ();
     670  };
     671  
     672  /* Class to store auxiliary information about call graph edges.  */
     673  
     674  template <class T>
     675  class GTY((user)) call_summary <T *>: public call_summary_base<T>
     676  {
     677  public:
     678    /* Default construction takes SYMTAB as an argument.  */
     679    call_summary (symbol_table *symtab, bool ggc = false
     680  		CXX_MEM_STAT_INFO)
     681    : call_summary_base<T> (symtab, call_summary::symtab_removal,
     682  			  call_summary::symtab_duplication PASS_MEM_STAT),
     683      m_ggc (ggc), m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT) {}
     684  
     685    /* Destructor.  */
     686    virtual ~call_summary ();
     687  
     688    /* Traverses all summarys with an edge E called with
     689       ARG as argument.  */
     690    template<typename Arg, bool (*f)(const T &, Arg)>
     691    void traverse (Arg a) const
     692    {
     693      m_map.template traverse <f> (a);
     694    }
     695  
     696    /* Getter for summary callgraph edge pointer.
     697       If a summary for an edge does not exist, it will be created.  */
     698    T* get_create (cgraph_edge *edge)
     699    {
     700      bool existed;
     701      T **v = &m_map.get_or_insert (edge->get_uid (), &existed);
     702      if (!existed)
     703        *v = this->allocate_new ();
     704  
     705      return *v;
     706    }
     707  
     708    /* Getter for summary callgraph edge pointer.  */
     709    T* get (cgraph_edge *edge) ATTRIBUTE_PURE
     710    {
     711      T **v = m_map.get (edge->get_uid ());
     712      return v == NULL ? NULL : *v;
     713    }
     714  
     715    /* Remove edge from summary.  */
     716    using call_summary_base<T>::remove;
     717    void remove (cgraph_edge *edge)
     718    {
     719      int uid = edge->get_uid ();
     720      T **v = m_map.get (uid);
     721      if (v)
     722        {
     723  	m_map.remove (uid);
     724  	this->release (*v);
     725        }
     726    }
     727  
     728    /* Return true if a summary for the given EDGE already exists.  */
     729    bool exists (cgraph_edge *edge)
     730    {
     731      return m_map.get (edge->get_uid ()) != NULL;
     732    }
     733  
     734    /* Symbol removal hook that is registered to symbol table.  */
     735    static void symtab_removal (cgraph_edge *edge, void *data);
     736  
     737    /* Symbol duplication hook that is registered to symbol table.  */
     738    static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
     739  				  void *data);
     740  
     741  protected:
     742    /* Indication if we use ggc summary.  */
     743    bool m_ggc;
     744  
     745  private:
     746    /* Indication if we use ggc summary.  */
     747    bool is_ggc () final override
     748    {
     749      return m_ggc;
     750    }
     751  
     752    typedef int_hash <int, 0, -1> map_hash;
     753  
     754    /* Main summary store, where summary ID is used as key.  */
     755    hash_map <map_hash, T *> m_map;
     756  
     757    template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &);
     758    template <typename U> friend void gt_pch_nx (call_summary <U *> * const &);
     759    template <typename U> friend void gt_pch_nx (call_summary <U *> * const &,
     760        gt_pointer_operator, void *);
     761  };
     762  
     763  template <typename T>
     764  call_summary<T *>::~call_summary ()
     765  {
     766    this->unregister_hooks ();
     767  
     768    /* Release all summaries.  */
     769    typedef typename hash_map <map_hash, T *>::iterator map_iterator;
     770    for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
     771      this->release ((*it).second);
     772  }
     773  
     774  template <typename T>
     775  void
     776  call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data)
     777  {
     778    call_summary *summary = (call_summary <T *> *) (data);
     779    summary->remove (edge);
     780  }
     781  
     782  template <typename T>
     783  void
     784  call_summary<T *>::symtab_duplication (cgraph_edge *edge1,
     785  				       cgraph_edge *edge2, void *data)
     786  {
     787    call_summary *summary = (call_summary <T *> *) (data);
     788    T *edge1_summary = NULL;
     789  
     790    if (summary->m_initialize_when_cloning)
     791      edge1_summary = summary->get_create (edge1);
     792    else
     793      edge1_summary = summary->get (edge1);
     794  
     795    if (edge1_summary)
     796      summary->duplicate (edge1, edge2, edge1_summary,
     797  			summary->get_create (edge2));
     798  }
     799  
     800  template <typename T>
     801  void
     802  gt_ggc_mx(call_summary<T *>* const &summary)
     803  {
     804    gcc_checking_assert (summary->m_ggc);
     805    gt_ggc_mx (&summary->m_map);
     806  }
     807  
     808  template <typename T>
     809  void
     810  gt_pch_nx (call_summary<T *> *const &)
     811  {
     812    gcc_unreachable ();
     813  }
     814  
     815  template <typename T>
     816  void
     817  gt_pch_nx (call_summary<T *> *const &, gt_pointer_operator, void *)
     818  {
     819    gcc_unreachable ();
     820  }
     821  
     822  /* We want to pass just pointer types as argument for fast_call_summary
     823     template class.  */
     824  
     825  template <class T, class V>
     826  class fast_call_summary
     827  {
     828  private:
     829    fast_call_summary ();
     830  };
     831  
     832  /* Call vector summary is a fast implementation of call_summary that
     833     utilizes vector as primary storage of summaries.  */
     834  
     835  template <class T, class V>
     836  class GTY((user)) fast_call_summary <T *, V>: public call_summary_base<T>
     837  {
     838  public:
     839    /* Default construction takes SYMTAB as an argument.  */
     840    fast_call_summary (symbol_table *symtab CXX_MEM_STAT_INFO)
     841    : call_summary_base<T> (symtab, fast_call_summary::symtab_removal,
     842  			  fast_call_summary::symtab_duplication PASS_MEM_STAT),
     843      m_vector (NULL)
     844    {
     845      vec_alloc (m_vector, 13 PASS_MEM_STAT);
     846    }
     847  
     848    /* Destructor.  */
     849    virtual ~fast_call_summary ();
     850  
     851    /* Traverses all summarys with an edge F called with
     852       ARG as argument.  */
     853    template<typename Arg, bool (*f)(const T &, Arg)>
     854    void traverse (Arg a) const
     855    {
     856      for (unsigned i = 0; i < m_vector->length (); i++)
     857        if ((*m_vector[i]) != NULL)
     858  	f ((*m_vector)[i], a);
     859    }
     860  
     861    /* Getter for summary callgraph edge pointer.
     862       If a summary for an edge does not exist, it will be created.  */
     863    T* get_create (cgraph_edge *edge)
     864    {
     865      int id = edge->get_summary_id ();
     866      if (id == -1)
     867        id = this->m_symtab->assign_summary_id (edge);
     868  
     869      if ((unsigned)id >= m_vector->length ())
     870        vec_safe_grow_cleared (m_vector, this->m_symtab->edges_max_summary_id);
     871  
     872      if ((*m_vector)[id] == NULL)
     873        (*m_vector)[id] = this->allocate_new ();
     874  
     875      return (*m_vector)[id];
     876    }
     877  
     878    /* Getter for summary callgraph edge pointer.  */
     879    T* get (cgraph_edge *edge) ATTRIBUTE_PURE
     880    {
     881      return exists (edge) ? (*m_vector)[edge->get_summary_id ()] : NULL;
     882    }
     883  
     884    /* Remove edge from summary.  */
     885    using call_summary_base<T>::remove;
     886    void remove (cgraph_edge *edge)
     887    {
     888      if (exists (edge))
     889        {
     890  	int id = edge->get_summary_id ();
     891  	this->release ((*m_vector)[id]);
     892  	(*m_vector)[id] = NULL;
     893        }
     894    }
     895  
     896    /* Return true if a summary for the given EDGE already exists.  */
     897    bool exists (cgraph_edge *edge)
     898    {
     899      int id = edge->get_summary_id ();
     900      return (id != -1
     901  	    && (unsigned)id < m_vector->length ()
     902  	    && (*m_vector)[id] != NULL);
     903    }
     904  
     905    /* Symbol removal hook that is registered to symbol table.  */
     906    static void symtab_removal (cgraph_edge *edge, void *data);
     907  
     908    /* Symbol duplication hook that is registered to symbol table.  */
     909    static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
     910  				  void *data);
     911  
     912  private:
     913    bool is_ggc () final override;
     914  
     915    /* Summary is stored in the vector.  */
     916    vec <T *, V> *m_vector;
     917  
     918    template <typename U> friend void gt_ggc_mx (fast_call_summary <U *, va_gc> * const &);
     919    template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &);
     920    template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &,
     921        gt_pointer_operator, void *);
     922  };
     923  
     924  template <typename T, typename V>
     925  fast_call_summary<T *, V>::~fast_call_summary ()
     926  {
     927    this->unregister_hooks ();
     928  
     929    /* Release all summaries.  */
     930    for (unsigned i = 0; i < m_vector->length (); i++)
     931      if ((*m_vector)[i] != NULL)
     932        this->release ((*m_vector)[i]);
     933    vec_free (m_vector);
     934  }
     935  
     936  template <typename T, typename V>
     937  void
     938  fast_call_summary<T *, V>::symtab_removal (cgraph_edge *edge, void *data)
     939  {
     940    fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
     941    summary->remove (edge);
     942  }
     943  
     944  template <typename T, typename V>
     945  void
     946  fast_call_summary<T *, V>::symtab_duplication (cgraph_edge *edge1,
     947  						 cgraph_edge *edge2, void *data)
     948  {
     949    fast_call_summary *summary = (fast_call_summary <T *, V> *) (data);
     950    T *edge1_summary = NULL;
     951  
     952    if (summary->m_initialize_when_cloning)
     953      edge1_summary = summary->get_create (edge1);
     954    else
     955      edge1_summary = summary->get (edge1);
     956  
     957    if (edge1_summary)
     958      {
     959        T *duplicate = summary->get_create (edge2);
     960        summary->duplicate (edge1, edge2, edge1_summary, duplicate);
     961      }
     962  }
     963  
     964  template <typename T, typename V>
     965  inline bool
     966  fast_call_summary<T *, V>::is_ggc ()
     967  {
     968    return is_same<V, va_gc>::value;
     969  }
     970  
     971  template <typename T>
     972  void
     973  gt_ggc_mx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED)
     974  {
     975  }
     976  
     977  template <typename T>
     978  void
     979  gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED)
     980  {
     981  }
     982  
     983  template <typename T>
     984  void
     985  gt_pch_nx (fast_call_summary<T *, va_heap>* const& summary ATTRIBUTE_UNUSED,
     986  	   gt_pointer_operator op ATTRIBUTE_UNUSED,
     987  	   void *cookie ATTRIBUTE_UNUSED)
     988  {
     989  }
     990  
     991  template <typename T>
     992  void
     993  gt_ggc_mx (fast_call_summary<T *, va_gc>* const &summary)
     994  {
     995    ggc_test_and_set_mark (summary->m_vector);
     996    gt_ggc_mx (&summary->m_vector);
     997  }
     998  
     999  template <typename T>
    1000  void
    1001  gt_pch_nx (fast_call_summary<T *, va_gc> *const &)
    1002  {
    1003    gcc_unreachable ();
    1004  }
    1005  
    1006  template <typename T>
    1007  void
    1008  gt_pch_nx (fast_call_summary<T *, va_gc> *const &, gt_pointer_operator, void *)
    1009  {
    1010    gcc_unreachable ();
    1011  }
    1012  
    1013  #endif  /* GCC_SYMBOL_SUMMARY_H  */