1 /* Callgraph summary data structure. 2 Copyright (C) 2014-2020 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 /* Base class for function_summary and fast_function_summary classes. */ 25 26 template <class T> 27 class function_summary_base 28 { 29 public: 30 /* Default construction takes SYMTAB as an argument. */ 31 function_summary_base (symbol_table *symtab CXX_MEM_STAT_INFO): 32 m_symtab (symtab), 33 m_insertion_enabled (true), 34 m_allocator ("function summary" PASS_MEM_STAT) 35 {} 36 37 /* Basic implementation of insert operation. */ 38 virtual void insert (cgraph_node *, T *) {} 39 40 /* Basic implementation of removal operation. */ 41 virtual void remove (cgraph_node *, T *) {} 42 43 /* Basic implementation of duplication operation. */ 44 virtual void duplicate (cgraph_node *, cgraph_node *, T *, T *) {} 45 46 /* Enable insertion hook invocation. */ 47 void enable_insertion_hook () 48 { 49 m_insertion_enabled = true; 50 } 51 52 /* Enable insertion hook invocation. */ 53 void disable_insertion_hook () 54 { 55 m_insertion_enabled = false; 56 } 57 58 protected: 59 /* Allocates new data that are stored within map. */ 60 T* allocate_new () 61 { 62 /* Call gcc_internal_because we do not want to call finalizer for 63 a type T. We call dtor explicitly. */ 64 return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () 65 : m_allocator.allocate () ; 66 } 67 68 /* Release an item that is stored within map. */ 69 void release (T *item) 70 { 71 if (is_ggc ()) 72 ggc_delete (item); 73 else 74 m_allocator.remove (item); 75 } 76 77 /* Unregister all call-graph hooks. */ 78 void unregister_hooks (); 79 80 /* Internal summary insertion hook pointer. */ 81 cgraph_node_hook_list *m_symtab_insertion_hook; 82 /* Internal summary removal hook pointer. */ 83 cgraph_node_hook_list *m_symtab_removal_hook; 84 /* Internal summary duplication hook pointer. */ 85 cgraph_2node_hook_list *m_symtab_duplication_hook; 86 /* Symbol table the summary is registered to. */ 87 symbol_table *m_symtab; 88 89 /* Indicates if insertion hook is enabled. */ 90 bool m_insertion_enabled; 91 92 private: 93 /* Return true when the summary uses GGC memory for allocation. */ 94 virtual bool is_ggc () = 0; 95 96 /* Object allocator for heap allocation. */ 97 object_allocator<T> m_allocator; 98 }; 99 100 template <typename T> 101 void 102 function_summary_base<T>::unregister_hooks () 103 { 104 m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook); 105 m_symtab->remove_cgraph_removal_hook (m_symtab_removal_hook); 106 m_symtab->remove_cgraph_duplication_hook (m_symtab_duplication_hook); 107 } 108 109 /* We want to pass just pointer types as argument for function_summary 110 template class. */ 111 112 template <class T> 113 class function_summary 114 { 115 private: 116 function_summary(); 117 }; 118 119 /* Function summary is a helper class that is used to associate a data structure 120 related to a callgraph node. Typical usage can be seen in IPA passes which 121 create a temporary pass-related structures. The summary class registers 122 hooks that are triggered when a new node is inserted, duplicated and deleted. 123 A user of a summary class can ovewrite virtual methods than are triggered by 124 the summary if such hook is triggered. Apart from a callgraph node, the user 125 is given a data structure tied to the node. 126 127 The function summary class can work both with a heap-allocated memory and 128 a memory gained by garbage collected memory. */ 129 130 template <class T> 131 class GTY((user)) function_summary <T *>: public function_summary_base<T> 132 { 133 public: 134 /* Default construction takes SYMTAB as an argument. */ 135 function_summary (symbol_table *symtab, bool ggc = false CXX_MEM_STAT_INFO); 136 137 /* Destructor. */ 138 virtual ~function_summary (); 139 140 /* Traverses all summarys with a function F called with 141 ARG as argument. */ 142 template<typename Arg, bool (*f)(const T &, Arg)> 143 void traverse (Arg a) const 144 { 145 m_map.template traverse <f> (a); 146 } 147 148 /* Getter for summary callgraph node pointer. If a summary for a node 149 does not exist it will be created. */ 150 T* get_create (cgraph_node *node) 151 { 152 bool existed; 153 T **v = &m_map.get_or_insert (node->get_uid (), &existed); 154 if (!existed) 155 *v = this->allocate_new (); 156 157 return *v; 158 } 159 160 /* Getter for summary callgraph node pointer. */ 161 T* get (cgraph_node *node) ATTRIBUTE_PURE 162 { 163 T **v = m_map.get (node->get_uid ()); 164 return v == NULL ? NULL : *v; 165 } 166 167 /* Remove node from summary. */ 168 using function_summary_base<T>::remove; 169 void remove (cgraph_node *node) 170 { 171 int uid = node->get_uid (); 172 T **v = m_map.get (uid); 173 if (v) 174 { 175 m_map.remove (uid); 176 this->release (*v); 177 } 178 } 179 180 /* Return true if a summary for the given NODE already exists. */ 181 bool exists (cgraph_node *node) 182 { 183 return m_map.get (node->get_uid ()) != NULL; 184 } 185 186 /* Symbol insertion hook that is registered to symbol table. */ 187 static void symtab_insertion (cgraph_node *node, void *data); 188 189 /* Symbol removal hook that is registered to symbol table. */ 190 static void symtab_removal (cgraph_node *node, void *data); 191 192 /* Symbol duplication hook that is registered to symbol table. */ 193 static void symtab_duplication (cgraph_node *node, cgraph_node *node2, 194 void *data); 195 196 protected: 197 /* Indication if we use ggc summary. */ 198 bool m_ggc; 199 200 private: 201 /* Indication if we use ggc summary. */ 202 virtual bool is_ggc () 203 { 204 return m_ggc; 205 } 206 207 typedef int_hash <int, 0, -1> map_hash; 208 209 /* Main summary store, where summary ID is used as key. */ 210 hash_map <map_hash, T *> m_map; 211 212 template <typename U> friend void gt_ggc_mx (function_summary <U *> * const &); 213 template <typename U> friend void gt_pch_nx (function_summary <U *> * const &); 214 template <typename U> friend void gt_pch_nx (function_summary <U *> * const &, 215 gt_pointer_operator, void *); 216 }; 217 218 template <typename T> 219 function_summary<T *>::function_summary (symbol_table *symtab, bool ggc 220 MEM_STAT_DECL): 221 function_summary_base<T> (symtab PASS_MEM_STAT), m_ggc (ggc), 222 m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT) 223 { 224 this->m_symtab_insertion_hook 225 = this->m_symtab->add_cgraph_insertion_hook (function_summary::symtab_insertion, 226 this); 227 this->m_symtab_removal_hook 228 = this->m_symtab->add_cgraph_removal_hook (function_summary::symtab_removal, 229 this); 230 this->m_symtab_duplication_hook 231 = this->m_symtab->add_cgraph_duplication_hook (function_summary::symtab_duplication, 232 this); 233 } 234 235 template <typename T> 236 function_summary<T *>::~function_summary () 237 { 238 this->unregister_hooks (); 239 240 /* Release all summaries. */ 241 typedef typename hash_map <map_hash, T *>::iterator map_iterator; 242 for (map_iterator it = m_map.begin (); it != m_map.end (); ++it) 243 this->release ((*it).second); 244 } 245 246 template <typename T> 247 void 248 function_summary<T *>::symtab_insertion (cgraph_node *node, void *data) 249 { 250 gcc_checking_assert (node->get_uid ()); 251 function_summary *summary = (function_summary <T *> *) (data); 252 253 if (summary->m_insertion_enabled) 254 summary->insert (node, summary->get_create (node)); 255 } 256 257 template <typename T> 258 void 259 function_summary<T *>::symtab_removal (cgraph_node *node, void *data) 260 { 261 gcc_checking_assert (node->get_uid ()); 262 function_summary *summary = (function_summary <T *> *) (data); 263 summary->remove (node); 264 } 265 266 template <typename T> 267 void 268 function_summary<T *>::symtab_duplication (cgraph_node *node, 269 cgraph_node *node2, void *data) 270 { 271 function_summary *summary = (function_summary <T *> *) (data); 272 T *v = summary->get (node); 273 274 if (v) 275 summary->duplicate (node, node2, v, summary->get_create (node2)); 276 } 277 278 template <typename T> 279 void 280 gt_ggc_mx(function_summary<T *>* const &summary) 281 { 282 gcc_checking_assert (summary->m_ggc); 283 gt_ggc_mx (&summary->m_map); 284 } 285 286 template <typename T> 287 void 288 gt_pch_nx (function_summary<T *> *const &) 289 { 290 gcc_unreachable (); 291 } 292 293 template <typename T> 294 void 295 gt_pch_nx (function_summary<T *> *const &, gt_pointer_operator, void *) 296 { 297 gcc_unreachable (); 298 } 299 300 /* Help template from std c++11. */ 301 302 template<typename T, typename U> 303 struct is_same 304 { 305 static const bool value = false; 306 }; 307 308 template<typename T> 309 struct is_same<T,T> //specialization 310 { 311 static const bool value = true; 312 }; 313 314 /* We want to pass just pointer types as argument for fast_function_summary 315 template class. */ 316 317 template <class T, class V> 318 class fast_function_summary 319 { 320 private: 321 fast_function_summary (); 322 }; 323 324 /* Function vector summary is a fast implementation of function_summary that 325 utilizes vector as primary storage of summaries. */ 326 327 template <class T, class V> 328 class GTY((user)) fast_function_summary <T *, V> 329 : public function_summary_base<T> 330 { 331 public: 332 /* Default construction takes SYMTAB as an argument. */ 333 fast_function_summary (symbol_table *symtab CXX_MEM_STAT_INFO); 334 335 /* Destructor. */ 336 virtual ~fast_function_summary (); 337 338 /* Traverses all summarys with a function F called with 339 ARG as argument. */ 340 template<typename Arg, bool (*f)(const T &, Arg)> 341 void traverse (Arg a) const 342 { 343 for (unsigned i = 0; i < m_vector->length (); i++) 344 if ((*m_vector[i]) != NULL) 345 f ((*m_vector)[i], a); 346 } 347 348 /* Getter for summary callgraph node pointer. If a summary for a node 349 does not exist it will be created. */ 350 T* get_create (cgraph_node *node) 351 { 352 int id = node->get_summary_id (); 353 if (id == -1) 354 id = this->m_symtab->assign_summary_id (node); 355 356 if ((unsigned int)id >= m_vector->length ()) 357 { 358 int newlen = this->m_symtab->cgraph_max_summary_id; 359 vec_safe_reserve (m_vector, newlen - m_vector->length ()); 360 m_vector->quick_grow_cleared (newlen); 361 } 362 363 if ((*m_vector)[id] == NULL) 364 (*m_vector)[id] = this->allocate_new (); 365 366 return (*m_vector)[id]; 367 } 368 369 /* Getter for summary callgraph node pointer. */ 370 T* get (cgraph_node *node) ATTRIBUTE_PURE 371 { 372 return exists (node) ? (*m_vector)[node->get_summary_id ()] : NULL; 373 } 374 375 using function_summary_base<T>::remove; 376 void remove (cgraph_node *node) 377 { 378 if (exists (node)) 379 { 380 int id = node->get_summary_id (); 381 this->release ((*m_vector)[id]); 382 (*m_vector)[id] = NULL; 383 } 384 } 385 386 /* Return true if a summary for the given NODE already exists. */ 387 bool exists (cgraph_node *node) 388 { 389 int id = node->get_summary_id (); 390 return (id != -1 391 && (unsigned int)id < m_vector->length () 392 && (*m_vector)[id] != NULL); 393 } 394 395 /* Symbol insertion hook that is registered to symbol table. */ 396 static void symtab_insertion (cgraph_node *node, void *data); 397 398 /* Symbol removal hook that is registered to symbol table. */ 399 static void symtab_removal (cgraph_node *node, void *data); 400 401 /* Symbol duplication hook that is registered to symbol table. */ 402 static void symtab_duplication (cgraph_node *node, cgraph_node *node2, 403 void *data); 404 405 private: 406 virtual bool is_ggc (); 407 408 /* Summary is stored in the vector. */ 409 vec <T *, V> *m_vector; 410 411 template <typename U> friend void gt_ggc_mx (fast_function_summary <U *, va_gc> * const &); 412 template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &); 413 template <typename U> friend void gt_pch_nx (fast_function_summary <U *, va_gc> * const &, 414 gt_pointer_operator, void *); 415 }; 416 417 template <typename T, typename V> 418 fast_function_summary<T *, V>::fast_function_summary (symbol_table *symtab MEM_STAT_DECL): 419 function_summary_base<T> (symtab PASS_MEM_STAT), m_vector (NULL) 420 { 421 vec_alloc (m_vector, 13 PASS_MEM_STAT); 422 this->m_symtab_insertion_hook 423 = this->m_symtab->add_cgraph_insertion_hook (fast_function_summary::symtab_insertion, 424 this); 425 this->m_symtab_removal_hook 426 = this->m_symtab->add_cgraph_removal_hook (fast_function_summary::symtab_removal, 427 this); 428 this->m_symtab_duplication_hook 429 = this->m_symtab->add_cgraph_duplication_hook (fast_function_summary::symtab_duplication, 430 this); 431 } 432 433 template <typename T, typename V> 434 fast_function_summary<T *, V>::~fast_function_summary () 435 { 436 this->unregister_hooks (); 437 438 /* Release all summaries. */ 439 for (unsigned i = 0; i < m_vector->length (); i++) 440 if ((*m_vector)[i] != NULL) 441 this->release ((*m_vector)[i]); 442 vec_free (m_vector); 443 } 444 445 template <typename T, typename V> 446 void 447 fast_function_summary<T *, V>::symtab_insertion (cgraph_node *node, void *data) 448 { 449 gcc_checking_assert (node->get_uid ()); 450 fast_function_summary *summary = (fast_function_summary <T *, V> *) (data); 451 452 if (summary->m_insertion_enabled) 453 summary->insert (node, summary->get_create (node)); 454 } 455 456 template <typename T, typename V> 457 void 458 fast_function_summary<T *, V>::symtab_removal (cgraph_node *node, void *data) 459 { 460 gcc_checking_assert (node->get_uid ()); 461 fast_function_summary *summary = (fast_function_summary <T *, V> *) (data); 462 463 if (summary->exists (node)) 464 summary->remove (node); 465 } 466 467 template <typename T, typename V> 468 void 469 fast_function_summary<T *, V>::symtab_duplication (cgraph_node *node, 470 cgraph_node *node2, 471 void *data) 472 { 473 fast_function_summary *summary = (fast_function_summary <T *, V> *) (data); 474 T *v = summary->get (node); 475 476 if (v) 477 { 478 T *duplicate = summary->get_create (node2); 479 summary->duplicate (node, node2, v, duplicate); 480 } 481 } 482 483 template <typename T, typename V> 484 inline bool 485 fast_function_summary<T *, V>::is_ggc () 486 { 487 return is_same<V, va_gc>::value; 488 } 489 490 template <typename T> 491 void 492 gt_ggc_mx (fast_function_summary<T *, va_heap>* const &) 493 { 494 } 495 496 template <typename T> 497 void 498 gt_pch_nx (fast_function_summary<T *, va_heap>* const &) 499 { 500 } 501 502 template <typename T> 503 void 504 gt_pch_nx (fast_function_summary<T *, va_heap>* const&, gt_pointer_operator, 505 void *) 506 { 507 } 508 509 template <typename T> 510 void 511 gt_ggc_mx (fast_function_summary<T *, va_gc>* const &summary) 512 { 513 ggc_test_and_set_mark (summary->m_vector); 514 gt_ggc_mx (summary->m_vector); 515 } 516 517 template <typename T> 518 void 519 gt_pch_nx (fast_function_summary<T *, va_gc> *const &) 520 { 521 gcc_unreachable (); 522 } 523 524 template <typename T> 525 void 526 gt_pch_nx (fast_function_summary<T *, va_gc> *const &, gt_pointer_operator, 527 void *) 528 { 529 gcc_unreachable (); 530 } 531 532 /* Base class for call_summary and fast_call_summary classes. */ 533 534 template <class T> 535 class call_summary_base 536 { 537 public: 538 /* Default construction takes SYMTAB as an argument. */ 539 call_summary_base (symbol_table *symtab CXX_MEM_STAT_INFO): 540 m_symtab (symtab), 541 m_initialize_when_cloning (false), 542 m_allocator ("call summary" PASS_MEM_STAT) 543 {} 544 545 /* Basic implementation of removal operation. */ 546 virtual void remove (cgraph_edge *, T *) {} 547 548 /* Basic implementation of duplication operation. */ 549 virtual void duplicate (cgraph_edge *, cgraph_edge *, T *, T *) {} 550 551 protected: 552 /* Allocates new data that are stored within map. */ 553 T* allocate_new () 554 { 555 /* Call gcc_internal_because we do not want to call finalizer for 556 a type T. We call dtor explicitly. */ 557 return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () 558 : m_allocator.allocate (); 559 } 560 561 /* Release an item that is stored within map. */ 562 void release (T *item) 563 { 564 if (is_ggc ()) 565 ggc_delete (item); 566 else 567 m_allocator.remove (item); 568 } 569 570 /* Unregister all call-graph hooks. */ 571 void unregister_hooks (); 572 573 /* Symbol table the summary is registered to. */ 574 symbol_table *m_symtab; 575 576 /* Internal summary removal hook pointer. */ 577 cgraph_edge_hook_list *m_symtab_removal_hook; 578 /* Internal summary duplication hook pointer. */ 579 cgraph_2edge_hook_list *m_symtab_duplication_hook; 580 /* Initialize summary for an edge that is cloned. */ 581 bool m_initialize_when_cloning; 582 583 private: 584 /* Return true when the summary uses GGC memory for allocation. */ 585 virtual bool is_ggc () = 0; 586 587 /* Object allocator for heap allocation. */ 588 object_allocator<T> m_allocator; 589 }; 590 591 template <typename T> 592 void 593 call_summary_base<T>::unregister_hooks () 594 { 595 m_symtab->remove_edge_removal_hook (m_symtab_removal_hook); 596 m_symtab->remove_edge_duplication_hook (m_symtab_duplication_hook); 597 } 598 599 /* An impossible class templated by non-pointers so, which makes sure that only 600 summaries gathering pointers can be created. */ 601 602 template <class T> 603 class call_summary 604 { 605 private: 606 call_summary (); 607 }; 608 609 /* Class to store auxiliary information about call graph edges. */ 610 611 template <class T> 612 class GTY((user)) call_summary <T *>: public call_summary_base<T> 613 { 614 public: 615 /* Default construction takes SYMTAB as an argument. */ 616 call_summary (symbol_table *symtab, bool ggc = false 617 CXX_MEM_STAT_INFO) 618 : call_summary_base<T> (symtab PASS_MEM_STAT), m_ggc (ggc), 619 m_map (13, ggc, true, GATHER_STATISTICS PASS_MEM_STAT) 620 { 621 this->m_symtab_removal_hook 622 = this->m_symtab->add_edge_removal_hook (call_summary::symtab_removal, 623 this); 624 this->m_symtab_duplication_hook 625 = this->m_symtab->add_edge_duplication_hook (call_summary::symtab_duplication, 626 this); 627 } 628 629 /* Destructor. */ 630 virtual ~call_summary (); 631 632 /* Traverses all summarys with an edge E called with 633 ARG as argument. */ 634 template<typename Arg, bool (*f)(const T &, Arg)> 635 void traverse (Arg a) const 636 { 637 m_map.template traverse <f> (a); 638 } 639 640 /* Getter for summary callgraph edge pointer. 641 If a summary for an edge does not exist, it will be created. */ 642 T* get_create (cgraph_edge *edge) 643 { 644 bool existed; 645 T **v = &m_map.get_or_insert (edge->get_uid (), &existed); 646 if (!existed) 647 *v = this->allocate_new (); 648 649 return *v; 650 } 651 652 /* Getter for summary callgraph edge pointer. */ 653 T* get (cgraph_edge *edge) ATTRIBUTE_PURE 654 { 655 T **v = m_map.get (edge->get_uid ()); 656 return v == NULL ? NULL : *v; 657 } 658 659 /* Remove edge from summary. */ 660 using call_summary_base<T>::remove; 661 void remove (cgraph_edge *edge) 662 { 663 int uid = edge->get_uid (); 664 T **v = m_map.get (uid); 665 if (v) 666 { 667 m_map.remove (uid); 668 this->release (*v); 669 } 670 } 671 672 /* Return true if a summary for the given EDGE already exists. */ 673 bool exists (cgraph_edge *edge) 674 { 675 return m_map.get (edge->get_uid ()) != NULL; 676 } 677 678 /* Symbol removal hook that is registered to symbol table. */ 679 static void symtab_removal (cgraph_edge *edge, void *data); 680 681 /* Symbol duplication hook that is registered to symbol table. */ 682 static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2, 683 void *data); 684 685 protected: 686 /* Indication if we use ggc summary. */ 687 bool m_ggc; 688 689 private: 690 /* Indication if we use ggc summary. */ 691 virtual bool is_ggc () 692 { 693 return m_ggc; 694 } 695 696 typedef int_hash <int, 0, -1> map_hash; 697 698 /* Main summary store, where summary ID is used as key. */ 699 hash_map <map_hash, T *> m_map; 700 701 template <typename U> friend void gt_ggc_mx (call_summary <U *> * const &); 702 template <typename U> friend void gt_pch_nx (call_summary <U *> * const &); 703 template <typename U> friend void gt_pch_nx (call_summary <U *> * const &, 704 gt_pointer_operator, void *); 705 }; 706 707 template <typename T> 708 call_summary<T *>::~call_summary () 709 { 710 this->unregister_hooks (); 711 712 /* Release all summaries. */ 713 typedef typename hash_map <map_hash, T *>::iterator map_iterator; 714 for (map_iterator it = m_map.begin (); it != m_map.end (); ++it) 715 this->release ((*it).second); 716 } 717 718 template <typename T> 719 void 720 call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data) 721 { 722 call_summary *summary = (call_summary <T *> *) (data); 723 summary->remove (edge); 724 } 725 726 template <typename T> 727 void 728 call_summary<T *>::symtab_duplication (cgraph_edge *edge1, 729 cgraph_edge *edge2, void *data) 730 { 731 call_summary *summary = (call_summary <T *> *) (data); 732 T *edge1_summary = NULL; 733 734 if (summary->m_initialize_when_cloning) 735 edge1_summary = summary->get_create (edge1); 736 else 737 edge1_summary = summary->get (edge1); 738 739 if (edge1_summary) 740 summary->duplicate (edge1, edge2, edge1_summary, 741 summary->get_create (edge2)); 742 } 743 744 template <typename T> 745 void 746 gt_ggc_mx(call_summary<T *>* const &summary) 747 { 748 gcc_checking_assert (summary->m_ggc); 749 gt_ggc_mx (&summary->m_map); 750 } 751 752 template <typename T> 753 void 754 gt_pch_nx (call_summary<T *> *const &) 755 { 756 gcc_unreachable (); 757 } 758 759 template <typename T> 760 void 761 gt_pch_nx (call_summary<T *> *const &, gt_pointer_operator, void *) 762 { 763 gcc_unreachable (); 764 } 765 766 /* We want to pass just pointer types as argument for fast_call_summary 767 template class. */ 768 769 template <class T, class V> 770 class fast_call_summary 771 { 772 private: 773 fast_call_summary (); 774 }; 775 776 /* Call vector summary is a fast implementation of call_summary that 777 utilizes vector as primary storage of summaries. */ 778 779 template <class T, class V> 780 class GTY((user)) fast_call_summary <T *, V>: public call_summary_base<T> 781 { 782 public: 783 /* Default construction takes SYMTAB as an argument. */ 784 fast_call_summary (symbol_table *symtab CXX_MEM_STAT_INFO) 785 : call_summary_base<T> (symtab PASS_MEM_STAT), m_vector (NULL) 786 { 787 vec_alloc (m_vector, 13 PASS_MEM_STAT); 788 this->m_symtab_removal_hook 789 = this->m_symtab->add_edge_removal_hook (fast_call_summary::symtab_removal, 790 this); 791 this->m_symtab_duplication_hook 792 = this->m_symtab->add_edge_duplication_hook (fast_call_summary::symtab_duplication, 793 this); 794 } 795 796 /* Destructor. */ 797 virtual ~fast_call_summary (); 798 799 /* Traverses all summarys with an edge F called with 800 ARG as argument. */ 801 template<typename Arg, bool (*f)(const T &, Arg)> 802 void traverse (Arg a) const 803 { 804 for (unsigned i = 0; i < m_vector->length (); i++) 805 if ((*m_vector[i]) != NULL) 806 f ((*m_vector)[i], a); 807 } 808 809 /* Getter for summary callgraph edge pointer. 810 If a summary for an edge does not exist, it will be created. */ 811 T* get_create (cgraph_edge *edge) 812 { 813 int id = edge->get_summary_id (); 814 if (id == -1) 815 id = this->m_symtab->assign_summary_id (edge); 816 817 if ((unsigned)id >= m_vector->length ()) 818 { 819 int newlen = this->m_symtab->edges_max_summary_id; 820 m_vector->reserve (newlen - m_vector->length ()); 821 m_vector->quick_grow_cleared (newlen); 822 } 823 824 if ((*m_vector)[id] == NULL) 825 (*m_vector)[id] = this->allocate_new (); 826 827 return (*m_vector)[id]; 828 } 829 830 /* Getter for summary callgraph edge pointer. */ 831 T* get (cgraph_edge *edge) ATTRIBUTE_PURE 832 { 833 return exists (edge) ? (*m_vector)[edge->get_summary_id ()] : NULL; 834 } 835 836 /* Remove edge from summary. */ 837 using call_summary_base<T>::remove; 838 void remove (cgraph_edge *edge) 839 { 840 if (exists (edge)) 841 { 842 int id = edge->get_summary_id (); 843 this->release ((*m_vector)[id]); 844 (*m_vector)[id] = NULL; 845 } 846 } 847 848 /* Return true if a summary for the given EDGE already exists. */ 849 bool exists (cgraph_edge *edge) 850 { 851 int id = edge->get_summary_id (); 852 return (id != -1 853 && (unsigned)id < m_vector->length () 854 && (*m_vector)[id] != NULL); 855 } 856 857 /* Symbol removal hook that is registered to symbol table. */ 858 static void symtab_removal (cgraph_edge *edge, void *data); 859 860 /* Symbol duplication hook that is registered to symbol table. */ 861 static void symtab_duplication (cgraph_edge *edge1, cgraph_edge *edge2, 862 void *data); 863 864 private: 865 virtual bool is_ggc (); 866 867 /* Summary is stored in the vector. */ 868 vec <T *, V> *m_vector; 869 870 template <typename U> friend void gt_ggc_mx (fast_call_summary <U *, va_gc> * const &); 871 template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &); 872 template <typename U> friend void gt_pch_nx (fast_call_summary <U *, va_gc> * const &, 873 gt_pointer_operator, void *); 874 }; 875 876 template <typename T, typename V> 877 fast_call_summary<T *, V>::~fast_call_summary () 878 { 879 this->unregister_hooks (); 880 881 /* Release all summaries. */ 882 for (unsigned i = 0; i < m_vector->length (); i++) 883 if ((*m_vector)[i] != NULL) 884 this->release ((*m_vector)[i]); 885 vec_free (m_vector); 886 } 887 888 template <typename T, typename V> 889 void 890 fast_call_summary<T *, V>::symtab_removal (cgraph_edge *edge, void *data) 891 { 892 fast_call_summary *summary = (fast_call_summary <T *, V> *) (data); 893 summary->remove (edge); 894 } 895 896 template <typename T, typename V> 897 void 898 fast_call_summary<T *, V>::symtab_duplication (cgraph_edge *edge1, 899 cgraph_edge *edge2, void *data) 900 { 901 fast_call_summary *summary = (fast_call_summary <T *, V> *) (data); 902 T *edge1_summary = NULL; 903 904 if (summary->m_initialize_when_cloning) 905 edge1_summary = summary->get_create (edge1); 906 else 907 edge1_summary = summary->get (edge1); 908 909 if (edge1_summary) 910 { 911 T *duplicate = summary->get_create (edge2); 912 summary->duplicate (edge1, edge2, edge1_summary, duplicate); 913 } 914 } 915 916 template <typename T, typename V> 917 inline bool 918 fast_call_summary<T *, V>::is_ggc () 919 { 920 return is_same<V, va_gc>::value; 921 } 922 923 template <typename T> 924 void 925 gt_ggc_mx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED) 926 { 927 } 928 929 template <typename T> 930 void 931 gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED) 932 { 933 } 934 935 template <typename T> 936 void 937 gt_pch_nx (fast_call_summary<T *, va_heap>* const& summary ATTRIBUTE_UNUSED, 938 gt_pointer_operator op ATTRIBUTE_UNUSED, 939 void *cookie ATTRIBUTE_UNUSED) 940 { 941 } 942 943 template <typename T> 944 void 945 gt_ggc_mx (fast_call_summary<T *, va_gc>* const &summary) 946 { 947 ggc_test_and_set_mark (summary->m_vector); 948 gt_ggc_mx (&summary->m_vector); 949 } 950 951 template <typename T> 952 void 953 gt_pch_nx (fast_call_summary<T *, va_gc> *const &) 954 { 955 gcc_unreachable (); 956 } 957 958 template <typename T> 959 void 960 gt_pch_nx (fast_call_summary<T *, va_gc> *const &, gt_pointer_operator, void *) 961 { 962 gcc_unreachable (); 963 } 964 965 #endif /* GCC_SYMBOL_SUMMARY_H */ 966