]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/symbol-summary.h
Code refactoring of symtab_summary.
[thirdparty/gcc.git] / gcc / symbol-summary.h
CommitLineData
4008290f 1/* Callgraph summary data structure.
85ec4feb 2 Copyright (C) 2014-2018 Free Software Foundation, Inc.
4008290f
ML
3 Contributed by Martin Liska
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along 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
27template <class T>
28class function_summary
29{
30private:
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
45template <class T>
46class GTY((user)) function_summary <T *>
47{
48public:
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
130protected:
131 /* Indication if we use ggc summary. */
132 bool m_ggc;
133
134private:
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
161template <typename T>
162function_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
177template <typename T>
178void
179function_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
196template <typename T>
197void
198function_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
209template <typename T>
210void
211function_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
220template <typename T>
221void
222function_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
241template <typename T>
242void
243function_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
261template <typename T>
262T*
263function_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
273template <typename T>
274void
275gt_ggc_mx(function_summary<T *>* const &summary)
276{
277 gcc_checking_assert (summary->m_ggc);
278 gt_ggc_mx (&summary->m_map);
279}
280
281template <typename T>
282void
283gt_pch_nx(function_summary<T *>* const &summary)
284{
285 gcc_checking_assert (summary->m_ggc);
286 gt_pch_nx (&summary->m_map);
287}
288
289template <typename T>
290void
291gt_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
301template <class T>
302class call_summary
303{
304private:
305 call_summary();
306};
307
308/* Class to store auxiliary information about call graph edges. */
309
310template <class T>
311class GTY((user)) call_summary <T *>
312{
313public:
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
434protected:
435 /* Indication if we use ggc summary. */
436 bool m_ggc;
437
438private:
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
476template <typename T>
477void
478gt_ggc_mx(call_summary<T *>* const &summary)
479{
480 gcc_checking_assert (summary->m_ggc);
481 gt_ggc_mx (&summary->m_map);
482}
483
484template <typename T>
485void
486gt_pch_nx(call_summary<T *>* const &summary)
487{
488 gcc_checking_assert (summary->m_ggc);
489 gt_pch_nx (&summary->m_map);
490}
491
492template <typename T>
493void
494gt_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 */