1 /* Callgraph summary data structure.
2    Copyright (C) 2014-2021 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.  */
function_summary_base(symbol_table * symtab,cgraph_node_hook symtab_insertion,cgraph_node_hook symtab_removal,cgraph_2node_hook symtab_duplication CXX_MEM_STAT_INFO)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.  */
insert(cgraph_node *,T *)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.  */
remove(cgraph_node *,T *)57   virtual void remove (cgraph_node *, T *) {}
58 
59   /* Basic implementation of duplication operation.  */
duplicate(cgraph_node *,cgraph_node *,T *,T *)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.  */
enable_insertion_hook()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.  */
disable_insertion_hook()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.  */
enable_duplication_hook()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.  */
disable_duplication_hook()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.  */
allocate_new()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.  */
release(T * item)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
unregister_hooks()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>
class(user)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.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   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 
267 template <typename T>
function_summary(symbol_table * symtab,bool ggc MEM_STAT_DECL)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>
~function_summary()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
symtab_insertion(cgraph_node * node,void * data)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
symtab_removal(cgraph_node * node,void * data)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
symtab_duplication(cgraph_node * node,cgraph_node * node2,void * data)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
gt_ggc_mx(function_summary<T * > * const & summary)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
gt_pch_nx(function_summary<T * > * const &)327 gt_pch_nx (function_summary<T *> *const &)
328 {
329   gcc_unreachable ();
330 }
331 
332 template <typename T>
333 void
gt_pch_nx(function_summary<T * > * const &,gt_pointer_operator,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   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 
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.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   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 
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   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 
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  */
1014