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