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