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