]>
Commit | Line | Data |
---|---|---|
4008290f | 1 | /* Callgraph summary data structure. |
85ec4feb | 2 | Copyright (C) 2014-2018 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 | ||
24 | /* We want to pass just pointer types as argument for function_summary | |
25 | template class. */ | |
26 | ||
27 | template <class T> | |
28 | class function_summary | |
29 | { | |
30 | private: | |
31 | function_summary(); | |
32 | }; | |
33 | ||
ef2ceb10 ML |
34 | /* Function summary is a helper class that is used to associate a data structure |
35 | related to a callgraph node. Typical usage can be seen in IPA passes which | |
36 | create a temporary pass-related structures. The summary class registers | |
37 | hooks that are triggered when a new node is inserted, duplicated and deleted. | |
38 | A user of a summary class can ovewrite virtual methods than are triggered by | |
39 | the summary if such hook is triggered. Apart from a callgraph node, the user | |
40 | is given a data structure tied to the node. | |
41 | ||
42 | The function summary class can work both with a heap-allocated memory and | |
43 | a memory gained by garbage collected memory. */ | |
44 | ||
4008290f ML |
45 | template <class T> |
46 | class GTY((user)) function_summary <T *> | |
47 | { | |
48 | public: | |
49 | /* Default construction takes SYMTAB as an argument. */ | |
ef2ceb10 | 50 | function_summary (symbol_table *symtab, bool ggc = false); |
4008290f ML |
51 | |
52 | /* Destructor. */ | |
53 | virtual ~function_summary () | |
54 | { | |
55 | release (); | |
56 | } | |
57 | ||
58 | /* Destruction method that can be called for GGT purpose. */ | |
ef2ceb10 | 59 | void release (); |
4008290f ML |
60 | |
61 | /* Traverses all summarys with a function F called with | |
62 | ARG as argument. */ | |
63 | template<typename Arg, bool (*f)(const T &, Arg)> | |
64 | void traverse (Arg a) const | |
65 | { | |
66 | m_map.traverse <f> (a); | |
67 | } | |
68 | ||
69 | /* Basic implementation of insert operation. */ | |
70 | virtual void insert (cgraph_node *, T *) {} | |
71 | ||
72 | /* Basic implementation of removal operation. */ | |
73 | virtual void remove (cgraph_node *, T *) {} | |
74 | ||
75 | /* Basic implementation of duplication operation. */ | |
76 | virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {} | |
77 | ||
78 | /* Allocates new data that are stored within map. */ | |
79 | T* allocate_new () | |
80 | { | |
e806796d ML |
81 | /* Call gcc_internal_because we do not want to call finalizer for |
82 | a type T. We call dtor explicitly. */ | |
83 | return m_ggc ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ; | |
4008290f ML |
84 | } |
85 | ||
fdbdc4b5 | 86 | /* Release an item that is stored within map. */ |
ef2ceb10 | 87 | void release (T *item); |
fdbdc4b5 | 88 | |
4008290f ML |
89 | /* Getter for summary callgraph node pointer. */ |
90 | T* get (cgraph_node *node) | |
91 | { | |
0ec955c2 | 92 | gcc_checking_assert (node->summary_uid); |
4008290f ML |
93 | return get (node->summary_uid); |
94 | } | |
95 | ||
96 | /* Return number of elements handled by data structure. */ | |
97 | size_t elements () | |
98 | { | |
99 | return m_map.elements (); | |
100 | } | |
101 | ||
57e563ac MJ |
102 | /* Return true if a summary for the given NODE already exists. */ |
103 | bool exists (cgraph_node *node) | |
104 | { | |
105 | return m_map.get (node->summary_uid) != NULL; | |
106 | } | |
107 | ||
4008290f ML |
108 | /* Enable insertion hook invocation. */ |
109 | void enable_insertion_hook () | |
110 | { | |
111 | m_insertion_enabled = true; | |
112 | } | |
113 | ||
114 | /* Enable insertion hook invocation. */ | |
115 | void disable_insertion_hook () | |
116 | { | |
117 | m_insertion_enabled = false; | |
118 | } | |
119 | ||
120 | /* Symbol insertion hook that is registered to symbol table. */ | |
ef2ceb10 | 121 | static void symtab_insertion (cgraph_node *node, void *data); |
4008290f ML |
122 | |
123 | /* Symbol removal hook that is registered to symbol table. */ | |
ef2ceb10 | 124 | static void symtab_removal (cgraph_node *node, void *data); |
4008290f ML |
125 | |
126 | /* Symbol duplication hook that is registered to symbol table. */ | |
127 | static void symtab_duplication (cgraph_node *node, cgraph_node *node2, | |
ef2ceb10 | 128 | void *data); |
4008290f ML |
129 | |
130 | protected: | |
131 | /* Indication if we use ggc summary. */ | |
132 | bool m_ggc; | |
133 | ||
134 | private: | |
e0702244 | 135 | typedef int_hash <int, 0, -1> map_hash; |
4008290f ML |
136 | |
137 | /* Getter for summary callgraph ID. */ | |
ef2ceb10 | 138 | T* get (int uid); |
4008290f | 139 | |
34e82342 RB |
140 | /* Indicates if insertion hook is enabled. */ |
141 | bool m_insertion_enabled; | |
142 | /* Indicates if the summary is released. */ | |
143 | bool m_released; | |
4008290f | 144 | /* Main summary store, where summary ID is used as key. */ |
fb5c464a | 145 | hash_map <map_hash, T *> m_map; |
4008290f ML |
146 | /* Internal summary insertion hook pointer. */ |
147 | cgraph_node_hook_list *m_symtab_insertion_hook; | |
148 | /* Internal summary removal hook pointer. */ | |
149 | cgraph_node_hook_list *m_symtab_removal_hook; | |
150 | /* Internal summary duplication hook pointer. */ | |
151 | cgraph_2node_hook_list *m_symtab_duplication_hook; | |
4008290f ML |
152 | /* Symbol table the summary is registered to. */ |
153 | symbol_table *m_symtab; | |
154 | ||
155 | template <typename U> friend void gt_ggc_mx (function_summary <U *> * const &); | |
156 | template <typename U> friend void gt_pch_nx (function_summary <U *> * const &); | |
157 | template <typename U> friend void gt_pch_nx (function_summary <U *> * const &, | |
158 | gt_pointer_operator, void *); | |
159 | }; | |
160 | ||
ef2ceb10 ML |
161 | template <typename T> |
162 | function_summary<T *>::function_summary (symbol_table *symtab, bool ggc): | |
163 | m_ggc (ggc), m_insertion_enabled (true), m_released (false), m_map (13, ggc), | |
164 | m_symtab (symtab) | |
165 | { | |
166 | m_symtab_insertion_hook | |
167 | = symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion, | |
168 | this); | |
169 | ||
170 | m_symtab_removal_hook | |
171 | = symtab->add_cgraph_removal_hook (function_summary::symtab_removal, this); | |
172 | m_symtab_duplication_hook | |
173 | = symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication, | |
174 | this); | |
175 | } | |
176 | ||
177 | template <typename T> | |
178 | void | |
179 | function_summary<T *>::release () | |
180 | { | |
181 | if (m_released) | |
182 | return; | |
183 | ||
184 | m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook); | |
185 | m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook); | |
186 | m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook); | |
187 | ||
188 | /* Release all summaries. */ | |
189 | typedef typename hash_map <map_hash, T *>::iterator map_iterator; | |
190 | for (map_iterator it = m_map.begin (); it != m_map.end (); ++it) | |
191 | release ((*it).second); | |
192 | ||
193 | m_released = true; | |
194 | } | |
195 | ||
196 | template <typename T> | |
197 | void | |
198 | function_summary<T *>::release (T *item) | |
199 | { | |
200 | if (m_ggc) | |
201 | { | |
202 | item->~T (); | |
203 | ggc_free (item); | |
204 | } | |
205 | else | |
206 | delete item; | |
207 | } | |
208 | ||
209 | template <typename T> | |
210 | void | |
211 | function_summary<T *>::symtab_insertion (cgraph_node *node, void *data) | |
212 | { | |
213 | gcc_checking_assert (node->summary_uid); | |
214 | function_summary *summary = (function_summary <T *> *) (data); | |
215 | ||
216 | if (summary->m_insertion_enabled) | |
217 | summary->insert (node, summary->get (node)); | |
218 | } | |
219 | ||
220 | template <typename T> | |
221 | void | |
222 | function_summary<T *>::symtab_removal (cgraph_node *node, void *data) | |
223 | { | |
224 | gcc_checking_assert (node->summary_uid); | |
225 | function_summary *summary = (function_summary <T *> *) (data); | |
226 | ||
227 | int summary_uid = node->summary_uid; | |
228 | T **v = summary->m_map.get (summary_uid); | |
229 | ||
230 | if (v) | |
231 | { | |
232 | summary->remove (node, *v); | |
233 | ||
234 | if (!summary->m_ggc) | |
235 | delete (*v); | |
236 | ||
237 | summary->m_map.remove (summary_uid); | |
238 | } | |
239 | } | |
240 | ||
241 | template <typename T> | |
242 | void | |
243 | function_summary<T *>::symtab_duplication (cgraph_node *node, | |
244 | cgraph_node *node2, void *data) | |
245 | { | |
246 | function_summary *summary = (function_summary <T *> *) (data); | |
247 | T **v = summary->m_map.get (node->summary_uid); | |
248 | ||
249 | gcc_checking_assert (node2->summary_uid > 0); | |
250 | ||
251 | if (v) | |
252 | { | |
253 | /* This load is necessary, because we insert a new value! */ | |
254 | T *data = *v; | |
255 | T *duplicate = summary->allocate_new (); | |
256 | summary->m_map.put (node2->summary_uid, duplicate); | |
257 | summary->duplicate (node, node2, data, duplicate); | |
258 | } | |
259 | } | |
260 | ||
261 | template <typename T> | |
262 | T* | |
263 | function_summary<T *>::get (int uid) | |
264 | { | |
265 | bool existed; | |
266 | T **v = &m_map.get_or_insert (uid, &existed); | |
267 | if (!existed) | |
268 | *v = allocate_new (); | |
269 | ||
270 | return *v; | |
271 | } | |
272 | ||
4008290f ML |
273 | template <typename T> |
274 | void | |
275 | gt_ggc_mx(function_summary<T *>* const &summary) | |
276 | { | |
277 | gcc_checking_assert (summary->m_ggc); | |
278 | gt_ggc_mx (&summary->m_map); | |
279 | } | |
280 | ||
281 | template <typename T> | |
282 | void | |
283 | gt_pch_nx(function_summary<T *>* const &summary) | |
284 | { | |
285 | gcc_checking_assert (summary->m_ggc); | |
286 | gt_pch_nx (&summary->m_map); | |
287 | } | |
288 | ||
289 | template <typename T> | |
290 | void | |
291 | gt_pch_nx(function_summary<T *>* const& summary, gt_pointer_operator op, | |
292 | void *cookie) | |
293 | { | |
294 | gcc_checking_assert (summary->m_ggc); | |
295 | gt_pch_nx (&summary->m_map, op, cookie); | |
296 | } | |
297 | ||
57e563ac MJ |
298 | /* An impossible class templated by non-pointers so, which makes sure that only |
299 | summaries gathering pointers can be created. */ | |
300 | ||
301 | template <class T> | |
302 | class call_summary | |
303 | { | |
304 | private: | |
305 | call_summary(); | |
306 | }; | |
307 | ||
308 | /* Class to store auxiliary information about call graph edges. */ | |
309 | ||
310 | template <class T> | |
311 | class GTY((user)) call_summary <T *> | |
312 | { | |
313 | public: | |
314 | /* Default construction takes SYMTAB as an argument. */ | |
315 | call_summary (symbol_table *symtab, bool ggc = false): m_ggc (ggc), | |
316 | m_map (13, ggc), m_released (false), m_symtab (symtab) | |
317 | { | |
318 | m_symtab_removal_hook = | |
319 | symtab->add_edge_removal_hook | |
320 | (call_summary::symtab_removal, this); | |
321 | m_symtab_duplication_hook = | |
322 | symtab->add_edge_duplication_hook | |
323 | (call_summary::symtab_duplication, this); | |
324 | } | |
325 | ||
326 | /* Destructor. */ | |
327 | virtual ~call_summary () | |
328 | { | |
329 | release (); | |
330 | } | |
331 | ||
332 | /* Destruction method that can be called for GGT purpose. */ | |
333 | void release () | |
334 | { | |
335 | if (m_released) | |
336 | return; | |
337 | ||
338 | m_symtab->remove_edge_removal_hook (m_symtab_removal_hook); | |
339 | m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook); | |
340 | ||
341 | /* Release all summaries. */ | |
342 | typedef typename hash_map <map_hash, T *>::iterator map_iterator; | |
343 | for (map_iterator it = m_map.begin (); it != m_map.end (); ++it) | |
344 | release ((*it).second); | |
345 | ||
346 | m_released = true; | |
347 | } | |
348 | ||
349 | /* Traverses all summarys with a function F called with | |
350 | ARG as argument. */ | |
351 | template<typename Arg, bool (*f)(const T &, Arg)> | |
352 | void traverse (Arg a) const | |
353 | { | |
354 | m_map.traverse <f> (a); | |
355 | } | |
356 | ||
357 | /* Basic implementation of removal operation. */ | |
358 | virtual void remove (cgraph_edge *, T *) {} | |
359 | ||
360 | /* Basic implementation of duplication operation. */ | |
361 | virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {} | |
362 | ||
363 | /* Allocates new data that are stored within map. */ | |
364 | T* allocate_new () | |
365 | { | |
366 | /* Call gcc_internal_because we do not want to call finalizer for | |
367 | a type T. We call dtor explicitly. */ | |
368 | return m_ggc ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ; | |
369 | } | |
370 | ||
371 | /* Release an item that is stored within map. */ | |
372 | void release (T *item) | |
373 | { | |
374 | if (m_ggc) | |
375 | { | |
376 | item->~T (); | |
377 | ggc_free (item); | |
378 | } | |
379 | else | |
380 | delete item; | |
381 | } | |
382 | ||
383 | /* Getter for summary callgraph edge pointer. */ | |
384 | T* get (cgraph_edge *edge) | |
385 | { | |
386 | return get (hashable_uid (edge)); | |
387 | } | |
388 | ||
389 | /* Return number of elements handled by data structure. */ | |
390 | size_t elements () | |
391 | { | |
392 | return m_map.elements (); | |
393 | } | |
394 | ||
395 | /* Return true if a summary for the given EDGE already exists. */ | |
396 | bool exists (cgraph_edge *edge) | |
397 | { | |
398 | return m_map.get (hashable_uid (edge)) != NULL; | |
399 | } | |
400 | ||
401 | /* Symbol removal hook that is registered to symbol table. */ | |
402 | static void symtab_removal (cgraph_edge *edge, void *data) | |
403 | { | |
404 | call_summary *summary = (call_summary <T *> *) (data); | |
405 | ||
406 | int h_uid = summary->hashable_uid (edge); | |
407 | T **v = summary->m_map.get (h_uid); | |
408 | ||
409 | if (v) | |
410 | { | |
411 | summary->remove (edge, *v); | |
412 | summary->release (*v); | |
413 | summary->m_map.remove (h_uid); | |
414 | } | |
415 | } | |
416 | ||
417 | /* Symbol duplication hook that is registered to symbol table. */ | |
418 | static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2, | |
419 | void *data) | |
420 | { | |
421 | call_summary *summary = (call_summary <T *> *) (data); | |
422 | T **v = summary->m_map.get (summary->hashable_uid (edge1)); | |
423 | ||
424 | if (v) | |
425 | { | |
426 | /* This load is necessary, because we insert a new value! */ | |
427 | T *data = *v; | |
428 | T *duplicate = summary->allocate_new (); | |
429 | summary->m_map.put (summary->hashable_uid (edge2), duplicate); | |
430 | summary->duplicate (edge1, edge2, data, duplicate); | |
431 | } | |
432 | } | |
433 | ||
434 | protected: | |
435 | /* Indication if we use ggc summary. */ | |
436 | bool m_ggc; | |
437 | ||
438 | private: | |
439 | typedef int_hash <int, 0, -1> map_hash; | |
440 | ||
441 | /* Getter for summary callgraph ID. */ | |
442 | T* get (int uid) | |
443 | { | |
444 | bool existed; | |
445 | T **v = &m_map.get_or_insert (uid, &existed); | |
446 | if (!existed) | |
447 | *v = allocate_new (); | |
448 | ||
449 | return *v; | |
450 | } | |
451 | ||
452 | /* Get a hashable uid of EDGE. */ | |
453 | int hashable_uid (cgraph_edge *edge) | |
454 | { | |
455 | /* Edge uids start at zero which our hash_map does not like. */ | |
456 | return edge->uid + 1; | |
457 | } | |
458 | ||
459 | /* Main summary store, where summary ID is used as key. */ | |
460 | hash_map <map_hash, T *> m_map; | |
461 | /* Internal summary removal hook pointer. */ | |
462 | cgraph_edge_hook_list *m_symtab_removal_hook; | |
463 | /* Internal summary duplication hook pointer. */ | |
464 | cgraph_2edge_hook_list *m_symtab_duplication_hook; | |
465 | /* Indicates if the summary is released. */ | |
466 | bool m_released; | |
467 | /* Symbol table the summary is registered to. */ | |
468 | symbol_table *m_symtab; | |
469 | ||
470 | template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &); | |
471 | template <typename U> friend void gt_pch_nx (call_summary <U *> * const &); | |
472 | template <typename U> friend void gt_pch_nx (call_summary <U *> * const &, | |
473 | gt_pointer_operator, void *); | |
474 | }; | |
475 | ||
476 | template <typename T> | |
477 | void | |
478 | gt_ggc_mx(call_summary<T *>* const &summary) | |
479 | { | |
480 | gcc_checking_assert (summary->m_ggc); | |
481 | gt_ggc_mx (&summary->m_map); | |
482 | } | |
483 | ||
484 | template <typename T> | |
485 | void | |
486 | gt_pch_nx(call_summary<T *>* const &summary) | |
487 | { | |
488 | gcc_checking_assert (summary->m_ggc); | |
489 | gt_pch_nx (&summary->m_map); | |
490 | } | |
491 | ||
492 | template <typename T> | |
493 | void | |
494 | gt_pch_nx(call_summary<T *>* const& summary, gt_pointer_operator op, | |
495 | void *cookie) | |
496 | { | |
497 | gcc_checking_assert (summary->m_ggc); | |
498 | gt_pch_nx (&summary->m_map, op, cookie); | |
499 | } | |
500 | ||
4008290f | 501 | #endif /* GCC_SYMBOL_SUMMARY_H */ |