1/* Callgraph summary data structure.
2   Copyright (C) 2014-2022 Free Software Foundation, Inc.
3   Contributed by Martin Liska
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
26template <class T>
27class function_summary_base
28{
29public:
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
102protected:
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
141private:
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
149template <typename T>
150void
151function_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
161template <class T>
162class function_summary
163{
164private:
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
179template <class T>
180class GTY((user)) function_summary <T *>: public function_summary_base<T>
181{
182public:
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
245protected:
246  /* Indication if we use ggc summary.  */
247  bool m_ggc;
248
249private:
250  /* Indication if we use ggc summary.  */
251  virtual bool is_ggc ()
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
267template <typename T>
268function_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
276template <typename T>
277function_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
287template <typename T>
288void
289function_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
296template <typename T>
297void
298function_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
305template <typename T>
306void
307function_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
317template <typename T>
318void
319gt_ggc_mx(function_summary<T *>* const &summary)
320{
321  gcc_checking_assert (summary->m_ggc);
322  gt_ggc_mx (&summary->m_map);
323}
324
325template <typename T>
326void
327gt_pch_nx (function_summary<T *> *const &)
328{
329  gcc_unreachable ();
330}
331
332template <typename T>
333void
334gt_pch_nx (function_summary<T *> *const &, gt_pointer_operator, void *)
335{
336  gcc_unreachable ();
337}
338
339/* Help template from std c++11.  */
340
341template<typename T, typename U>
342struct is_same
343{
344    static const bool value = false;
345};
346
347template<typename T>
348struct 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
356template <class T, class V>
357class fast_function_summary
358{
359private:
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
366template <class T, class V>
367class GTY((user)) fast_function_summary <T *, V>
368  : public function_summary_base<T>
369{
370public:
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
441private:
442  virtual bool is_ggc ();
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
453template <typename T, typename V>
454fast_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
465template <typename T, typename V>
466fast_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
477template <typename T, typename V>
478void
479fast_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
486template <typename T, typename V>
487void
488fast_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
497template <typename T, typename V>
498void
499fast_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
513template <typename T, typename V>
514inline bool
515fast_function_summary<T *, V>::is_ggc ()
516{
517  return is_same<V, va_gc>::value;
518}
519
520template <typename T>
521void
522gt_ggc_mx (fast_function_summary<T *, va_heap>* const &)
523{
524}
525
526template <typename T>
527void
528gt_pch_nx (fast_function_summary<T *, va_heap>* const &)
529{
530}
531
532template <typename T>
533void
534gt_pch_nx (fast_function_summary<T *, va_heap>* const&, gt_pointer_operator,
535	   void *)
536{
537}
538
539template <typename T>
540void
541gt_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
547template <typename T>
548void
549gt_pch_nx (fast_function_summary<T *, va_gc> *const &)
550{
551  gcc_unreachable ();
552}
553
554template <typename T>
555void
556gt_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
564template <class T>
565class call_summary_base
566{
567public:
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
609protected:
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
646private:
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
654template <typename T>
655void
656call_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
665template <class T>
666class call_summary
667{
668private:
669  call_summary ();
670};
671
672/* Class to store auxiliary information about call graph edges.  */
673
674template <class T>
675class GTY((user)) call_summary <T *>: public call_summary_base<T>
676{
677public:
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
741protected:
742  /* Indication if we use ggc summary.  */
743  bool m_ggc;
744
745private:
746  /* Indication if we use ggc summary.  */
747  virtual bool is_ggc ()
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
763template <typename T>
764call_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
774template <typename T>
775void
776call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data)
777{
778  call_summary *summary = (call_summary <T *> *) (data);
779  summary->remove (edge);
780}
781
782template <typename T>
783void
784call_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
800template <typename T>
801void
802gt_ggc_mx(call_summary<T *>* const &summary)
803{
804  gcc_checking_assert (summary->m_ggc);
805  gt_ggc_mx (&summary->m_map);
806}
807
808template <typename T>
809void
810gt_pch_nx (call_summary<T *> *const &)
811{
812  gcc_unreachable ();
813}
814
815template <typename T>
816void
817gt_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
825template <class T, class V>
826class fast_call_summary
827{
828private:
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
835template <class T, class V>
836class GTY((user)) fast_call_summary <T *, V>: public call_summary_base<T>
837{
838public:
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
912private:
913  virtual bool is_ggc ();
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
924template <typename T, typename V>
925fast_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
936template <typename T, typename V>
937void
938fast_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
944template <typename T, typename V>
945void
946fast_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
964template <typename T, typename V>
965inline bool
966fast_call_summary<T *, V>::is_ggc ()
967{
968  return is_same<V, va_gc>::value;
969}
970
971template <typename T>
972void
973gt_ggc_mx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED)
974{
975}
976
977template <typename T>
978void
979gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED)
980{
981}
982
983template <typename T>
984void
985gt_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
991template <typename T>
992void
993gt_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
999template <typename T>
1000void
1001gt_pch_nx (fast_call_summary<T *, va_gc> *const &)
1002{
1003  gcc_unreachable ();
1004}
1005
1006template <typename T>
1007void
1008gt_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  */
1014