1/* Callgraph summary data structure. 2 Copyright (C) 2014-2020 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 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 58protected: 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 92private: 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 100template <typename T> 101void 102function_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 112template <class T> 113class function_summary 114{ 115private: 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 130template <class T> 131class GTY((user)) function_summary <T *>: public function_summary_base<T> 132{ 133public: 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 196protected: 197 /* Indication if we use ggc summary. */ 198 bool m_ggc; 199 200private: 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 218template <typename T> 219function_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 235template <typename T> 236function_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 246template <typename T> 247void 248function_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 257template <typename T> 258void 259function_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 266template <typename T> 267void 268function_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 278template <typename T> 279void 280gt_ggc_mx(function_summary<T *>* const &summary) 281{ 282 gcc_checking_assert (summary->m_ggc); 283 gt_ggc_mx (&summary->m_map); 284} 285 286template <typename T> 287void 288gt_pch_nx (function_summary<T *> *const &) 289{ 290 gcc_unreachable (); 291} 292 293template <typename T> 294void 295gt_pch_nx (function_summary<T *> *const &, gt_pointer_operator, void *) 296{ 297 gcc_unreachable (); 298} 299 300/* Help template from std c++11. */ 301 302template<typename T, typename U> 303struct is_same 304{ 305 static const bool value = false; 306}; 307 308template<typename T> 309struct 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 317template <class T, class V> 318class fast_function_summary 319{ 320private: 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 327template <class T, class V> 328class GTY((user)) fast_function_summary <T *, V> 329 : public function_summary_base<T> 330{ 331public: 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 405private: 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 417template <typename T, typename V> 418fast_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 433template <typename T, typename V> 434fast_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 445template <typename T, typename V> 446void 447fast_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 456template <typename T, typename V> 457void 458fast_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 467template <typename T, typename V> 468void 469fast_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 483template <typename T, typename V> 484inline bool 485fast_function_summary<T *, V>::is_ggc () 486{ 487 return is_same<V, va_gc>::value; 488} 489 490template <typename T> 491void 492gt_ggc_mx (fast_function_summary<T *, va_heap>* const &) 493{ 494} 495 496template <typename T> 497void 498gt_pch_nx (fast_function_summary<T *, va_heap>* const &) 499{ 500} 501 502template <typename T> 503void 504gt_pch_nx (fast_function_summary<T *, va_heap>* const&, gt_pointer_operator, 505 void *) 506{ 507} 508 509template <typename T> 510void 511gt_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 517template <typename T> 518void 519gt_pch_nx (fast_function_summary<T *, va_gc> *const &) 520{ 521 gcc_unreachable (); 522} 523 524template <typename T> 525void 526gt_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 534template <class T> 535class call_summary_base 536{ 537public: 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 551protected: 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 583private: 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 591template <typename T> 592void 593call_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 602template <class T> 603class call_summary 604{ 605private: 606 call_summary (); 607}; 608 609/* Class to store auxiliary information about call graph edges. */ 610 611template <class T> 612class GTY((user)) call_summary <T *>: public call_summary_base<T> 613{ 614public: 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 685protected: 686 /* Indication if we use ggc summary. */ 687 bool m_ggc; 688 689private: 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 707template <typename T> 708call_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 718template <typename T> 719void 720call_summary<T *>::symtab_removal (cgraph_edge *edge, void *data) 721{ 722 call_summary *summary = (call_summary <T *> *) (data); 723 summary->remove (edge); 724} 725 726template <typename T> 727void 728call_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 744template <typename T> 745void 746gt_ggc_mx(call_summary<T *>* const &summary) 747{ 748 gcc_checking_assert (summary->m_ggc); 749 gt_ggc_mx (&summary->m_map); 750} 751 752template <typename T> 753void 754gt_pch_nx (call_summary<T *> *const &) 755{ 756 gcc_unreachable (); 757} 758 759template <typename T> 760void 761gt_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 769template <class T, class V> 770class fast_call_summary 771{ 772private: 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 779template <class T, class V> 780class GTY((user)) fast_call_summary <T *, V>: public call_summary_base<T> 781{ 782public: 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 864private: 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 876template <typename T, typename V> 877fast_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 888template <typename T, typename V> 889void 890fast_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 896template <typename T, typename V> 897void 898fast_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 916template <typename T, typename V> 917inline bool 918fast_call_summary<T *, V>::is_ggc () 919{ 920 return is_same<V, va_gc>::value; 921} 922 923template <typename T> 924void 925gt_ggc_mx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED) 926{ 927} 928 929template <typename T> 930void 931gt_pch_nx (fast_call_summary<T *, va_heap>* const &summary ATTRIBUTE_UNUSED) 932{ 933} 934 935template <typename T> 936void 937gt_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 943template <typename T> 944void 945gt_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 951template <typename T> 952void 953gt_pch_nx (fast_call_summary<T *, va_gc> *const &) 954{ 955 gcc_unreachable (); 956} 957 958template <typename T> 959void 960gt_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