111
|
1 /* Callgraph summary data structure.
|
131
|
2 Copyright (C) 2014-2018 Free Software Foundation, Inc.
|
111
|
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
|
131
|
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
|
111
|
45 template <class T>
|
|
46 class GTY((user)) function_summary <T *>
|
|
47 {
|
|
48 public:
|
|
49 /* Default construction takes SYMTAB as an argument. */
|
131
|
50 function_summary (symbol_table *symtab, bool ggc = false);
|
111
|
51
|
|
52 /* Destructor. */
|
|
53 virtual ~function_summary ()
|
|
54 {
|
|
55 release ();
|
|
56 }
|
|
57
|
|
58 /* Destruction method that can be called for GGT purpose. */
|
131
|
59 void release ();
|
111
|
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 {
|
|
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 () ;
|
|
84 }
|
|
85
|
|
86 /* Release an item that is stored within map. */
|
131
|
87 void release (T *item);
|
|
88
|
|
89 /* Getter for summary callgraph node pointer. If a summary for a node
|
|
90 does not exist it will be created. */
|
|
91 T* get_create (cgraph_node *node)
|
111
|
92 {
|
131
|
93 bool existed;
|
|
94 T **v = &m_map.get_or_insert (node->get_uid (), &existed);
|
|
95 if (!existed)
|
|
96 *v = allocate_new ();
|
|
97
|
|
98 return *v;
|
111
|
99 }
|
|
100
|
|
101 /* Getter for summary callgraph node pointer. */
|
131
|
102 T* get (cgraph_node *node) ATTRIBUTE_PURE
|
111
|
103 {
|
131
|
104 T **v = m_map.get (node->get_uid ());
|
|
105 return v == NULL ? NULL : *v;
|
|
106 }
|
|
107
|
|
108 /* Remove node from summary. */
|
|
109 void remove (cgraph_node *node)
|
|
110 {
|
|
111 int uid = node->get_uid ();
|
|
112 T **v = m_map.get (uid);
|
|
113 if (v)
|
|
114 {
|
|
115 m_map.remove (uid);
|
|
116 release (*v);
|
|
117 }
|
111
|
118 }
|
|
119
|
|
120 /* Return number of elements handled by data structure. */
|
|
121 size_t elements ()
|
|
122 {
|
|
123 return m_map.elements ();
|
|
124 }
|
|
125
|
|
126 /* Return true if a summary for the given NODE already exists. */
|
|
127 bool exists (cgraph_node *node)
|
|
128 {
|
131
|
129 return m_map.get (node->get_uid ()) != NULL;
|
111
|
130 }
|
|
131
|
|
132 /* Enable insertion hook invocation. */
|
|
133 void enable_insertion_hook ()
|
|
134 {
|
|
135 m_insertion_enabled = true;
|
|
136 }
|
|
137
|
|
138 /* Enable insertion hook invocation. */
|
|
139 void disable_insertion_hook ()
|
|
140 {
|
|
141 m_insertion_enabled = false;
|
|
142 }
|
|
143
|
|
144 /* Symbol insertion hook that is registered to symbol table. */
|
131
|
145 static void symtab_insertion (cgraph_node *node, void *data);
|
111
|
146
|
|
147 /* Symbol removal hook that is registered to symbol table. */
|
131
|
148 static void symtab_removal (cgraph_node *node, void *data);
|
111
|
149
|
|
150 /* Symbol duplication hook that is registered to symbol table. */
|
|
151 static void symtab_duplication (cgraph_node *node, cgraph_node *node2,
|
131
|
152 void *data);
|
111
|
153
|
|
154 protected:
|
|
155 /* Indication if we use ggc summary. */
|
|
156 bool m_ggc;
|
|
157
|
|
158 private:
|
|
159 typedef int_hash <int, 0, -1> map_hash;
|
|
160
|
|
161 /* Indicates if insertion hook is enabled. */
|
|
162 bool m_insertion_enabled;
|
|
163 /* Indicates if the summary is released. */
|
|
164 bool m_released;
|
|
165 /* Main summary store, where summary ID is used as key. */
|
|
166 hash_map <map_hash, T *> m_map;
|
|
167 /* Internal summary insertion hook pointer. */
|
|
168 cgraph_node_hook_list *m_symtab_insertion_hook;
|
|
169 /* Internal summary removal hook pointer. */
|
|
170 cgraph_node_hook_list *m_symtab_removal_hook;
|
|
171 /* Internal summary duplication hook pointer. */
|
|
172 cgraph_2node_hook_list *m_symtab_duplication_hook;
|
|
173 /* Symbol table the summary is registered to. */
|
|
174 symbol_table *m_symtab;
|
|
175
|
|
176 template <typename U> friend void gt_ggc_mx (function_summary <U *> * const &);
|
|
177 template <typename U> friend void gt_pch_nx (function_summary <U *> * const &);
|
|
178 template <typename U> friend void gt_pch_nx (function_summary <U *> * const &,
|
|
179 gt_pointer_operator, void *);
|
|
180 };
|
|
181
|
|
182 template <typename T>
|
131
|
183 function_summary<T *>::function_summary (symbol_table *symtab, bool ggc):
|
|
184 m_ggc (ggc), m_insertion_enabled (true), m_released (false), m_map (13, ggc),
|
|
185 m_symtab (symtab)
|
|
186 {
|
|
187 m_symtab_insertion_hook
|
|
188 = symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion,
|
|
189 this);
|
|
190
|
|
191 m_symtab_removal_hook
|
|
192 = symtab->add_cgraph_removal_hook (function_summary::symtab_removal, this);
|
|
193 m_symtab_duplication_hook
|
|
194 = symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication,
|
|
195 this);
|
|
196 }
|
|
197
|
|
198 template <typename T>
|
|
199 void
|
|
200 function_summary<T *>::release ()
|
|
201 {
|
|
202 if (m_released)
|
|
203 return;
|
|
204
|
|
205 m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook);
|
|
206 m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook);
|
|
207 m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook);
|
|
208
|
|
209 /* Release all summaries. */
|
|
210 typedef typename hash_map <map_hash, T *>::iterator map_iterator;
|
|
211 for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
|
|
212 release ((*it).second);
|
|
213
|
|
214 m_released = true;
|
|
215 }
|
|
216
|
|
217 template <typename T>
|
|
218 void
|
|
219 function_summary<T *>::release (T *item)
|
|
220 {
|
|
221 if (m_ggc)
|
|
222 {
|
|
223 item->~T ();
|
|
224 ggc_free (item);
|
|
225 }
|
|
226 else
|
|
227 delete item;
|
|
228 }
|
|
229
|
|
230 template <typename T>
|
|
231 void
|
|
232 function_summary<T *>::symtab_insertion (cgraph_node *node, void *data)
|
|
233 {
|
|
234 gcc_checking_assert (node->get_uid ());
|
|
235 function_summary *summary = (function_summary <T *> *) (data);
|
|
236
|
|
237 if (summary->m_insertion_enabled)
|
|
238 summary->insert (node, summary->get_create (node));
|
|
239 }
|
|
240
|
|
241 template <typename T>
|
|
242 void
|
|
243 function_summary<T *>::symtab_removal (cgraph_node *node, void *data)
|
|
244 {
|
|
245 gcc_checking_assert (node->get_uid ());
|
|
246 function_summary *summary = (function_summary <T *> *) (data);
|
|
247
|
|
248 int uid = node->get_uid ();
|
|
249 T **v = summary->m_map.get (uid);
|
|
250
|
|
251 if (v)
|
|
252 {
|
|
253 summary->remove (node, *v);
|
|
254
|
|
255 if (!summary->m_ggc)
|
|
256 delete (*v);
|
|
257
|
|
258 summary->m_map.remove (uid);
|
|
259 }
|
|
260 }
|
|
261
|
|
262 template <typename T>
|
|
263 void
|
|
264 function_summary<T *>::symtab_duplication (cgraph_node *node,
|
|
265 cgraph_node *node2, void *data)
|
|
266 {
|
|
267 function_summary *summary = (function_summary <T *> *) (data);
|
|
268 T *v = summary->get (node);
|
|
269
|
|
270 if (v)
|
|
271 {
|
|
272 /* This load is necessary, because we insert a new value! */
|
|
273 T *duplicate = summary->allocate_new ();
|
|
274 summary->m_map.put (node2->get_uid (), duplicate);
|
|
275 summary->duplicate (node, node2, v, duplicate);
|
|
276 }
|
|
277 }
|
|
278
|
|
279 template <typename T>
|
111
|
280 void
|
|
281 gt_ggc_mx(function_summary<T *>* const &summary)
|
|
282 {
|
|
283 gcc_checking_assert (summary->m_ggc);
|
|
284 gt_ggc_mx (&summary->m_map);
|
|
285 }
|
|
286
|
|
287 template <typename T>
|
|
288 void
|
|
289 gt_pch_nx(function_summary<T *>* const &summary)
|
|
290 {
|
|
291 gcc_checking_assert (summary->m_ggc);
|
|
292 gt_pch_nx (&summary->m_map);
|
|
293 }
|
|
294
|
|
295 template <typename T>
|
|
296 void
|
|
297 gt_pch_nx(function_summary<T *>* const& summary, gt_pointer_operator op,
|
|
298 void *cookie)
|
|
299 {
|
|
300 gcc_checking_assert (summary->m_ggc);
|
|
301 gt_pch_nx (&summary->m_map, op, cookie);
|
|
302 }
|
|
303
|
|
304 /* An impossible class templated by non-pointers so, which makes sure that only
|
|
305 summaries gathering pointers can be created. */
|
|
306
|
|
307 template <class T>
|
|
308 class call_summary
|
|
309 {
|
|
310 private:
|
|
311 call_summary();
|
|
312 };
|
|
313
|
|
314 /* Class to store auxiliary information about call graph edges. */
|
|
315
|
|
316 template <class T>
|
|
317 class GTY((user)) call_summary <T *>
|
|
318 {
|
|
319 public:
|
|
320 /* Default construction takes SYMTAB as an argument. */
|
|
321 call_summary (symbol_table *symtab, bool ggc = false): m_ggc (ggc),
|
131
|
322 m_initialize_when_cloning (false), m_map (13, ggc), m_released (false),
|
|
323 m_symtab (symtab)
|
111
|
324 {
|
|
325 m_symtab_removal_hook =
|
|
326 symtab->add_edge_removal_hook
|
|
327 (call_summary::symtab_removal, this);
|
|
328 m_symtab_duplication_hook =
|
|
329 symtab->add_edge_duplication_hook
|
|
330 (call_summary::symtab_duplication, this);
|
|
331 }
|
|
332
|
|
333 /* Destructor. */
|
|
334 virtual ~call_summary ()
|
|
335 {
|
|
336 release ();
|
|
337 }
|
|
338
|
|
339 /* Destruction method that can be called for GGT purpose. */
|
131
|
340 void release ();
|
111
|
341
|
|
342 /* Traverses all summarys with a function F called with
|
|
343 ARG as argument. */
|
|
344 template<typename Arg, bool (*f)(const T &, Arg)>
|
|
345 void traverse (Arg a) const
|
|
346 {
|
|
347 m_map.traverse <f> (a);
|
|
348 }
|
|
349
|
|
350 /* Basic implementation of removal operation. */
|
|
351 virtual void remove (cgraph_edge *, T *) {}
|
|
352
|
|
353 /* Basic implementation of duplication operation. */
|
|
354 virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {}
|
|
355
|
|
356 /* Allocates new data that are stored within map. */
|
|
357 T* allocate_new ()
|
|
358 {
|
|
359 /* Call gcc_internal_because we do not want to call finalizer for
|
|
360 a type T. We call dtor explicitly. */
|
|
361 return m_ggc ? new (ggc_internal_alloc (sizeof (T))) T () : new T () ;
|
|
362 }
|
|
363
|
|
364 /* Release an item that is stored within map. */
|
131
|
365 void release (T *item);
|
|
366
|
|
367 /* Getter for summary callgraph edge pointer.
|
|
368 If a summary for an edge does not exist, it will be created. */
|
|
369 T* get_create (cgraph_edge *edge)
|
111
|
370 {
|
131
|
371 bool existed;
|
|
372 T **v = &m_map.get_or_insert (edge->get_uid (), &existed);
|
|
373 if (!existed)
|
|
374 *v = allocate_new ();
|
|
375
|
|
376 return *v;
|
111
|
377 }
|
|
378
|
|
379 /* Getter for summary callgraph edge pointer. */
|
131
|
380 T* get (cgraph_edge *edge) ATTRIBUTE_PURE
|
111
|
381 {
|
131
|
382 T **v = m_map.get (edge->get_uid ());
|
|
383 return v == NULL ? NULL : *v;
|
|
384 }
|
|
385
|
|
386 /* Remove edge from summary. */
|
|
387 void remove (cgraph_edge *edge)
|
|
388 {
|
|
389 int uid = edge->get_uid ();
|
|
390 T **v = m_map.get (uid);
|
|
391 if (v)
|
|
392 {
|
|
393 m_map.remove (uid);
|
|
394 release (*v);
|
|
395 }
|
111
|
396 }
|
|
397
|
|
398 /* Return number of elements handled by data structure. */
|
|
399 size_t elements ()
|
|
400 {
|
|
401 return m_map.elements ();
|
|
402 }
|
|
403
|
|
404 /* Return true if a summary for the given EDGE already exists. */
|
|
405 bool exists (cgraph_edge *edge)
|
|
406 {
|
131
|
407 return m_map.get (edge->get_uid ()) != NULL;
|
111
|
408 }
|
|
409
|
|
410 /* Symbol removal hook that is registered to symbol table. */
|
131
|
411 static void symtab_removal (cgraph_edge *edge, void *data);
|
111
|
412
|
|
413 /* Symbol duplication hook that is registered to symbol table. */
|
|
414 static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2,
|
131
|
415 void *data);
|
111
|
416
|
|
417 protected:
|
|
418 /* Indication if we use ggc summary. */
|
|
419 bool m_ggc;
|
|
420
|
131
|
421 /* Initialize summary for an edge that is cloned. */
|
|
422 bool m_initialize_when_cloning;
|
|
423
|
111
|
424 private:
|
|
425 typedef int_hash <int, 0, -1> map_hash;
|
|
426
|
|
427 /* Main summary store, where summary ID is used as key. */
|
|
428 hash_map <map_hash, T *> m_map;
|
|
429 /* Internal summary removal hook pointer. */
|
|
430 cgraph_edge_hook_list *m_symtab_removal_hook;
|
|
431 /* Internal summary duplication hook pointer. */
|
|
432 cgraph_2edge_hook_list *m_symtab_duplication_hook;
|
|
433 /* Indicates if the summary is released. */
|
|
434 bool m_released;
|
|
435 /* Symbol table the summary is registered to. */
|
|
436 symbol_table *m_symtab;
|
|
437
|
|
438 template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &);
|
|
439 template <typename U> friend void gt_pch_nx (call_summary <U *> * const &);
|
|
440 template <typename U> friend void gt_pch_nx (call_summary <U *> * const &,
|
|
441 gt_pointer_operator, void *);
|
|
442 };
|
|
443
|
|
444 template <typename T>
|
|
445 void
|
131
|
446 call_summary<T *>::release ()
|
|
447 {
|
|
448 if (m_released)
|
|
449 return;
|
|
450
|
|
451 m_symtab->remove_edge_removal_hook (m_symtab_removal_hook);
|
|
452 m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook);
|
|
453
|
|
454 /* Release all summaries. */
|
|
455 typedef typename hash_map <map_hash, T *>::iterator map_iterator;
|
|
456 for (map_iterator it = m_map.begin (); it != m_map.end (); ++it)
|
|
457 release ((*it).second);
|
|
458
|
|
459 m_released = true;
|
|
460 }
|
|
461
|
|
462 template <typename T>
|
|
463 void
|
|
464 call_summary<T *>::release (T *item)
|
|
465 {
|
|
466 if (m_ggc)
|
|
467 {
|
|
468 item->~T ();
|
|
469 ggc_free (item);
|
|
470 }
|
|
471 else
|
|
472 delete item;
|
|
473 }
|
|
474
|
|
475 template <typename T>
|
|
476 void
|
|
477 call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data)
|
|
478 {
|
|
479 call_summary *summary = (call_summary <T *> *) (data);
|
|
480
|
|
481 int h_uid = edge->get_uid ();
|
|
482 T **v = summary->m_map.get (h_uid);
|
|
483
|
|
484 if (v)
|
|
485 {
|
|
486 summary->remove (edge, *v);
|
|
487 summary->release (*v);
|
|
488 summary->m_map.remove (h_uid);
|
|
489 }
|
|
490 }
|
|
491
|
|
492 template <typename T>
|
|
493 void
|
|
494 call_summary<T *>::symtab_duplication (cgraph_edge *edge1,
|
|
495 cgraph_edge *edge2, void *data)
|
|
496 {
|
|
497 call_summary *summary = (call_summary <T *> *) (data);
|
|
498 T *edge1_summary = NULL;
|
|
499
|
|
500 if (summary->m_initialize_when_cloning)
|
|
501 edge1_summary = summary->get_create (edge1);
|
|
502 else
|
|
503 {
|
|
504 T **v = summary->m_map.get (edge1->get_uid ());
|
|
505 if (v)
|
|
506 {
|
|
507 /* This load is necessary, because we insert a new value! */
|
|
508 edge1_summary = *v;
|
|
509 }
|
|
510 }
|
|
511
|
|
512 if (edge1_summary)
|
|
513 {
|
|
514 T *duplicate = summary->allocate_new ();
|
|
515 summary->m_map.put (edge2->get_uid (), duplicate);
|
|
516 summary->duplicate (edge1, edge2, edge1_summary, duplicate);
|
|
517 }
|
|
518 }
|
|
519
|
|
520 template <typename T>
|
|
521 void
|
111
|
522 gt_ggc_mx(call_summary<T *>* const &summary)
|
|
523 {
|
|
524 gcc_checking_assert (summary->m_ggc);
|
|
525 gt_ggc_mx (&summary->m_map);
|
|
526 }
|
|
527
|
|
528 template <typename T>
|
|
529 void
|
|
530 gt_pch_nx(call_summary<T *>* const &summary)
|
|
531 {
|
|
532 gcc_checking_assert (summary->m_ggc);
|
|
533 gt_pch_nx (&summary->m_map);
|
|
534 }
|
|
535
|
|
536 template <typename T>
|
|
537 void
|
|
538 gt_pch_nx(call_summary<T *>* const& summary, gt_pointer_operator op,
|
|
539 void *cookie)
|
|
540 {
|
|
541 gcc_checking_assert (summary->m_ggc);
|
|
542 gt_pch_nx (&summary->m_map, op, cookie);
|
|
543 }
|
|
544
|
|
545 #endif /* GCC_SYMBOL_SUMMARY_H */
|