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