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