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