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

source code of gcc/symbol-summary.h