1 /* Callgraph summary data structure.
2    Copyright (C) 2014-2018 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  */
461