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