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