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