Home | History | Annotate | Line # | Download | only in gcc
symbol-summary.h revision 1.1.1.4
      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